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