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