dev
dart 162 lines 4.73 KB
Raw
1 import 'package:cw_core/subaddress.dart';
2 import 'package:cw_core/utils/print_verbose.dart';
3 import 'package:cw_monero/api/coins_info.dart';
4 import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
5
6 import 'package:flutter/services.dart';
7 import 'package:mobx/mobx.dart';
8
9 part 'monero_subaddress_list.g.dart';
10
11 class MoneroSubaddressList = MoneroSubaddressListBase with _$MoneroSubaddressList;
12
13 abstract class MoneroSubaddressListBase with Store {
14 MoneroSubaddressListBase()
15 : _isRefreshing = false,
16 _isUpdating = false,
17 subaddresses = ObservableList<Subaddress>();
18
19 final List<String> _usedAddresses = [];
20
21 @observable
22 ObservableList<Subaddress> subaddresses;
23
24 bool _isRefreshing;
25 bool _isUpdating;
26
27 Future<void> update({required int accountIndex}) async {
28 refreshCoins(accountIndex);
29
30 if (_isUpdating) {
31 return;
32 }
33
34 try {
35 _isUpdating = true;
36 refresh(accountIndex: accountIndex);
37 final newAddrs = await getAll();
38 subaddresses.clear();
39 subaddresses.addAll(newAddrs);
40 _isUpdating = false;
41 } catch (e) {
42 _isUpdating = false;
43 rethrow;
44 }
45 }
46
47 Future<List<Subaddress>> getAll() async {
48 var subaddresses = await subaddress_list.getAllSubaddresses();
49
50 if (subaddresses.length > 2) {
51 final primary = subaddresses.first;
52 final rest = subaddresses.sublist(1).reversed;
53 subaddresses = [primary] + rest.toList();
54 }
55
56 return subaddresses.map((s) {
57 final address = s.address;
58 final label = s.label;
59 final id = s.addressIndex;
60 return Subaddress(
61 id: id,
62 address: address,
63 balance: (s.received / 1e12).toStringAsFixed(6),
64 txCount: s.txCount,
65 label: label);
66 }).toList();
67 }
68
69 Future<void> addSubaddress({required int accountIndex, required String label}) async {
70 await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
71 await update(accountIndex: accountIndex);
72 }
73
74 Future<void> setLabelSubaddress(
75 {required int accountIndex, required int addressIndex, required String label}) async {
76 await subaddress_list.setLabelForSubaddress(
77 accountIndex: accountIndex, addressIndex: addressIndex, label: label);
78 await update(accountIndex: accountIndex);
79 }
80
81 void refresh({required int accountIndex}) {
82 if (_isRefreshing) {
83 return;
84 }
85
86 try {
87 _isRefreshing = true;
88 subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
89 _isRefreshing = false;
90 } on PlatformException catch (e) {
91 _isRefreshing = false;
92 printV(e);
93 rethrow;
94 }
95 }
96
97 Future<void> updateWithAutoGenerate({
98 required int accountIndex,
99 required String defaultLabel,
100 required List<String> usedAddresses,
101 }) async {
102 _usedAddresses.addAll(usedAddresses);
103 final _all = _usedAddresses.toSet().toList();
104 _usedAddresses.clear();
105 _usedAddresses.addAll(_all);
106 if (_isUpdating) {
107 return;
108 }
109
110 try {
111 _isUpdating = true;
112 refresh(accountIndex: accountIndex);
113 subaddresses.clear();
114 final newSubAddresses =
115 await _getAllUnusedAddresses(accountIndex: accountIndex, label: defaultLabel);
116 subaddresses.addAll(newSubAddresses);
117 } catch (e) {
118 rethrow;
119 } finally {
120 _isUpdating = false;
121 }
122 }
123
124 Future<List<Subaddress>> _getAllUnusedAddresses(
125 {required int accountIndex, required String label}) async {
126 final allAddresses = await subaddress_list.getAllSubaddresses();
127 // first because addresses come in reversed order.
128 if (allAddresses.isEmpty || _usedAddresses.contains(allAddresses.first.address)) {
129 final isAddressUnused = await _newSubaddress(accountIndex: accountIndex, label: label);
130 if (!isAddressUnused) {
131 return await _getAllUnusedAddresses(accountIndex: accountIndex, label: label);
132 }
133 }
134
135 return allAddresses
136 .map((s) {
137 final id = s.addressIndex;
138 final address = s.address;
139 final label = s.label;
140 return Subaddress(
141 id: id,
142 address: address,
143 balance: (s.received / 1e12).toStringAsFixed(6),
144 txCount: s.txCount,
145 label: id == 0 && label.toLowerCase() == 'Primary account'.toLowerCase()
146 ? 'Primary address'
147 : label);
148 })
149 .toList()
150 .reversed
151 .toList();
152 }
153
154 Future<bool> _newSubaddress({required int accountIndex, required String label}) async {
155 await subaddress_list.addSubaddress(accountIndex: accountIndex, label: label);
156
157 return (await subaddress_list.getAllSubaddresses()).where((s) {
158 final address = s.address;
159 return !_usedAddresses.contains(address);
160 }).isNotEmpty;
161 }
162 }