Fixes for update fiat rate after change of current wallet type. Fixes for change amount for btc transactions. Changed displaying of balance for btc wallet. General fixes.

M committed Dec 15, 2020 at 18:29 UTC 8cb9bd15cdf4bf82d94d0cb92b2dab922a6f6955
29 files changed +334 -270
ios/Runner.xcodeproj/project.pbxproj
+6 -6
@@ -354,7 +354,7 @@
354 buildSettings = {
355 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
356 CLANG_ENABLE_MODULES = YES;
357 - CURRENT_PROJECT_VERSION = 1;
357 + CURRENT_PROJECT_VERSION = 2;
358 DEVELOPMENT_TEAM = 32J6BB6VUS;
359 ENABLE_BITCODE = NO;
360 FRAMEWORK_SEARCH_PATHS = (
@@ -371,7 +371,7 @@
371 "$(inherited)",
372 "$(PROJECT_DIR)/Flutter",
373 );
374 - MARKETING_VERSION = 4.0.9;
374 + MARKETING_VERSION = 4.1.0;
375 PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
376 PRODUCT_NAME = "$(TARGET_NAME)";
377 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -494,7 +494,7 @@
494 buildSettings = {
495 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
496 CLANG_ENABLE_MODULES = YES;
497 - CURRENT_PROJECT_VERSION = 1;
497 + CURRENT_PROJECT_VERSION = 2;
498 DEVELOPMENT_TEAM = 32J6BB6VUS;
499 ENABLE_BITCODE = NO;
500 FRAMEWORK_SEARCH_PATHS = (
@@ -511,7 +511,7 @@
511 "$(inherited)",
512 "$(PROJECT_DIR)/Flutter",
513 );
514 - MARKETING_VERSION = 4.0.9;
514 + MARKETING_VERSION = 4.1.0;
515 PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
516 PRODUCT_NAME = "$(TARGET_NAME)";
517 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -528,7 +528,7 @@
528 buildSettings = {
529 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
530 CLANG_ENABLE_MODULES = YES;
531 - CURRENT_PROJECT_VERSION = 1;
531 + CURRENT_PROJECT_VERSION = 2;
532 DEVELOPMENT_TEAM = 32J6BB6VUS;
533 ENABLE_BITCODE = NO;
534 FRAMEWORK_SEARCH_PATHS = (
@@ -545,7 +545,7 @@
545 "$(inherited)",
546 "$(PROJECT_DIR)/Flutter",
547 );
548 - MARKETING_VERSION = 4.0.9;
548 + MARKETING_VERSION = 4.1.0;
549 PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
550 PRODUCT_NAME = "$(TARGET_NAME)";
551 SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
lib/bitcoin/bitcoin_balance.dart
+15 -1
@@ -1,11 +1,13 @@
1 import 'dart:convert';
2
3 +import 'package:cake_wallet/entities/balance_display_mode.dart';
4 import 'package:flutter/foundation.dart';
5 import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
6 import 'package:cake_wallet/entities/balance.dart';
7
8 class BitcoinBalance extends Balance {
8 - const BitcoinBalance({@required this.confirmed, @required this.unconfirmed}) : super();
9 + const BitcoinBalance({@required this.confirmed, @required this.unconfirmed})
10 + : super(const [BalanceDisplayMode.availableBalance]);
11
12 factory BitcoinBalance.fromJSON(String jsonSource) {
13 if (jsonSource == null) {
@@ -30,6 +32,18 @@ class BitcoinBalance extends Balance {
32
33 String get totalFormatted => bitcoinAmountToString(amount: total);
34
35 + @override
36 + String formattedBalance(BalanceDisplayMode mode) {
37 + switch (mode) {
38 + case BalanceDisplayMode.fullBalance:
39 + return totalFormatted;
40 + case BalanceDisplayMode.availableBalance:
41 + return totalFormatted;
42 + default:
43 + return null;
44 + }
45 + }
46 +
47 String toJSON() =>
48 json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed});
49 }
lib/bitcoin/bitcoin_wallet.dart
+7 -3
@@ -262,9 +262,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
262 final utxs = await unptsFutures;
263
264 for (final utx in utxs) {
265 - final inAmount = utx.value > totalAmount ? totalAmount : utx.value;
266 - leftAmount = leftAmount - inAmount;
267 - totalInputAmount += inAmount;
265 + leftAmount = leftAmount - utx.value;
266 + totalInputAmount += utx.value;
267 inputs.add(utx);
268
269 if (leftAmount <= 0) {
@@ -348,6 +347,11 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
347 // FIXME: Unimplemented
348 }
349
350 + @override
351 + void close() {
352 +
353 + }
354 +
355 void _subscribeForUpdates() {
356 scriptHashes.forEach((sh) async {
357 await _scripthashesUpdateSubject[sh]?.close();
lib/bitcoin/electrum.dart
+5 -3
@@ -75,7 +75,7 @@ class ElectrumClient {
75 try {
76 final jsoned =
77 json.decode(utf8.decode(event.toList())) as Map<String, Object>;
78 - print(jsoned);
78 + // print(jsoned);
79 final method = jsoned['method'];
80 final id = jsoned['id'] as String;
81 final result = jsoned['result'];
@@ -92,7 +92,9 @@ class ElectrumClient {
92 }, onError: (Object error) {
93 print(error.toString());
94 _setIsConnected(false);
95 - }, onDone: () => _setIsConnected(false));
95 + }, onDone: () {
96 + _setIsConnected(false);
97 + });
98 keepAlive();
99 }
100
@@ -103,7 +105,7 @@ class ElectrumClient {
105
106 Future<void> ping() async {
107 try {
106 - // await callWithTimeout(method: 'server.ping');
108 + await callWithTimeout(method: 'server.ping');
109 _setIsConnected(true);
110 } on RequestFailedTimeoutException catch (_) {
111 _setIsConnected(false);
lib/core/wallet_base.dart
+2
@@ -52,4 +52,6 @@ abstract class WalletBase<BalaceType> {
52 Future<void> save();
53
54 Future<void> rescan({int height});
55 +
56 + void close();
57 }
lib/entities/balance.dart
+7 -1
@@ -1,3 +1,9 @@
1 +import 'package:cake_wallet/entities/balance_display_mode.dart';
2 +
3 abstract class Balance {
2 - const Balance();
4 + const Balance(this.availableModes);
5 +
6 + final List<BalanceDisplayMode> availableModes;
7 +
8 + String formattedBalance(BalanceDisplayMode mode);
9 }
lib/entities/load_current_wallet.dart
+1 -1
@@ -19,5 +19,5 @@ Future<void> loadCurrentWallet() async {
19 await getIt.get<KeyService>().getWalletPassword(walletName: name);
20 final _service = getIt.get<WalletService>(param1: type);
21 final wallet = await _service.openWallet(name, password);
22 - appStore.wallet = wallet;
22 + appStore.changeCurrentWallet(wallet);
23 }
lib/entities/node_list.dart
+3 -3
@@ -39,9 +39,9 @@ Future<List<Node>> loadElectrumServerList() async {
39
40 Future resetToDefault(Box<Node> nodeSource) async {
41 final moneroNodes = await loadDefaultNodes();
42 - // final bitcoinElectrumServerList = await loadElectrumServerList();
43 - // final nodes = moneroNodes + bitcoinElectrumServerList;
42 + final bitcoinElectrumServerList = await loadElectrumServerList();
43 + final nodes = moneroNodes + bitcoinElectrumServerList;
44
45 await nodeSource.clear();
46 - await nodeSource.addAll(moneroNodes);
46 + await nodeSource.addAll(nodes);
47 }
lib/main.dart
-1
@@ -83,7 +83,6 @@ void main() async {
83 )))));
84 }
85 }
86 -
86 Future<void> initialSetup(
87 {@required SharedPreferences sharedPreferences,
88 @required Box<Node> nodes,
lib/monero/monero_balance.dart
+27 -5
@@ -1,20 +1,42 @@
1 +import 'package:cake_wallet/entities/balance.dart';
2 +import 'package:cake_wallet/entities/balance_display_mode.dart';
3 import 'package:flutter/foundation.dart';
4 import 'package:cake_wallet/monero/monero_amount_format.dart';
5
4 -class MoneroBalance {
6 +class MoneroBalance extends Balance {
7 MoneroBalance({@required this.fullBalance, @required this.unlockedBalance})
8 : formattedFullBalance = moneroAmountToString(amount: fullBalance),
9 formattedUnlockedBalance =
8 - moneroAmountToString(amount: unlockedBalance);
10 + moneroAmountToString(amount: unlockedBalance),
11 + super(const [
12 + BalanceDisplayMode.availableBalance,
13 + BalanceDisplayMode.fullBalance
14 + ]);
15
16 MoneroBalance.fromString(
17 {@required this.formattedFullBalance,
12 - @required this.formattedUnlockedBalance})
18 + @required this.formattedUnlockedBalance})
19 : fullBalance = moneroParseAmount(amount: formattedFullBalance),
14 - unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance);
20 + unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
21 + super(const [
22 + BalanceDisplayMode.availableBalance,
23 + BalanceDisplayMode.fullBalance
24 + ]);
25
26 final int fullBalance;
27 final int unlockedBalance;
28 final String formattedFullBalance;
29 final String formattedUnlockedBalance;
20 -}
\ No newline at end of file
30 +
31 + @override
32 + String formattedBalance(BalanceDisplayMode mode) {
33 + switch (mode) {
34 + case BalanceDisplayMode.fullBalance:
35 + return formattedFullBalance;
36 + case BalanceDisplayMode.availableBalance:
37 + return formattedUnlockedBalance;
38 + default:
39 + return null;
40 + }
41 + }
42 +}
lib/monero/monero_wallet.dart
+41 -33
@@ -43,7 +43,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
43 balance = MoneroBalance(
44 fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
45 unlockedBalance:
46 - monero_wallet.getUnlockedBalance(accountIndex: account.id));
46 + monero_wallet.getUnlockedBalance(accountIndex: account.id));
47 subaddressList.update(accountIndex: account.id);
48 subaddress = subaddressList.subaddresses.first;
49 address = subaddress.address;
@@ -120,6 +120,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
120 }
121 }
122
123 + @override
124 void close() {
125 _listener?.stop();
126 _onAccountChangeReaction?.reaction?.dispose();
@@ -315,9 +316,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
316 }
317 }
318
318 - Future<void> _askForUpdateTransactionHistory() async {
319 - await transactionHistory.update();
320 - }
319 + Future<void> _askForUpdateTransactionHistory() async =>
320 + await transactionHistory.update();
321
322 int _getFullBalance() =>
323 monero_wallet.getFullBalance(accountIndex: account.id);
@@ -326,13 +326,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
326 monero_wallet.getUnlockedBalance(accountIndex: account.id);
327
328 Future<void> _afterSyncSave() async {
329 - if (_isSavingAfterSync) {
330 - return;
331 - }
329 + try {
330 + if (_isSavingAfterSync) {
331 + return;
332 + }
333
333 - _isSavingAfterSync = true;
334 + _isSavingAfterSync = true;
335
335 - try {
336 final nowTimestamp = DateTime.now().millisecondsSinceEpoch;
337 final sum = _lastAutosaveTimestamp + _autoAfterSyncSaveInterval;
338
@@ -350,13 +350,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
350 }
351
352 Future<void> _afterNewTransactionSave() async {
353 - if (_isSavingAfterNewTransaction) {
354 - return;
355 - }
353 + try {
354 + if (_isSavingAfterNewTransaction) {
355 + return;
356 + }
357
357 - _isSavingAfterNewTransaction = true;
358 + _isSavingAfterNewTransaction = true;
359
359 - try {
360 await save();
361 } catch (e) {
362 print(e.toString());
@@ -366,30 +366,38 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
366 }
367
368 void _onNewBlock(int height, int blocksLeft, double ptc) async {
369 - if (walletInfo.isRecovery) {
370 - await _askForUpdateTransactionHistory();
371 - _askForUpdateBalance();
372 - accountList.update();
373 - }
374 -
375 - if (blocksLeft < 100) {
376 - await _askForUpdateTransactionHistory();
377 - _askForUpdateBalance();
378 - accountList.update();
379 - syncStatus = SyncedSyncStatus();
380 - await _afterSyncSave();
381 -
369 + try {
370 if (walletInfo.isRecovery) {
383 - await setAsRecovered();
371 + await _askForUpdateTransactionHistory();
372 + _askForUpdateBalance();
373 + accountList.update();
374 + }
375 +
376 + if (blocksLeft < 100) {
377 + await _askForUpdateTransactionHistory();
378 + _askForUpdateBalance();
379 + accountList.update();
380 + syncStatus = SyncedSyncStatus();
381 + await _afterSyncSave();
382 +
383 + if (walletInfo.isRecovery) {
384 + await setAsRecovered();
385 + }
386 + } else {
387 + syncStatus = SyncingSyncStatus(blocksLeft, ptc);
388 }
385 - } else {
386 - syncStatus = SyncingSyncStatus(blocksLeft, ptc);
389 + } catch (e) {
390 + print(e.toString());
391 }
392 }
393
394 void _onNewTransaction() {
391 - _askForUpdateTransactionHistory();
392 - _askForUpdateBalance();
393 - Timer(Duration(seconds: 1), () => _afterNewTransactionSave());
395 + try {
396 + _askForUpdateTransactionHistory();
397 + _askForUpdateBalance();
398 + Timer(Duration(seconds: 1), () => _afterNewTransactionSave());
399 + } catch (e) {
400 + print(e.toString());
401 + }
402 }
403 }
lib/reactions/fiat_rate_update.dart
+4 -3
@@ -12,12 +12,13 @@ Future<void> startFiatRateUpdate(AppStore appStore, SettingsStore settingsStore,
12 return;
13 }
14
15 - fiatConversionStore.price = await FiatConversionService.fetchPrice(
16 - appStore.wallet.currency, settingsStore.fiatCurrency);
15 + fiatConversionStore.prices[appStore.wallet.currency] =
16 + await FiatConversionService.fetchPrice(
17 + appStore.wallet.currency, settingsStore.fiatCurrency);
18
19 _timer = Timer.periodic(
20 Duration(seconds: 30),
20 - (_) async => fiatConversionStore.price =
21 + (_) async => fiatConversionStore.prices[appStore.wallet.currency] =
22 await FiatConversionService.fetchPrice(
23 appStore.wallet.currency, settingsStore.fiatCurrency));
24 }
lib/reactions/on_current_fiat_change.dart
+6 -5
@@ -7,12 +7,13 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
7
8 ReactionDisposer _onCurrentFiatCurrencyChangeDisposer;
9
10 -void startCurrentFiatChangeReaction(AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
10 +void startCurrentFiatChangeReaction(AppStore appStore,
11 + SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
12 _onCurrentFiatCurrencyChangeDisposer?.reaction?.dispose();
13 _onCurrentFiatCurrencyChangeDisposer = reaction(
13 - (_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async {
14 + (_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async {
15 final cryptoCurrency = appStore.wallet.currency;
15 - fiatConversionStore.price = await FiatConversionService.fetchPrice(
16 - cryptoCurrency, fiatCurrency);
16 + fiatConversionStore.prices[appStore.wallet.currency] =
17 + await FiatConversionService.fetchPrice(cryptoCurrency, fiatCurrency);
18 });
18 -}
\ No newline at end of file
19 +}
lib/reactions/on_current_node_change.dart
+2 -3
@@ -6,10 +6,9 @@ ReactionDisposer _onCurrentNodeChangeReaction;
6
7 void startOnCurrentNodeChangeReaction(AppStore appStore) {
8 _onCurrentNodeChangeReaction?.reaction?.dispose();
9 - _onCurrentNodeChangeReaction =
10 - reaction((_) => appStore.settingsStore.currentNode, (Node node) async {
9 + appStore.settingsStore.nodes.observe((change) async {
10 try {
12 - await appStore.wallet.connectToNode(node: node);
11 + await appStore.wallet.connectToNode(node: change.newValue);
12 } catch (e) {
13 print(e.toString());
14 }
lib/reactions/on_current_wallet_change.dart
+10 -1
@@ -12,6 +12,7 @@ import 'package:cake_wallet/core/wallet_base.dart';
12 import 'package:cake_wallet/entities/wallet_type.dart';
13
14 ReactionDisposer _onCurrentWalletChangeReaction;
15 +ReactionDisposer _onCurrentWalletChangeFiatRateUpdateReaction;
16
17 void startCurrentWalletChangeReaction(AppStore appStore,
18 SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
@@ -29,8 +30,16 @@ void startCurrentWalletChangeReaction(AppStore appStore,
30 await getIt.get<SharedPreferences>().setInt(
31 PreferencesKey.currentWalletType, serializeToInt(wallet.type));
32 await wallet.connectToNode(node: node);
33 + } catch (e) {
34 + print(e.toString());
35 + }
36 + });
37
33 - fiatConversionStore.price = await FiatConversionService.fetchPrice(
38 + _onCurrentWalletChangeFiatRateUpdateReaction =
39 + reaction((_) => appStore.wallet, (WalletBase wallet) async {
40 + try {
41 + fiatConversionStore.prices[wallet.currency] = 0;
42 + fiatConversionStore.prices[wallet.currency] = await FiatConversionService.fetchPrice(
43 wallet.currency, settingsStore.fiatCurrency);
44 } catch (e) {
45 print(e.toString());
lib/src/screens/dashboard/widgets/balance_page.dart
+55 -47
@@ -11,58 +11,66 @@ class BalancePage extends StatelessWidget {
11 @override
12 Widget build(BuildContext context) {
13 return Container(
14 - padding: EdgeInsets.all(24),
15 - child: GestureDetector(
16 - onTapUp: (_) => dashboardViewModel.balanceViewModel.isReversing = false,
17 - onTapDown: (_) => dashboardViewModel.balanceViewModel.isReversing = true,
18 - child: Column(
19 - mainAxisAlignment: MainAxisAlignment.center,
20 - crossAxisAlignment: CrossAxisAlignment.center,
21 - children: <Widget>[
22 - Observer(builder: (_) {
23 - return Text(
24 - dashboardViewModel.balanceViewModel.currency.toString(),
25 - style: TextStyle(
26 - fontSize: 40,
27 - fontWeight: FontWeight.bold,
28 - color: Theme.of(context).indicatorColor,
29 - height: 1),
30 - );
31 - }),
32 - Observer(builder: (_) {
33 - return Text(
34 - dashboardViewModel.balanceViewModel.displayMode.toString(),
35 - style: TextStyle(
36 - fontSize: 12,
37 - fontWeight: FontWeight.w600,
38 - color: Theme.of(context).indicatorColor,
39 - height: 1),
40 - );
41 - }),
42 - SizedBox(height: 10),
43 - Observer(builder: (_) {
44 - return AutoSizeText(dashboardViewModel.balanceViewModel.cryptoBalance,
14 + padding: EdgeInsets.all(24),
15 + child: GestureDetector(
16 + onTapUp: (_) {
17 + if (dashboardViewModel.balanceViewModel.canReverse) {
18 + dashboardViewModel.balanceViewModel.isReversing = false;
19 + }
20 + },
21 + onTapDown: (_) {
22 + if (dashboardViewModel.balanceViewModel.canReverse) {
23 + dashboardViewModel.balanceViewModel.isReversing = true;
24 + }
25 + },
26 + child: Column(
27 + mainAxisAlignment: MainAxisAlignment.center,
28 + crossAxisAlignment: CrossAxisAlignment.center,
29 + children: <Widget>[
30 + Observer(builder: (_) {
31 + return Text(
32 + dashboardViewModel.balanceViewModel.currency.toString(),
33 style: TextStyle(
46 - fontSize: 54,
34 + fontSize: 40,
35 fontWeight: FontWeight.bold,
48 - color: Colors.white,
36 + color: Theme.of(context).indicatorColor,
37 height: 1),
50 - maxLines: 1,
51 - textAlign: TextAlign.center);
52 - }),
53 - SizedBox(height: 10),
54 - Observer(builder: (_) {
55 - return Text(dashboardViewModel.balanceViewModel.fiatBalance,
38 + );
39 + }),
40 + Observer(builder: (_) {
41 + return Text(
42 + dashboardViewModel.balanceViewModel.displayMode.toString(),
43 style: TextStyle(
57 - fontSize: 18,
58 - fontWeight: FontWeight.w500,
44 + fontSize: 12,
45 + fontWeight: FontWeight.w600,
46 color: Theme.of(context).indicatorColor,
47 height: 1),
61 - textAlign: TextAlign.center);
62 - }),
63 - ],
64 - ),
65 - )
66 - );
48 + );
49 + }),
50 + SizedBox(height: 10),
51 + Observer(builder: (_) {
52 + return AutoSizeText(
53 + dashboardViewModel.balanceViewModel.cryptoBalance,
54 + style: TextStyle(
55 + fontSize: 54,
56 + fontWeight: FontWeight.bold,
57 + color: Colors.white,
58 + height: 1),
59 + maxLines: 1,
60 + textAlign: TextAlign.center);
61 + }),
62 + SizedBox(height: 10),
63 + Observer(builder: (_) {
64 + return Text(dashboardViewModel.balanceViewModel.fiatBalance,
65 + style: TextStyle(
66 + fontSize: 18,
67 + fontWeight: FontWeight.w500,
68 + color: Theme.of(context).indicatorColor,
69 + height: 1),
70 + textAlign: TextAlign.center);
71 + }),
72 + ],
73 + ),
74 + ));
75 }
76 }
lib/src/screens/dashboard/widgets/transactions_page.dart
+3 -2
@@ -46,7 +46,8 @@ class TransactionsPage extends StatelessWidget {
46 if (item is TransactionListItem) {
47 final transaction = item.transaction;
48
49 - return TransactionRow(
49 + return Observer(
50 + builder: (_) => TransactionRow(
51 onTap: () => Navigator.of(context).pushNamed(
52 Routes.transactionDetails,
53 arguments: transaction),
@@ -55,7 +56,7 @@ class TransactionsPage extends StatelessWidget {
56 .format(transaction.date),
57 formattedAmount: item.formattedCryptoAmount,
58 formattedFiatAmount: item.formattedFiatAmount,
58 - isPending: transaction.isPending);
59 + isPending: transaction.isPending));
60 }
61
62 if (item is TradeListItem) {
lib/src/screens/nodes/nodes_list_page.dart
+78 -86
@@ -65,98 +65,90 @@ class NodeListPage extends BasePage {
65 padding: EdgeInsets.only(top: 10),
66 child: Observer(
67 builder: (BuildContext context) {
68 - return nodeListViewModel.nodes.isNotEmpty
69 - ? SectionStandardList(
70 - sectionCount: 2,
71 - context: context,
72 - itemCounter: (int sectionIndex) {
73 - if (sectionIndex == 0) {
74 - return 1;
75 - }
68 + return SectionStandardList(
69 + sectionCount: 2,
70 + context: context,
71 + itemCounter: (int sectionIndex) {
72 + if (sectionIndex == 0) {
73 + return 1;
74 + }
75
77 - return nodeListViewModel.nodes.length;
78 - },
79 - itemBuilder: (_, sectionIndex, index) {
80 - if (sectionIndex == 0) {
81 - return NodeHeaderListRow(
82 - title: S.of(context).add_new_node,
83 - onTap: (_) async => await Navigator.of(context)
84 - .pushNamed(Routes.newNode));
85 - }
76 + return nodeListViewModel.nodes.length;
77 + },
78 + itemBuilder: (_, sectionIndex, index) {
79 + if (sectionIndex == 0) {
80 + return NodeHeaderListRow(
81 + title: S.of(context).add_new_node,
82 + onTap: (_) async => await Navigator.of(context)
83 + .pushNamed(Routes.newNode));
84 + }
85
87 - final node = nodeListViewModel.nodes[index];
88 - final isSelected = node.keyIndex ==
89 - nodeListViewModel.settingsStore.currentNode.keyIndex;
90 - final nodeListRow = NodeListRow(
91 - title: node.uri,
92 - isSelected: isSelected,
93 - isAlive: node.requestNode(),
94 - onTap: (_) async {
95 - if (isSelected) {
96 - return;
97 - }
86 + final node = nodeListViewModel.nodes[index];
87 + final isSelected =
88 + node.keyIndex == nodeListViewModel.currentNode?.keyIndex;
89 + final nodeListRow = NodeListRow(
90 + title: node.uri,
91 + isSelected: isSelected,
92 + isAlive: node.requestNode(),
93 + onTap: (_) async {
94 + if (isSelected) {
95 + return;
96 + }
97
99 - await showPopUp<void>(
100 - context: context,
101 - builder: (BuildContext context) {
102 - return AlertWithTwoActions(
103 - alertTitle: S.of(context)
104 - .change_current_node_title,
105 - alertContent: S
106 - .of(context)
107 - .change_current_node(node.uri),
108 - leftButtonText: S.of(context).cancel,
109 - rightButtonText: S.of(context).change,
110 - actionLeftButton: () =>
111 - Navigator.of(context).pop(),
112 - actionRightButton: () async {
113 - await nodeListViewModel
114 - .setAsCurrent(node);
115 - Navigator.of(context).pop();
116 - });
117 - });
118 - });
98 + await showPopUp<void>(
99 + context: context,
100 + builder: (BuildContext context) {
101 + return AlertWithTwoActions(
102 + alertTitle:
103 + S.of(context).change_current_node_title,
104 + alertContent:
105 + S.of(context).change_current_node(node.uri),
106 + leftButtonText: S.of(context).cancel,
107 + rightButtonText: S.of(context).change,
108 + actionLeftButton: () =>
109 + Navigator.of(context).pop(),
110 + actionRightButton: () async {
111 + await nodeListViewModel.setAsCurrent(node);
112 + Navigator.of(context).pop();
113 + });
114 + });
115 + });
116
120 - final dismissibleRow = Slidable(
121 - key: Key('${node.keyIndex}'),
122 - actionPane: SlidableDrawerActionPane(),
123 - child: nodeListRow,
124 - secondaryActions: <Widget>[
125 - IconSlideAction(
126 - caption: S.of(context).delete,
127 - color: Colors.red,
128 - icon: CupertinoIcons.delete,
129 - onTap: () async {
130 - final confirmed = await showPopUp<bool>(
131 - context: context,
132 - builder: (BuildContext context) {
133 - return AlertWithTwoActions(
134 - alertTitle:
135 - S.of(context).remove_node,
136 - alertContent: S
137 - .of(context)
138 - .remove_node_message,
139 - rightButtonText:
140 - S.of(context).remove,
141 - leftButtonText:
142 - S.of(context).cancel,
143 - actionRightButton: () =>
144 - Navigator.pop(context, true),
145 - actionLeftButton: () =>
146 - Navigator.pop(context, false));
147 - }) ??
148 - false;
117 + final dismissibleRow = Slidable(
118 + key: Key('${node.keyIndex}'),
119 + actionPane: SlidableDrawerActionPane(),
120 + child: nodeListRow,
121 + secondaryActions: <Widget>[
122 + IconSlideAction(
123 + caption: S.of(context).delete,
124 + color: Colors.red,
125 + icon: CupertinoIcons.delete,
126 + onTap: () async {
127 + final confirmed = await showPopUp<bool>(
128 + context: context,
129 + builder: (BuildContext context) {
130 + return AlertWithTwoActions(
131 + alertTitle: S.of(context).remove_node,
132 + alertContent:
133 + S.of(context).remove_node_message,
134 + rightButtonText: S.of(context).remove,
135 + leftButtonText: S.of(context).cancel,
136 + actionRightButton: () =>
137 + Navigator.pop(context, true),
138 + actionLeftButton: () =>
139 + Navigator.pop(context, false));
140 + }) ??
141 + false;
142
150 - if (confirmed) {
151 - await nodeListViewModel.delete(node);
152 - }
153 - },
154 - ),
155 - ]);
143 + if (confirmed) {
144 + await nodeListViewModel.delete(node);
145 + }
146 + },
147 + ),
148 + ]);
149
157 - return isSelected ? nodeListRow : dismissibleRow;
158 - })
159 - : Container();
150 + return isSelected ? nodeListRow : dismissibleRow;
151 + });
152 },
153 ),
154 );
lib/src/widgets/address_text_field.dart
+1 -1
@@ -204,7 +204,7 @@ class AddressTextField extends StatelessWidget {
204 onURIScanned(uri);
205 }
206 } catch (e) {
207 - print('Error $e');
207 + print(e.toString());
208 }
209 }
210
lib/store/app_store.dart
+6
@@ -26,4 +26,10 @@ abstract class AppStoreBase with Store {
26 SettingsStore settingsStore;
27
28 NodeListStore nodeListStore;
29 +
30 + @action
31 + void changeCurrentWallet(WalletBase wallet) {
32 + this.wallet?.close();
33 + this.wallet = wallet;
34 + }
35 }
lib/store/dashboard/fiat_conversion_store.dart
+4 -4
@@ -1,13 +1,13 @@
1 +import 'package:cake_wallet/entities/crypto_currency.dart';
2 import 'package:mobx/mobx.dart';
3
4 part 'fiat_conversion_store.g.dart';
5
5 -class FiatConversionStore = FiatConversionStoreBase
6 - with _$FiatConversionStore;
6 +class FiatConversionStore = FiatConversionStoreBase with _$FiatConversionStore;
7
8 abstract class FiatConversionStoreBase with Store {
9 - FiatConversionStoreBase() : price = 0.0;
9 + FiatConversionStoreBase() : prices = ObservableMap<CryptoCurrency, double>();
10
11 @observable
12 - double price;
12 + ObservableMap<CryptoCurrency, double> prices;
13 }
lib/store/settings_store.dart
+4 -7
@@ -43,7 +43,6 @@ abstract class SettingsStoreBase with Store {
43 isDarkTheme = initialDarkTheme;
44 pinCodeLength = initialPinLength;
45 languageCode = initialLanguageCode;
46 - currentNode = nodes[WalletType.monero];
46 this.nodes = ObservableMap<WalletType, Node>.of(nodes);
47 _sharedPreferences = sharedPreferences;
48
@@ -80,13 +79,14 @@ abstract class SettingsStoreBase with Store {
79 (int pinLength) => sharedPreferences.setInt(
80 PreferencesKey.currentPinLength, pinLength));
81
83 - reaction((_) => currentNode,
84 - (Node node) => _saveCurrentNode(node, WalletType.monero));
85 -
82 reaction(
83 (_) => languageCode,
84 (String languageCode) => sharedPreferences.setString(
85 PreferencesKey.currentLanguageCode, languageCode));
86 +
87 + this
88 + .nodes
89 + .observe((change) => _saveCurrentNode(change.newValue, change.key));
90 }
91
92 static const defaultPinLength = 4;
@@ -116,9 +116,6 @@ abstract class SettingsStoreBase with Store {
116 @observable
117 int pinCodeLength;
118
119 - @observable
120 - Node currentNode;
121 -
119 @computed
120 ThemeData get theme => isDarkTheme ? Themes.darkTheme : Themes.lightTheme;
121
lib/utils/mobx.dart
+2 -1
@@ -57,7 +57,8 @@ extension MobxBindable<T extends Keyable> on Box<T> {
57 Filter<T> filter,
58 }) {
59 if (initialFire) {
60 - dest.addAll(values);
60 + final res = filter != null ? values.where(filter) : values;
61 + dest.addAll(res);
62 }
63
64 return watch().listen((event) {
lib/view_model/dashboard/balance_view_model.dart
+20 -21
@@ -15,31 +15,34 @@ part 'balance_view_model.g.dart';
15 class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel;
16
17 abstract class BalanceViewModelBase with Store {
18 - BalanceViewModelBase({
19 - @required this.appStore,
20 - @required this.settingsStore,
21 - @required this.fiatConvertationStore
22 - }) : isReversing = false;
18 + BalanceViewModelBase(
19 + {@required this.appStore,
20 + @required this.settingsStore,
21 + @required this.fiatConvertationStore})
22 + : isReversing = false;
23
24 final AppStore appStore;
25 final SettingsStore settingsStore;
26 final FiatConversionStore fiatConvertationStore;
27
28 + bool get canReverse =>
29 + (appStore.wallet.balance.availableModes as List).length > 1;
30 +
31 @observable
32 bool isReversing;
33
34 @computed
32 - BalanceDisplayMode get savedDisplayMode => settingsStore.balanceDisplayMode;
35 + double get price => fiatConvertationStore.prices[appStore.wallet.currency];
36
37 @computed
35 - BalanceDisplayMode get displayMode => isReversing
36 - ? (savedDisplayMode == BalanceDisplayMode.availableBalance
37 - ? BalanceDisplayMode.fullBalance
38 - : BalanceDisplayMode.availableBalance)
39 - : savedDisplayMode;
38 + BalanceDisplayMode get savedDisplayMode => settingsStore.balanceDisplayMode;
39
40 @computed
42 - double get price => fiatConvertationStore.price;
41 + BalanceDisplayMode get displayMode => isReversing
42 + ? (savedDisplayMode == BalanceDisplayMode.availableBalance
43 + ? BalanceDisplayMode.fullBalance
44 + : BalanceDisplayMode.availableBalance)
45 + : savedDisplayMode;
46
47 @computed
48 String get cryptoBalance {
@@ -63,15 +66,11 @@ abstract class BalanceViewModelBase with Store {
66 final fiatCurrency = settingsStore.fiatCurrency;
67 var balance = '---';
68
66 - final totalBalance = _getFiatBalance(
67 - price: price,
68 - cryptoAmount: walletBalance.totalBalance
69 - );
69 + final totalBalance =
70 + _getFiatBalance(price: price, cryptoAmount: walletBalance.totalBalance);
71
72 final unlockedBalance = _getFiatBalance(
72 - price: price,
73 - cryptoAmount: walletBalance.unlockedBalance
74 - );
73 + price: price, cryptoAmount: walletBalance.unlockedBalance);
74
75 if (displayMode == BalanceDisplayMode.availableBalance) {
76 balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00';
@@ -89,7 +88,7 @@ abstract class BalanceViewModelBase with Store {
88 final _wallet = appStore.wallet;
89
90 if (_wallet is MoneroWallet) {
92 - return WalletBalance(
91 + return WalletBalance(
92 unlockedBalance: _wallet.balance.formattedUnlockedBalance,
93 totalBalance: _wallet.balance.formattedFullBalance);
94 }
@@ -113,4 +112,4 @@ abstract class BalanceViewModelBase with Store {
112
113 return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount);
114 }
116 -}
\ No newline at end of file
115 +}
lib/view_model/node_list/node_list_view_model.dart
+9 -9
@@ -13,16 +13,18 @@ part 'node_list_view_model.g.dart';
13 class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
14
15 abstract class NodeListViewModelBase with Store {
16 - NodeListViewModelBase(this._nodeSource, this._wallet, this.settingsStore)
16 + NodeListViewModelBase(this._nodeSource, this.wallet, this.settingsStore)
17 : nodes = ObservableList<Node>() {
18 _nodeSource.bindToList(nodes,
19 - filter: (Node val) => val?.type == _wallet.type, initialFire: true);
19 + filter: (Node val) => val?.type == wallet.type, initialFire: true);
20 }
21
22 + @computed
23 + Node get currentNode => settingsStore.nodes[wallet.type];
24 +
25 final ObservableList<Node> nodes;
26 final SettingsStore settingsStore;
24 -
25 - final WalletBase _wallet;
27 + final WalletBase wallet;
28 final Box<Node> _nodeSource;
29
30 Future<void> reset() async {
@@ -30,14 +32,12 @@ abstract class NodeListViewModelBase with Store {
32
33 Node node;
34
33 - switch (_wallet.type) {
35 + switch (wallet.type) {
36 case WalletType.bitcoin:
37 node = getBitcoinDefaultElectrumServer(nodes: _nodeSource);
38 break;
39 case WalletType.monero:
38 - node = getMoneroDefaultNode(
39 - nodes: _nodeSource,
40 - );
40 + node = getMoneroDefaultNode(nodes: _nodeSource);
41 break;
42 default:
43 break;
@@ -50,5 +50,5 @@ abstract class NodeListViewModelBase with Store {
50 Future<void> delete(Node node) async => node.delete();
51
52 Future<void> setAsCurrent(Node node) async =>
53 - settingsStore.currentNode = node;
53 + settingsStore.nodes[wallet.type] = node;
54 }
lib/view_model/send/send_view_model.dart
+6 -15
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/entities/balance_display_mode.dart';
2 import 'package:cake_wallet/entities/transaction_description.dart';
3 import 'package:hive/hive.dart';
4 import 'package:intl/intl.dart';
@@ -77,19 +78,9 @@ abstract class SendViewModelBase with Store {
78 PendingTransaction pendingTransaction;
79
80 @computed
80 - String get balance {
81 - String balance = '0.0';
82 -
83 - if (_wallet is MoneroWallet) {
84 - balance = _wallet.balance.formattedUnlockedBalance as String ?? '';
85 - }
86 -
87 - if (_wallet is BitcoinWallet) {
88 - balance = _wallet.balance.confirmedFormatted as String ?? '';
89 - }
90 -
91 - return balance;
92 - }
81 + String get balance =>
82 + _wallet.balance.formattedBalance(BalanceDisplayMode.availableBalance)
83 + as String ?? '0.0';
84
85 @computed
86 bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus;
@@ -176,7 +167,7 @@ abstract class SendViewModelBase with Store {
167 void _updateFiatAmount() {
168 try {
169 final fiat = calculateFiatAmount(
179 - price: _fiatConversationStore.price,
170 + price: _fiatConversationStore.prices[_wallet.currency],
171 cryptoAmount: cryptoAmount.replaceAll(',', '.'));
172 if (fiatAmount != fiat) {
173 fiatAmount = fiat;
@@ -190,7 +181,7 @@ abstract class SendViewModelBase with Store {
181 void _updateCryptoAmount() {
182 try {
183 final crypto = double.parse(fiatAmount.replaceAll(',', '.')) /
193 - _fiatConversationStore.price;
184 + _fiatConversationStore.prices[_wallet.currency];
185 final cryptoAmountTmp = _cryptoNumberFormat.format(crypto);
186
187 if (cryptoAmount != cryptoAmountTmp) {
lib/view_model/settings/settings_view_model.dart
+7 -6
@@ -35,12 +35,13 @@ abstract class SettingsViewModelBase with Store {
35 (PackageInfo packageInfo) => currentVersion = packageInfo.version);
36 sections = [
37 [
38 - PickerListItem(
39 - title: S.current.settings_display_balance_as,
40 - items: BalanceDisplayMode.all,
41 - selectedItem: () => balanceDisplayMode,
42 - onItemSelected: (BalanceDisplayMode mode) =>
43 - _settingsStore.balanceDisplayMode = mode),
38 + if ((wallet.balance.availableModes as List).length > 1)
39 + PickerListItem(
40 + title: S.current.settings_display_balance_as,
41 + items: BalanceDisplayMode.all,
42 + selectedItem: () => balanceDisplayMode,
43 + onItemSelected: (BalanceDisplayMode mode) =>
44 + _settingsStore.balanceDisplayMode = mode),
45 PickerListItem(
46 title: S.current.settings_currency,
47 items: FiatCurrency.all,
lib/view_model/wallet_creation_vm.dart
+1 -1
@@ -51,7 +51,7 @@ abstract class WalletCreationVMBase with Store {
51 credentials.walletInfo = walletInfo;
52 final wallet = await process(credentials);
53 await _walletInfoSource.add(walletInfo);
54 - _appStore.wallet = wallet;
54 + _appStore.changeCurrentWallet(wallet);
55 _appStore.authenticationStore.allowed();
56 state = ExecutedSuccessfullyState();
57 } catch (e) {
lib/view_model/wallet_list/wallet_list_view_model.dart
+2 -1
@@ -32,7 +32,8 @@ abstract class WalletListViewModelBase with Store {
32 final password =
33 await _keyService.getWalletPassword(walletName: wallet.name);
34 final walletService = getIt.get<WalletService>(param1: wallet.type);
35 - _appStore.wallet = await walletService.openWallet(wallet.name, password);
35 + final loadedWallet = await walletService.openWallet(wallet.name, password);
36 + _appStore.changeCurrentWallet(loadedWallet);
37 _updateList();
38 }
39