CW-681 Add address and account list to Wownero (#1538)

cyan committed Jul 21, 2024 at 02:58 UTC 649305acc343f75d26892b92f878e18747ddc8a2
9 files changed +171 -33
lib/di.dart
+2 -1
@@ -678,7 +678,7 @@ Future<void> setup({
678
679 getIt.registerFactory<MoneroAccountListViewModel>(() {
680 final wallet = getIt.get<AppStore>().wallet!;
681 - if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
681 + if (wallet.type == WalletType.monero || wallet.type == WalletType.wownero || wallet.type == WalletType.haven) {
682 return MoneroAccountListViewModel(wallet);
683 }
684 throw Exception(
@@ -709,6 +709,7 @@ Future<void> setup({
709 getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel, AccountListItem?, void>(
710 (AccountListItem? account, _) => MoneroAccountEditOrCreateViewModel(
711 monero!.getAccountList(getIt.get<AppStore>().wallet!),
712 + wownero?.getAccountList(getIt.get<AppStore>().wallet!),
713 haven?.getAccountList(getIt.get<AppStore>().wallet!),
714 wallet: getIt.get<AppStore>().wallet!,
715 accountListItem: account));
lib/src/screens/receive/receive_page.dart
+1
@@ -139,6 +139,7 @@ class ReceivePage extends BasePage {
139 walletAddressListViewModel: addressListViewModel,
140 trailingButtonTap: () async {
141 if (addressListViewModel.type == WalletType.monero ||
142 + addressListViewModel.type == WalletType.wownero ||
143 addressListViewModel.type == WalletType.haven) {
144 await showPopUp<void>(
145 context: context,
lib/view_model/dashboard/balance_view_model.dart
+1 -1
@@ -88,7 +88,7 @@ abstract class BalanceViewModelBase with Store {
88 wallet.type == WalletType.tron;
89
90 @computed
91 - bool get hasAccounts => wallet.type == WalletType.monero;
91 + bool get hasAccounts => wallet.type == WalletType.monero || wallet.type == WalletType.wownero;
92
93 @computed
94 SortBalanceBy get sortBalanceBy => settingsStore.sortBalanceBy;
lib/view_model/dashboard/dashboard_view_model.dart
+77 -12
@@ -31,6 +31,7 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
31 import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
32 import 'package:cake_wallet/view_model/settings/sync_mode.dart';
33 import 'package:cake_wallet/wallet_type_utils.dart';
34 +import 'package:cake_wallet/wownero/wownero.dart' as wow;
35 import 'package:cryptography/cryptography.dart';
36 import 'package:cw_core/balance.dart';
37 import 'package:cw_core/cake_hive.dart';
@@ -163,6 +164,29 @@ abstract class DashboardViewModelBase with Store {
164 final sortedTransactions = [..._accountTransactions];
165 sortedTransactions.sort((a, b) => a.date.compareTo(b.date));
166
167 + transactions = ObservableList.of(sortedTransactions.map((transaction) => TransactionListItem(
168 + transaction: transaction,
169 + balanceViewModel: balanceViewModel,
170 + settingsStore: appStore.settingsStore)));
171 + } else if (_wallet.type == WalletType.wownero) {
172 + subname = wow.wownero!.getCurrentAccount(_wallet).label;
173 +
174 + _onMoneroAccountChangeReaction = reaction(
175 + (_) => wow.wownero!.getWowneroWalletDetails(wallet).account,
176 + (wow.Account account) => _onMoneroAccountChange(_wallet));
177 +
178 + _onMoneroBalanceChangeReaction = reaction(
179 + (_) => wow.wownero!.getWowneroWalletDetails(wallet).balance,
180 + (wow.WowneroBalance balance) => _onMoneroTransactionsUpdate(_wallet));
181 +
182 + final _accountTransactions = _wallet.transactionHistory.transactions.values
183 + .where((tx) =>
184 + wow.wownero!.getTransactionInfoAccountId(tx) == wow.wownero!.getCurrentAccount(wallet).id)
185 + .toList();
186 +
187 + final sortedTransactions = [..._accountTransactions];
188 + sortedTransactions.sort((a, b) => a.date.compareTo(b.date));
189 +
190 transactions = ObservableList.of(sortedTransactions.map((transaction) => TransactionListItem(
191 transaction: transaction,
192 balanceViewModel: balanceViewModel,
@@ -200,6 +224,10 @@ abstract class DashboardViewModelBase with Store {
224 return monero!.getTransactionInfoAccountId(transaction) ==
225 monero!.getCurrentAccount(wallet).id;
226 }
227 + if (wallet.type == WalletType.wownero) {
228 + return wow.wownero!.getTransactionInfoAccountId(transaction) ==
229 + wow.wownero!.getCurrentAccount(wallet).id;
230 + }
231
232 return true;
233 });
@@ -459,6 +487,21 @@ abstract class DashboardViewModelBase with Store {
487 (_) => monero!.getMoneroWalletDetails(wallet).balance,
488 (MoneroBalance balance) => _onMoneroTransactionsUpdate(wallet));
489
490 + _onMoneroTransactionsUpdate(wallet);
491 + } else if (wallet.type == WalletType.wownero) {
492 + subname = wow.wownero!.getCurrentAccount(wallet).label;
493 +
494 + _onMoneroAccountChangeReaction?.reaction.dispose();
495 + _onMoneroBalanceChangeReaction?.reaction.dispose();
496 +
497 + _onMoneroAccountChangeReaction = reaction(
498 + (_) => wow.wownero!.getWowneroWalletDetails(wallet).account,
499 + (wow.Account account) => _onMoneroAccountChange(wallet));
500 +
501 + _onMoneroBalanceChangeReaction = reaction(
502 + (_) => wow.wownero!.getWowneroWalletDetails(wallet).balance,
503 + (wow.WowneroBalance balance) => _onMoneroTransactionsUpdate(wallet));
504 +
505 _onMoneroTransactionsUpdate(wallet);
506 } else {
507 // FIX-ME: Check for side effects
@@ -489,32 +532,54 @@ abstract class DashboardViewModelBase with Store {
532 return monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id;
533 }
534
535 + if (wallet.type == WalletType.wownero) {
536 + return wow.wownero!.getTransactionInfoAccountId(tx) == wow.wownero!.getCurrentAccount(wallet).id;
537 + }
538 +
539 return true;
540 });
541 }
542
543 @action
544 void _onMoneroAccountChange(WalletBase wallet) {
498 - subname = monero!.getCurrentAccount(wallet).label;
545 + if (wallet.type == WalletType.monero) {
546 + subname = monero!.getCurrentAccount(wallet).label;
547 + } else if (wallet.type == WalletType.wownero) {
548 + subname = wow.wownero!.getCurrentAccount(wallet).label;
549 + }
550 _onMoneroTransactionsUpdate(wallet);
551 }
552
553 @action
554 void _onMoneroTransactionsUpdate(WalletBase wallet) {
555 transactions.clear();
556 + if (wallet.type == WalletType.monero) {
557 + final _accountTransactions = monero!
558 + .getTransactionHistory(wallet)
559 + .transactions
560 + .values
561 + .where(
562 + (tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
563 + .toList();
564
506 - final _accountTransactions = monero!
507 - .getTransactionHistory(wallet)
508 - .transactions
509 - .values
510 - .where(
511 - (tx) => monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
512 - .toList();
565 + transactions.addAll(_accountTransactions.map((transaction) => TransactionListItem(
566 + transaction: transaction,
567 + balanceViewModel: balanceViewModel,
568 + settingsStore: appStore.settingsStore)));
569 + } else if (wallet.type == WalletType.wownero) {
570 + final _accountTransactions = wow.wownero!
571 + .getTransactionHistory(wallet)
572 + .transactions
573 + .values
574 + .where(
575 + (tx) => wow.wownero!.getTransactionInfoAccountId(tx) == wow.wownero!.getCurrentAccount(wallet).id)
576 + .toList();
577
514 - transactions.addAll(_accountTransactions.map((transaction) => TransactionListItem(
515 - transaction: transaction,
516 - balanceViewModel: balanceViewModel,
517 - settingsStore: appStore.settingsStore)));
578 + transactions.addAll(_accountTransactions.map((transaction) => TransactionListItem(
579 + transaction: transaction,
580 + balanceViewModel: balanceViewModel,
581 + settingsStore: appStore.settingsStore)));
582 + }
583 }
584
585 void updateActions() {
lib/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart
+30 -1
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/wownero/wownero.dart';
2 import 'package:cw_core/wallet_base.dart';
3 import 'package:cw_core/wallet_type.dart';
4 import 'package:flutter/foundation.dart';
@@ -13,7 +14,7 @@ class MoneroAccountEditOrCreateViewModel = MoneroAccountEditOrCreateViewModelBas
14 with _$MoneroAccountEditOrCreateViewModel;
15
16 abstract class MoneroAccountEditOrCreateViewModelBase with Store {
16 - MoneroAccountEditOrCreateViewModelBase(this._moneroAccountList, this._havenAccountList,
17 + MoneroAccountEditOrCreateViewModelBase(this._moneroAccountList, this._wowneroAccountList, this._havenAccountList,
18 {required WalletBase wallet, AccountListItem? accountListItem})
19 : state = InitialExecutionState(),
20 isEdit = accountListItem != null,
@@ -30,6 +31,7 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
31 String label;
32
33 final MoneroAccountList _moneroAccountList;
34 + final WowneroAccountList? _wowneroAccountList;
35 final HavenAccountList? _havenAccountList;
36 final AccountListItem? _accountListItem;
37 final WalletBase _wallet;
@@ -42,6 +44,10 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
44 if (_wallet.type == WalletType.haven) {
45 await saveHaven();
46 }
47 +
48 + if (_wallet.type == WalletType.wownero) {
49 + await saveWownero();
50 + }
51 }
52
53 Future<void> saveMonero() async {
@@ -91,4 +97,27 @@ abstract class MoneroAccountEditOrCreateViewModelBase with Store {
97 state = FailureState(e.toString());
98 }
99 }
100 +
101 + Future<void> saveWownero() async {
102 + try {
103 + state = IsExecutingState();
104 +
105 + if (_accountListItem != null) {
106 + await _wowneroAccountList?.setLabelAccount(
107 + _wallet,
108 + accountIndex: _accountListItem!.id,
109 + label: label);
110 + } else {
111 + await _wowneroAccountList?.addAccount(
112 + _wallet,
113 + label: label);
114 + }
115 +
116 + await _wallet.save();
117 + state = ExecutedSuccessfullyState();
118 + } catch (e) {
119 + state = FailureState(e.toString());
120 + }
121 + }
122 +
123 }
lib/view_model/monero_account_list/monero_account_list_view_model.dart
+21
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/wownero/wownero.dart';
2 import 'package:cw_core/crypto_currency.dart';
3 import 'package:cw_core/wallet_type.dart';
4 import 'package:mobx/mobx.dart';
@@ -47,6 +48,17 @@ abstract class MoneroAccountListViewModelBase with Store {
48 .toList();
49 }
50
51 + if (_wallet.type == WalletType.wownero) {
52 + return wownero
53 + !.getAccountList(_wallet)
54 + .accounts.map((acc) => AccountListItem(
55 + label: acc.label,
56 + id: acc.id,
57 + balance: acc.balance,
58 + isSelected: acc.id == wownero!.getCurrentAccount(_wallet).id))
59 + .toList();
60 + }
61 +
62 throw Exception('Unexpected wallet type: ${_wallet.type}');
63 }
64
@@ -62,6 +74,15 @@ abstract class MoneroAccountListViewModelBase with Store {
74 );
75 }
76
77 + if (_wallet.type == WalletType.wownero) {
78 + wownero!.setCurrentAccount(
79 + _wallet,
80 + item.id,
81 + item.label,
82 + item.balance,
83 + );
84 + }
85 +
86 if (_wallet.type == WalletType.haven) {
87 haven!.setCurrentAccount(
88 _wallet,
lib/view_model/node_list/node_create_or_edit_view_model.dart
+1 -1
@@ -65,7 +65,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
65 bool get isReady => address.isNotEmpty && port.isNotEmpty;
66
67 bool get hasAuthCredentials =>
68 - _walletType == WalletType.monero || _walletType == WalletType.haven;
68 + _walletType == WalletType.monero || _walletType == WalletType.wownero || _walletType == WalletType.haven;
69
70 bool get hasTestnetSupport => _walletType == WalletType.bitcoin;
71
lib/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart
+16
@@ -1,4 +1,5 @@
1 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
2 +import 'package:cake_wallet/wownero/wownero.dart';
3 import 'package:mobx/mobx.dart';
4 import 'package:cw_core/wallet_base.dart';
5 import 'package:cake_wallet/bitcoin/bitcoin.dart';
@@ -80,6 +81,16 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
81 await wallet.save();
82 }
83
84 + if (wallet.type == WalletType.wownero) {
85 + await wownero
86 + !.getSubaddressList(wallet)
87 + .addSubaddress(
88 + wallet,
89 + accountIndex: wownero!.getCurrentAccount(wallet).id,
90 + label: label);
91 + await wallet.save();
92 + }
93 +
94 if (wallet.type == WalletType.haven) {
95 await haven
96 !.getSubaddressList(wallet)
@@ -103,6 +114,11 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
114 accountIndex: monero!.getCurrentAccount(wallet).id, addressIndex: index, label: label);
115 await wallet.save();
116 }
117 + if (wallet.type == WalletType.wownero) {
118 + await wownero!.getSubaddressList(wallet).setLabelSubaddress(wallet,
119 + accountIndex: wownero!.getCurrentAccount(wallet).id, addressIndex: index, label: label);
120 + await wallet.save();
121 + }
122 if (wallet.type == WalletType.haven) {
123 await haven!.getSubaddressList(wallet).setLabelSubaddress(wallet,
124 accountIndex: haven!.getCurrentAccount(wallet).id,
lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+22 -17
@@ -217,7 +217,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
217 selectedCurrency = walletTypeToCryptoCurrency(appStore.wallet!.type),
218 _cryptoNumberFormat = NumberFormat(_cryptoNumberPattern),
219 hasAccounts =
220 - appStore.wallet!.type == WalletType.monero || appStore.wallet!.type == WalletType.haven,
220 + appStore.wallet!.type == WalletType.monero || appStore.wallet!.type == WalletType.wownero || appStore.wallet!.type == WalletType.haven,
221 amount = '',
222 _settingsStore = appStore.settingsStore,
223 super(appStore: appStore) {
@@ -229,7 +229,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
229 _init();
230
231 selectedCurrency = walletTypeToCryptoCurrency(wallet.type);
232 - hasAccounts = wallet.type == WalletType.monero || wallet.type == WalletType.haven;
232 + hasAccounts = wallet.type == WalletType.monero || wallet.type == WalletType.wownero || wallet.type == WalletType.haven;
233 }
234
235 static const String _cryptoNumberPattern = '0.00000000';
@@ -340,6 +340,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
340 addressList.addAll(addressItems);
341 }
342
343 + if (wallet.type == WalletType.wownero) {
344 + final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
345 + final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
346 + final isPrimary = subaddress == primaryAddress;
347 +
348 + return WalletAddressListItem(
349 + id: subaddress.id,
350 + isPrimary: isPrimary,
351 + name: subaddress.label,
352 + address: subaddress.address);
353 + });
354 + addressList.addAll(addressItems);
355 + }
356 +
357 if (wallet.type == WalletType.haven) {
358 final primaryAddress = haven!.getSubaddressList(wallet).subaddresses.first;
359 final addressItems = haven!.getSubaddressList(wallet).subaddresses.map((subaddress) {
@@ -430,20 +444,6 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
444 addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress));
445 }
446
433 - if (wallet.type == WalletType.wownero) {
434 - final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first;
435 - final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) {
436 - final isPrimary = subaddress == primaryAddress;
437 -
438 - return WalletAddressListItem(
439 - id: subaddress.id,
440 - isPrimary: isPrimary,
441 - name: subaddress.label,
442 - address: subaddress.address);
443 - });
444 - addressList.addAll(addressItems);
445 - }
446 -
447 if (searchText.isNotEmpty) {
448 return ObservableList.of(addressList.where((item) {
449 if (item is WalletAddressListItem) {
@@ -465,6 +465,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
465 return monero!.getCurrentAccount(wallet).label;
466 }
467
468 + if (wallet.type == WalletType.wownero) {
469 + return wownero!.getCurrentAccount(wallet).label;
470 + }
471 +
472 if (wallet.type == WalletType.haven) {
473 return haven!.getCurrentAccount(wallet).label;
474 }
@@ -475,6 +479,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
479 @computed
480 bool get hasAddressList =>
481 wallet.type == WalletType.monero ||
482 + wallet.type == WalletType.wownero ||
483 wallet.type == WalletType.haven ||
484 wallet.type == WalletType.bitcoinCash ||
485 wallet.type == WalletType.bitcoin ||
@@ -513,7 +518,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
518 void _init() {
519 _baseItems = [];
520
516 - if (wallet.type == WalletType.monero || wallet.type == WalletType.haven) {
521 + if (wallet.type == WalletType.monero || wallet.type == WalletType.wownero || wallet.type == WalletType.haven) {
522 _baseItems.add(WalletAccountListHeader());
523 }
524