diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index ca92f3f09..cfab7a395 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -354,7 +354,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -371,7 +371,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 4.0.9; + MARKETING_VERSION = 4.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -494,7 +494,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -511,7 +511,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 4.0.9; + MARKETING_VERSION = 4.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -528,7 +528,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 32J6BB6VUS; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -545,7 +545,7 @@ "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - MARKETING_VERSION = 4.0.9; + MARKETING_VERSION = 4.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/bitcoin/bitcoin_balance.dart b/lib/bitcoin/bitcoin_balance.dart index 6aefe28f4..2afece832 100644 --- a/lib/bitcoin/bitcoin_balance.dart +++ b/lib/bitcoin/bitcoin_balance.dart @@ -1,11 +1,13 @@ import 'dart:convert'; +import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:flutter/foundation.dart'; import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart'; import 'package:cake_wallet/entities/balance.dart'; class BitcoinBalance extends Balance { - const BitcoinBalance({@required this.confirmed, @required this.unconfirmed}) : super(); + const BitcoinBalance({@required this.confirmed, @required this.unconfirmed}) + : super(const [BalanceDisplayMode.availableBalance]); factory BitcoinBalance.fromJSON(String jsonSource) { if (jsonSource == null) { @@ -30,6 +32,18 @@ class BitcoinBalance extends Balance { String get totalFormatted => bitcoinAmountToString(amount: total); + @override + String formattedBalance(BalanceDisplayMode mode) { + switch (mode) { + case BalanceDisplayMode.fullBalance: + return totalFormatted; + case BalanceDisplayMode.availableBalance: + return totalFormatted; + default: + return null; + } + } + String toJSON() => json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed}); } diff --git a/lib/bitcoin/bitcoin_wallet.dart b/lib/bitcoin/bitcoin_wallet.dart index cc9680c63..5d2b72093 100644 --- a/lib/bitcoin/bitcoin_wallet.dart +++ b/lib/bitcoin/bitcoin_wallet.dart @@ -262,9 +262,8 @@ abstract class BitcoinWalletBase extends WalletBase with Store { final utxs = await unptsFutures; for (final utx in utxs) { - final inAmount = utx.value > totalAmount ? totalAmount : utx.value; - leftAmount = leftAmount - inAmount; - totalInputAmount += inAmount; + leftAmount = leftAmount - utx.value; + totalInputAmount += utx.value; inputs.add(utx); if (leftAmount <= 0) { @@ -348,6 +347,11 @@ abstract class BitcoinWalletBase extends WalletBase with Store { // FIXME: Unimplemented } + @override + void close() { + + } + void _subscribeForUpdates() { scriptHashes.forEach((sh) async { await _scripthashesUpdateSubject[sh]?.close(); diff --git a/lib/bitcoin/electrum.dart b/lib/bitcoin/electrum.dart index f679a62c6..9a51a2c6f 100644 --- a/lib/bitcoin/electrum.dart +++ b/lib/bitcoin/electrum.dart @@ -75,7 +75,7 @@ class ElectrumClient { try { final jsoned = json.decode(utf8.decode(event.toList())) as Map; - print(jsoned); + // print(jsoned); final method = jsoned['method']; final id = jsoned['id'] as String; final result = jsoned['result']; @@ -92,7 +92,9 @@ class ElectrumClient { }, onError: (Object error) { print(error.toString()); _setIsConnected(false); - }, onDone: () => _setIsConnected(false)); + }, onDone: () { + _setIsConnected(false); + }); keepAlive(); } @@ -103,7 +105,7 @@ class ElectrumClient { Future ping() async { try { - // await callWithTimeout(method: 'server.ping'); + await callWithTimeout(method: 'server.ping'); _setIsConnected(true); } on RequestFailedTimeoutException catch (_) { _setIsConnected(false); diff --git a/lib/core/wallet_base.dart b/lib/core/wallet_base.dart index 8eea39dca..d08eff0ef 100644 --- a/lib/core/wallet_base.dart +++ b/lib/core/wallet_base.dart @@ -52,4 +52,6 @@ abstract class WalletBase { Future save(); Future rescan({int height}); + + void close(); } diff --git a/lib/entities/balance.dart b/lib/entities/balance.dart index e8564c5a2..89f3cd725 100644 --- a/lib/entities/balance.dart +++ b/lib/entities/balance.dart @@ -1,3 +1,9 @@ +import 'package:cake_wallet/entities/balance_display_mode.dart'; + abstract class Balance { - const Balance(); + const Balance(this.availableModes); + + final List availableModes; + + String formattedBalance(BalanceDisplayMode mode); } diff --git a/lib/entities/load_current_wallet.dart b/lib/entities/load_current_wallet.dart index ef690521f..88c236088 100644 --- a/lib/entities/load_current_wallet.dart +++ b/lib/entities/load_current_wallet.dart @@ -19,5 +19,5 @@ Future loadCurrentWallet() async { await getIt.get().getWalletPassword(walletName: name); final _service = getIt.get(param1: type); final wallet = await _service.openWallet(name, password); - appStore.wallet = wallet; + appStore.changeCurrentWallet(wallet); } diff --git a/lib/entities/node_list.dart b/lib/entities/node_list.dart index 470b9bc99..118394e6f 100644 --- a/lib/entities/node_list.dart +++ b/lib/entities/node_list.dart @@ -39,9 +39,9 @@ Future> loadElectrumServerList() async { Future resetToDefault(Box nodeSource) async { final moneroNodes = await loadDefaultNodes(); - // final bitcoinElectrumServerList = await loadElectrumServerList(); - // final nodes = moneroNodes + bitcoinElectrumServerList; + final bitcoinElectrumServerList = await loadElectrumServerList(); + final nodes = moneroNodes + bitcoinElectrumServerList; await nodeSource.clear(); - await nodeSource.addAll(moneroNodes); + await nodeSource.addAll(nodes); } diff --git a/lib/main.dart b/lib/main.dart index 9cd55e054..9eefd4196 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -83,7 +83,6 @@ void main() async { ))))); } } - Future initialSetup( {@required SharedPreferences sharedPreferences, @required Box nodes, diff --git a/lib/monero/monero_balance.dart b/lib/monero/monero_balance.dart index c3cca86a7..6183e087d 100644 --- a/lib/monero/monero_balance.dart +++ b/lib/monero/monero_balance.dart @@ -1,20 +1,42 @@ +import 'package:cake_wallet/entities/balance.dart'; +import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:flutter/foundation.dart'; import 'package:cake_wallet/monero/monero_amount_format.dart'; -class MoneroBalance { +class MoneroBalance extends Balance { MoneroBalance({@required this.fullBalance, @required this.unlockedBalance}) : formattedFullBalance = moneroAmountToString(amount: fullBalance), formattedUnlockedBalance = - moneroAmountToString(amount: unlockedBalance); + moneroAmountToString(amount: unlockedBalance), + super(const [ + BalanceDisplayMode.availableBalance, + BalanceDisplayMode.fullBalance + ]); MoneroBalance.fromString( {@required this.formattedFullBalance, - @required this.formattedUnlockedBalance}) + @required this.formattedUnlockedBalance}) : fullBalance = moneroParseAmount(amount: formattedFullBalance), - unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance); + unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance), + super(const [ + BalanceDisplayMode.availableBalance, + BalanceDisplayMode.fullBalance + ]); final int fullBalance; final int unlockedBalance; final String formattedFullBalance; final String formattedUnlockedBalance; -} \ No newline at end of file + + @override + String formattedBalance(BalanceDisplayMode mode) { + switch (mode) { + case BalanceDisplayMode.fullBalance: + return formattedFullBalance; + case BalanceDisplayMode.availableBalance: + return formattedUnlockedBalance; + default: + return null; + } + } +} diff --git a/lib/monero/monero_wallet.dart b/lib/monero/monero_wallet.dart index c7e2cff44..048ca952e 100644 --- a/lib/monero/monero_wallet.dart +++ b/lib/monero/monero_wallet.dart @@ -43,7 +43,7 @@ abstract class MoneroWalletBase extends WalletBase with Store { balance = MoneroBalance( fullBalance: monero_wallet.getFullBalance(accountIndex: account.id), unlockedBalance: - monero_wallet.getUnlockedBalance(accountIndex: account.id)); + monero_wallet.getUnlockedBalance(accountIndex: account.id)); subaddressList.update(accountIndex: account.id); subaddress = subaddressList.subaddresses.first; address = subaddress.address; @@ -120,6 +120,7 @@ abstract class MoneroWalletBase extends WalletBase with Store { } } + @override void close() { _listener?.stop(); _onAccountChangeReaction?.reaction?.dispose(); @@ -315,9 +316,8 @@ abstract class MoneroWalletBase extends WalletBase with Store { } } - Future _askForUpdateTransactionHistory() async { - await transactionHistory.update(); - } + Future _askForUpdateTransactionHistory() async => + await transactionHistory.update(); int _getFullBalance() => monero_wallet.getFullBalance(accountIndex: account.id); @@ -326,13 +326,13 @@ abstract class MoneroWalletBase extends WalletBase with Store { monero_wallet.getUnlockedBalance(accountIndex: account.id); Future _afterSyncSave() async { - if (_isSavingAfterSync) { - return; - } - - _isSavingAfterSync = true; - try { + if (_isSavingAfterSync) { + return; + } + + _isSavingAfterSync = true; + final nowTimestamp = DateTime.now().millisecondsSinceEpoch; final sum = _lastAutosaveTimestamp + _autoAfterSyncSaveInterval; @@ -350,13 +350,13 @@ abstract class MoneroWalletBase extends WalletBase with Store { } Future _afterNewTransactionSave() async { - if (_isSavingAfterNewTransaction) { - return; - } - - _isSavingAfterNewTransaction = true; - try { + if (_isSavingAfterNewTransaction) { + return; + } + + _isSavingAfterNewTransaction = true; + await save(); } catch (e) { print(e.toString()); @@ -366,30 +366,38 @@ abstract class MoneroWalletBase extends WalletBase with Store { } void _onNewBlock(int height, int blocksLeft, double ptc) async { - if (walletInfo.isRecovery) { - await _askForUpdateTransactionHistory(); - _askForUpdateBalance(); - accountList.update(); - } - - if (blocksLeft < 100) { - await _askForUpdateTransactionHistory(); - _askForUpdateBalance(); - accountList.update(); - syncStatus = SyncedSyncStatus(); - await _afterSyncSave(); - + try { if (walletInfo.isRecovery) { - await setAsRecovered(); + await _askForUpdateTransactionHistory(); + _askForUpdateBalance(); + accountList.update(); } - } else { - syncStatus = SyncingSyncStatus(blocksLeft, ptc); + + if (blocksLeft < 100) { + await _askForUpdateTransactionHistory(); + _askForUpdateBalance(); + accountList.update(); + syncStatus = SyncedSyncStatus(); + await _afterSyncSave(); + + if (walletInfo.isRecovery) { + await setAsRecovered(); + } + } else { + syncStatus = SyncingSyncStatus(blocksLeft, ptc); + } + } catch (e) { + print(e.toString()); } } void _onNewTransaction() { - _askForUpdateTransactionHistory(); - _askForUpdateBalance(); - Timer(Duration(seconds: 1), () => _afterNewTransactionSave()); + try { + _askForUpdateTransactionHistory(); + _askForUpdateBalance(); + Timer(Duration(seconds: 1), () => _afterNewTransactionSave()); + } catch (e) { + print(e.toString()); + } } } diff --git a/lib/reactions/fiat_rate_update.dart b/lib/reactions/fiat_rate_update.dart index 7d2f1a097..365423ef4 100644 --- a/lib/reactions/fiat_rate_update.dart +++ b/lib/reactions/fiat_rate_update.dart @@ -12,12 +12,13 @@ Future startFiatRateUpdate(AppStore appStore, SettingsStore settingsStore, return; } - fiatConversionStore.price = await FiatConversionService.fetchPrice( - appStore.wallet.currency, settingsStore.fiatCurrency); + fiatConversionStore.prices[appStore.wallet.currency] = + await FiatConversionService.fetchPrice( + appStore.wallet.currency, settingsStore.fiatCurrency); _timer = Timer.periodic( Duration(seconds: 30), - (_) async => fiatConversionStore.price = + (_) async => fiatConversionStore.prices[appStore.wallet.currency] = await FiatConversionService.fetchPrice( appStore.wallet.currency, settingsStore.fiatCurrency)); } diff --git a/lib/reactions/on_current_fiat_change.dart b/lib/reactions/on_current_fiat_change.dart index 28c6f621c..d7d9c2e82 100644 --- a/lib/reactions/on_current_fiat_change.dart +++ b/lib/reactions/on_current_fiat_change.dart @@ -7,12 +7,13 @@ import 'package:cake_wallet/entities/fiat_currency.dart'; ReactionDisposer _onCurrentFiatCurrencyChangeDisposer; -void startCurrentFiatChangeReaction(AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) { +void startCurrentFiatChangeReaction(AppStore appStore, + SettingsStore settingsStore, FiatConversionStore fiatConversionStore) { _onCurrentFiatCurrencyChangeDisposer?.reaction?.dispose(); _onCurrentFiatCurrencyChangeDisposer = reaction( - (_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async { + (_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async { final cryptoCurrency = appStore.wallet.currency; - fiatConversionStore.price = await FiatConversionService.fetchPrice( - cryptoCurrency, fiatCurrency); + fiatConversionStore.prices[appStore.wallet.currency] = + await FiatConversionService.fetchPrice(cryptoCurrency, fiatCurrency); }); -} \ No newline at end of file +} diff --git a/lib/reactions/on_current_node_change.dart b/lib/reactions/on_current_node_change.dart index c03bbac21..2922e6ec7 100644 --- a/lib/reactions/on_current_node_change.dart +++ b/lib/reactions/on_current_node_change.dart @@ -6,10 +6,9 @@ ReactionDisposer _onCurrentNodeChangeReaction; void startOnCurrentNodeChangeReaction(AppStore appStore) { _onCurrentNodeChangeReaction?.reaction?.dispose(); - _onCurrentNodeChangeReaction = - reaction((_) => appStore.settingsStore.currentNode, (Node node) async { + appStore.settingsStore.nodes.observe((change) async { try { - await appStore.wallet.connectToNode(node: node); + await appStore.wallet.connectToNode(node: change.newValue); } catch (e) { print(e.toString()); } diff --git a/lib/reactions/on_current_wallet_change.dart b/lib/reactions/on_current_wallet_change.dart index 6b9b447b6..117eafd33 100644 --- a/lib/reactions/on_current_wallet_change.dart +++ b/lib/reactions/on_current_wallet_change.dart @@ -12,6 +12,7 @@ import 'package:cake_wallet/core/wallet_base.dart'; import 'package:cake_wallet/entities/wallet_type.dart'; ReactionDisposer _onCurrentWalletChangeReaction; +ReactionDisposer _onCurrentWalletChangeFiatRateUpdateReaction; void startCurrentWalletChangeReaction(AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) { @@ -29,8 +30,16 @@ void startCurrentWalletChangeReaction(AppStore appStore, await getIt.get().setInt( PreferencesKey.currentWalletType, serializeToInt(wallet.type)); await wallet.connectToNode(node: node); + } catch (e) { + print(e.toString()); + } + }); - fiatConversionStore.price = await FiatConversionService.fetchPrice( + _onCurrentWalletChangeFiatRateUpdateReaction = + reaction((_) => appStore.wallet, (WalletBase wallet) async { + try { + fiatConversionStore.prices[wallet.currency] = 0; + fiatConversionStore.prices[wallet.currency] = await FiatConversionService.fetchPrice( wallet.currency, settingsStore.fiatCurrency); } catch (e) { print(e.toString()); diff --git a/lib/src/screens/dashboard/widgets/balance_page.dart b/lib/src/screens/dashboard/widgets/balance_page.dart index 5470c859d..69c4eae0b 100644 --- a/lib/src/screens/dashboard/widgets/balance_page.dart +++ b/lib/src/screens/dashboard/widgets/balance_page.dart @@ -11,58 +11,66 @@ class BalancePage extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.all(24), - child: GestureDetector( - onTapUp: (_) => dashboardViewModel.balanceViewModel.isReversing = false, - onTapDown: (_) => dashboardViewModel.balanceViewModel.isReversing = true, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Observer(builder: (_) { - return Text( - dashboardViewModel.balanceViewModel.currency.toString(), - style: TextStyle( - fontSize: 40, - fontWeight: FontWeight.bold, - color: Theme.of(context).indicatorColor, - height: 1), - ); - }), - Observer(builder: (_) { - return Text( - dashboardViewModel.balanceViewModel.displayMode.toString(), - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Theme.of(context).indicatorColor, - height: 1), - ); - }), - SizedBox(height: 10), - Observer(builder: (_) { - return AutoSizeText(dashboardViewModel.balanceViewModel.cryptoBalance, + padding: EdgeInsets.all(24), + child: GestureDetector( + onTapUp: (_) { + if (dashboardViewModel.balanceViewModel.canReverse) { + dashboardViewModel.balanceViewModel.isReversing = false; + } + }, + onTapDown: (_) { + if (dashboardViewModel.balanceViewModel.canReverse) { + dashboardViewModel.balanceViewModel.isReversing = true; + } + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Observer(builder: (_) { + return Text( + dashboardViewModel.balanceViewModel.currency.toString(), style: TextStyle( - fontSize: 54, + fontSize: 40, fontWeight: FontWeight.bold, - color: Colors.white, - height: 1), - maxLines: 1, - textAlign: TextAlign.center); - }), - SizedBox(height: 10), - Observer(builder: (_) { - return Text(dashboardViewModel.balanceViewModel.fiatBalance, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, color: Theme.of(context).indicatorColor, height: 1), - textAlign: TextAlign.center); - }), - ], - ), - ) - ); + ); + }), + Observer(builder: (_) { + return Text( + dashboardViewModel.balanceViewModel.displayMode.toString(), + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Theme.of(context).indicatorColor, + height: 1), + ); + }), + SizedBox(height: 10), + Observer(builder: (_) { + return AutoSizeText( + dashboardViewModel.balanceViewModel.cryptoBalance, + style: TextStyle( + fontSize: 54, + fontWeight: FontWeight.bold, + color: Colors.white, + height: 1), + maxLines: 1, + textAlign: TextAlign.center); + }), + SizedBox(height: 10), + Observer(builder: (_) { + return Text(dashboardViewModel.balanceViewModel.fiatBalance, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500, + color: Theme.of(context).indicatorColor, + height: 1), + textAlign: TextAlign.center); + }), + ], + ), + )); } } diff --git a/lib/src/screens/dashboard/widgets/transactions_page.dart b/lib/src/screens/dashboard/widgets/transactions_page.dart index 15b2eedaa..c8dd2bfa1 100644 --- a/lib/src/screens/dashboard/widgets/transactions_page.dart +++ b/lib/src/screens/dashboard/widgets/transactions_page.dart @@ -46,7 +46,8 @@ class TransactionsPage extends StatelessWidget { if (item is TransactionListItem) { final transaction = item.transaction; - return TransactionRow( + return Observer( + builder: (_) => TransactionRow( onTap: () => Navigator.of(context).pushNamed( Routes.transactionDetails, arguments: transaction), @@ -55,7 +56,7 @@ class TransactionsPage extends StatelessWidget { .format(transaction.date), formattedAmount: item.formattedCryptoAmount, formattedFiatAmount: item.formattedFiatAmount, - isPending: transaction.isPending); + isPending: transaction.isPending)); } if (item is TradeListItem) { diff --git a/lib/src/screens/nodes/nodes_list_page.dart b/lib/src/screens/nodes/nodes_list_page.dart index 80697afad..87753e1ce 100644 --- a/lib/src/screens/nodes/nodes_list_page.dart +++ b/lib/src/screens/nodes/nodes_list_page.dart @@ -65,98 +65,90 @@ class NodeListPage extends BasePage { padding: EdgeInsets.only(top: 10), child: Observer( builder: (BuildContext context) { - return nodeListViewModel.nodes.isNotEmpty - ? SectionStandardList( - sectionCount: 2, - context: context, - itemCounter: (int sectionIndex) { - if (sectionIndex == 0) { - return 1; - } + return SectionStandardList( + sectionCount: 2, + context: context, + itemCounter: (int sectionIndex) { + if (sectionIndex == 0) { + return 1; + } - return nodeListViewModel.nodes.length; - }, - itemBuilder: (_, sectionIndex, index) { - if (sectionIndex == 0) { - return NodeHeaderListRow( - title: S.of(context).add_new_node, - onTap: (_) async => await Navigator.of(context) - .pushNamed(Routes.newNode)); - } + return nodeListViewModel.nodes.length; + }, + itemBuilder: (_, sectionIndex, index) { + if (sectionIndex == 0) { + return NodeHeaderListRow( + title: S.of(context).add_new_node, + onTap: (_) async => await Navigator.of(context) + .pushNamed(Routes.newNode)); + } - final node = nodeListViewModel.nodes[index]; - final isSelected = node.keyIndex == - nodeListViewModel.settingsStore.currentNode.keyIndex; - final nodeListRow = NodeListRow( - title: node.uri, - isSelected: isSelected, - isAlive: node.requestNode(), - onTap: (_) async { - if (isSelected) { - return; + final node = nodeListViewModel.nodes[index]; + final isSelected = + node.keyIndex == nodeListViewModel.currentNode?.keyIndex; + final nodeListRow = NodeListRow( + title: node.uri, + isSelected: isSelected, + isAlive: node.requestNode(), + onTap: (_) async { + if (isSelected) { + return; + } + + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: + S.of(context).change_current_node_title, + alertContent: + S.of(context).change_current_node(node.uri), + leftButtonText: S.of(context).cancel, + rightButtonText: S.of(context).change, + actionLeftButton: () => + Navigator.of(context).pop(), + actionRightButton: () async { + await nodeListViewModel.setAsCurrent(node); + Navigator.of(context).pop(); + }); + }); + }); + + final dismissibleRow = Slidable( + key: Key('${node.keyIndex}'), + actionPane: SlidableDrawerActionPane(), + child: nodeListRow, + secondaryActions: [ + IconSlideAction( + caption: S.of(context).delete, + color: Colors.red, + icon: CupertinoIcons.delete, + onTap: () async { + final confirmed = await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).remove_node, + alertContent: + S.of(context).remove_node_message, + rightButtonText: S.of(context).remove, + leftButtonText: S.of(context).cancel, + actionRightButton: () => + Navigator.pop(context, true), + actionLeftButton: () => + Navigator.pop(context, false)); + }) ?? + false; + + if (confirmed) { + await nodeListViewModel.delete(node); } + }, + ), + ]); - await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context) - .change_current_node_title, - alertContent: S - .of(context) - .change_current_node(node.uri), - leftButtonText: S.of(context).cancel, - rightButtonText: S.of(context).change, - actionLeftButton: () => - Navigator.of(context).pop(), - actionRightButton: () async { - await nodeListViewModel - .setAsCurrent(node); - Navigator.of(context).pop(); - }); - }); - }); - - final dismissibleRow = Slidable( - key: Key('${node.keyIndex}'), - actionPane: SlidableDrawerActionPane(), - child: nodeListRow, - secondaryActions: [ - IconSlideAction( - caption: S.of(context).delete, - color: Colors.red, - icon: CupertinoIcons.delete, - onTap: () async { - final confirmed = await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: - S.of(context).remove_node, - alertContent: S - .of(context) - .remove_node_message, - rightButtonText: - S.of(context).remove, - leftButtonText: - S.of(context).cancel, - actionRightButton: () => - Navigator.pop(context, true), - actionLeftButton: () => - Navigator.pop(context, false)); - }) ?? - false; - - if (confirmed) { - await nodeListViewModel.delete(node); - } - }, - ), - ]); - - return isSelected ? nodeListRow : dismissibleRow; - }) - : Container(); + return isSelected ? nodeListRow : dismissibleRow; + }); }, ), ); diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 6074319e7..8c18d84a1 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -204,7 +204,7 @@ class AddressTextField extends StatelessWidget { onURIScanned(uri); } } catch (e) { - print('Error $e'); + print(e.toString()); } } diff --git a/lib/store/app_store.dart b/lib/store/app_store.dart index 7421fa54e..6c95ebafe 100644 --- a/lib/store/app_store.dart +++ b/lib/store/app_store.dart @@ -26,4 +26,10 @@ abstract class AppStoreBase with Store { SettingsStore settingsStore; NodeListStore nodeListStore; + + @action + void changeCurrentWallet(WalletBase wallet) { + this.wallet?.close(); + this.wallet = wallet; + } } diff --git a/lib/store/dashboard/fiat_conversion_store.dart b/lib/store/dashboard/fiat_conversion_store.dart index 48aed82b7..386ad6455 100644 --- a/lib/store/dashboard/fiat_conversion_store.dart +++ b/lib/store/dashboard/fiat_conversion_store.dart @@ -1,13 +1,13 @@ +import 'package:cake_wallet/entities/crypto_currency.dart'; import 'package:mobx/mobx.dart'; part 'fiat_conversion_store.g.dart'; -class FiatConversionStore = FiatConversionStoreBase - with _$FiatConversionStore; +class FiatConversionStore = FiatConversionStoreBase with _$FiatConversionStore; abstract class FiatConversionStoreBase with Store { - FiatConversionStoreBase() : price = 0.0; + FiatConversionStoreBase() : prices = ObservableMap(); @observable - double price; + ObservableMap prices; } diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index b4b76bb8d..e236f4b1b 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -43,7 +43,6 @@ abstract class SettingsStoreBase with Store { isDarkTheme = initialDarkTheme; pinCodeLength = initialPinLength; languageCode = initialLanguageCode; - currentNode = nodes[WalletType.monero]; this.nodes = ObservableMap.of(nodes); _sharedPreferences = sharedPreferences; @@ -80,13 +79,14 @@ abstract class SettingsStoreBase with Store { (int pinLength) => sharedPreferences.setInt( PreferencesKey.currentPinLength, pinLength)); - reaction((_) => currentNode, - (Node node) => _saveCurrentNode(node, WalletType.monero)); - reaction( (_) => languageCode, (String languageCode) => sharedPreferences.setString( PreferencesKey.currentLanguageCode, languageCode)); + + this + .nodes + .observe((change) => _saveCurrentNode(change.newValue, change.key)); } static const defaultPinLength = 4; @@ -116,9 +116,6 @@ abstract class SettingsStoreBase with Store { @observable int pinCodeLength; - @observable - Node currentNode; - @computed ThemeData get theme => isDarkTheme ? Themes.darkTheme : Themes.lightTheme; diff --git a/lib/utils/mobx.dart b/lib/utils/mobx.dart index 7ae97d56f..a5bfb2220 100644 --- a/lib/utils/mobx.dart +++ b/lib/utils/mobx.dart @@ -57,7 +57,8 @@ extension MobxBindable on Box { Filter filter, }) { if (initialFire) { - dest.addAll(values); + final res = filter != null ? values.where(filter) : values; + dest.addAll(res); } return watch().listen((event) { diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart index 37f6e5247..7e3efa073 100644 --- a/lib/view_model/dashboard/balance_view_model.dart +++ b/lib/view_model/dashboard/balance_view_model.dart @@ -15,31 +15,34 @@ part 'balance_view_model.g.dart'; class BalanceViewModel = BalanceViewModelBase with _$BalanceViewModel; abstract class BalanceViewModelBase with Store { - BalanceViewModelBase({ - @required this.appStore, - @required this.settingsStore, - @required this.fiatConvertationStore - }) : isReversing = false; + BalanceViewModelBase( + {@required this.appStore, + @required this.settingsStore, + @required this.fiatConvertationStore}) + : isReversing = false; final AppStore appStore; final SettingsStore settingsStore; final FiatConversionStore fiatConvertationStore; + bool get canReverse => + (appStore.wallet.balance.availableModes as List).length > 1; + @observable bool isReversing; + @computed + double get price => fiatConvertationStore.prices[appStore.wallet.currency]; + @computed BalanceDisplayMode get savedDisplayMode => settingsStore.balanceDisplayMode; @computed BalanceDisplayMode get displayMode => isReversing - ? (savedDisplayMode == BalanceDisplayMode.availableBalance - ? BalanceDisplayMode.fullBalance - : BalanceDisplayMode.availableBalance) - : savedDisplayMode; - - @computed - double get price => fiatConvertationStore.price; + ? (savedDisplayMode == BalanceDisplayMode.availableBalance + ? BalanceDisplayMode.fullBalance + : BalanceDisplayMode.availableBalance) + : savedDisplayMode; @computed String get cryptoBalance { @@ -63,15 +66,11 @@ abstract class BalanceViewModelBase with Store { final fiatCurrency = settingsStore.fiatCurrency; var balance = '---'; - final totalBalance = _getFiatBalance( - price: price, - cryptoAmount: walletBalance.totalBalance - ); + final totalBalance = + _getFiatBalance(price: price, cryptoAmount: walletBalance.totalBalance); final unlockedBalance = _getFiatBalance( - price: price, - cryptoAmount: walletBalance.unlockedBalance - ); + price: price, cryptoAmount: walletBalance.unlockedBalance); if (displayMode == BalanceDisplayMode.availableBalance) { balance = fiatCurrency.toString() + ' ' + unlockedBalance ?? '0.00'; @@ -89,7 +88,7 @@ abstract class BalanceViewModelBase with Store { final _wallet = appStore.wallet; if (_wallet is MoneroWallet) { - return WalletBalance( + return WalletBalance( unlockedBalance: _wallet.balance.formattedUnlockedBalance, totalBalance: _wallet.balance.formattedFullBalance); } @@ -113,4 +112,4 @@ abstract class BalanceViewModelBase with Store { return calculateFiatAmount(price: price, cryptoAmount: cryptoAmount); } -} \ No newline at end of file +} diff --git a/lib/view_model/node_list/node_list_view_model.dart b/lib/view_model/node_list/node_list_view_model.dart index 3bb1d09ba..9cf800705 100644 --- a/lib/view_model/node_list/node_list_view_model.dart +++ b/lib/view_model/node_list/node_list_view_model.dart @@ -13,16 +13,18 @@ part 'node_list_view_model.g.dart'; class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel; abstract class NodeListViewModelBase with Store { - NodeListViewModelBase(this._nodeSource, this._wallet, this.settingsStore) + NodeListViewModelBase(this._nodeSource, this.wallet, this.settingsStore) : nodes = ObservableList() { _nodeSource.bindToList(nodes, - filter: (Node val) => val?.type == _wallet.type, initialFire: true); + filter: (Node val) => val?.type == wallet.type, initialFire: true); } + @computed + Node get currentNode => settingsStore.nodes[wallet.type]; + final ObservableList nodes; final SettingsStore settingsStore; - - final WalletBase _wallet; + final WalletBase wallet; final Box _nodeSource; Future reset() async { @@ -30,14 +32,12 @@ abstract class NodeListViewModelBase with Store { Node node; - switch (_wallet.type) { + switch (wallet.type) { case WalletType.bitcoin: node = getBitcoinDefaultElectrumServer(nodes: _nodeSource); break; case WalletType.monero: - node = getMoneroDefaultNode( - nodes: _nodeSource, - ); + node = getMoneroDefaultNode(nodes: _nodeSource); break; default: break; @@ -50,5 +50,5 @@ abstract class NodeListViewModelBase with Store { Future delete(Node node) async => node.delete(); Future setAsCurrent(Node node) async => - settingsStore.currentNode = node; + settingsStore.nodes[wallet.type] = node; } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index cd49c97d0..f3d46ccb3 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/entities/balance_display_mode.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:hive/hive.dart'; import 'package:intl/intl.dart'; @@ -77,19 +78,9 @@ abstract class SendViewModelBase with Store { PendingTransaction pendingTransaction; @computed - String get balance { - String balance = '0.0'; - - if (_wallet is MoneroWallet) { - balance = _wallet.balance.formattedUnlockedBalance as String ?? ''; - } - - if (_wallet is BitcoinWallet) { - balance = _wallet.balance.confirmedFormatted as String ?? ''; - } - - return balance; - } + String get balance => + _wallet.balance.formattedBalance(BalanceDisplayMode.availableBalance) + as String ?? '0.0'; @computed bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus; @@ -176,7 +167,7 @@ abstract class SendViewModelBase with Store { void _updateFiatAmount() { try { final fiat = calculateFiatAmount( - price: _fiatConversationStore.price, + price: _fiatConversationStore.prices[_wallet.currency], cryptoAmount: cryptoAmount.replaceAll(',', '.')); if (fiatAmount != fiat) { fiatAmount = fiat; @@ -190,7 +181,7 @@ abstract class SendViewModelBase with Store { void _updateCryptoAmount() { try { final crypto = double.parse(fiatAmount.replaceAll(',', '.')) / - _fiatConversationStore.price; + _fiatConversationStore.prices[_wallet.currency]; final cryptoAmountTmp = _cryptoNumberFormat.format(crypto); if (cryptoAmount != cryptoAmountTmp) { diff --git a/lib/view_model/settings/settings_view_model.dart b/lib/view_model/settings/settings_view_model.dart index 9db01d3f2..f4f479cd1 100644 --- a/lib/view_model/settings/settings_view_model.dart +++ b/lib/view_model/settings/settings_view_model.dart @@ -35,12 +35,13 @@ abstract class SettingsViewModelBase with Store { (PackageInfo packageInfo) => currentVersion = packageInfo.version); sections = [ [ - PickerListItem( - title: S.current.settings_display_balance_as, - items: BalanceDisplayMode.all, - selectedItem: () => balanceDisplayMode, - onItemSelected: (BalanceDisplayMode mode) => - _settingsStore.balanceDisplayMode = mode), + if ((wallet.balance.availableModes as List).length > 1) + PickerListItem( + title: S.current.settings_display_balance_as, + items: BalanceDisplayMode.all, + selectedItem: () => balanceDisplayMode, + onItemSelected: (BalanceDisplayMode mode) => + _settingsStore.balanceDisplayMode = mode), PickerListItem( title: S.current.settings_currency, items: FiatCurrency.all, diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index 3509f8c07..b236fe151 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -51,7 +51,7 @@ abstract class WalletCreationVMBase with Store { credentials.walletInfo = walletInfo; final wallet = await process(credentials); await _walletInfoSource.add(walletInfo); - _appStore.wallet = wallet; + _appStore.changeCurrentWallet(wallet); _appStore.authenticationStore.allowed(); state = ExecutedSuccessfullyState(); } catch (e) { diff --git a/lib/view_model/wallet_list/wallet_list_view_model.dart b/lib/view_model/wallet_list/wallet_list_view_model.dart index cf9e61088..f5860d628 100644 --- a/lib/view_model/wallet_list/wallet_list_view_model.dart +++ b/lib/view_model/wallet_list/wallet_list_view_model.dart @@ -32,7 +32,8 @@ abstract class WalletListViewModelBase with Store { final password = await _keyService.getWalletPassword(walletName: wallet.name); final walletService = getIt.get(param1: wallet.type); - _appStore.wallet = await walletService.openWallet(wallet.name, password); + final loadedWallet = await walletService.openWallet(wallet.name, password); + _appStore.changeCurrentWallet(loadedWallet); _updateList(); }