diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index 0260dc6b4..3e399266a 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -1,14 +1,15 @@ -import 'dart:math'; +import 'dart:developer' as dev; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/core/wallet_change_listener_view_model.dart'; import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/monero/monero.dart'; -import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/solana/solana.dart'; import 'package:cake_wallet/store/app_store.dart'; @@ -24,16 +25,14 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i import 'package:cake_wallet/wownero/wownero.dart'; import 'package:cw_core/amount_converter.dart'; import 'package:cw_core/currency.dart'; -import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; -import 'package:cw_monero/api/wallet.dart'; -import 'package:flutter/foundation.dart'; import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; part 'wallet_address_list_view_model.g.dart'; -class WalletAddressListViewModel = WalletAddressListViewModelBase with _$WalletAddressListViewModel; +class WalletAddressListViewModel = WalletAddressListViewModelBase + with _$WalletAddressListViewModel; abstract class PaymentURI { PaymentURI({required this.amount, required this.address}); @@ -43,12 +42,11 @@ abstract class PaymentURI { } class MoneroURI extends PaymentURI { - MoneroURI({required String amount, required String address}) - : super(amount: amount, address: address); + MoneroURI({required super.amount, required super.address}); @override String toString() { - var base = 'monero:' + address; + var base = 'monero:$address'; if (amount.isNotEmpty) { base += '?tx_amount=${amount.replaceAll(',', '.')}'; @@ -59,12 +57,11 @@ class MoneroURI extends PaymentURI { } class HavenURI extends PaymentURI { - HavenURI({required String amount, required String address}) - : super(amount: amount, address: address); + HavenURI({required super.amount, required super.address}); @override String toString() { - var base = 'haven:' + address; + var base = 'haven:$address'; if (amount.isNotEmpty) { base += '?tx_amount=${amount.replaceAll(',', '.')}'; @@ -75,12 +72,11 @@ class HavenURI extends PaymentURI { } class BitcoinURI extends PaymentURI { - BitcoinURI({required String amount, required String address}) - : super(amount: amount, address: address); + BitcoinURI({required super.amount, required super.address}); @override String toString() { - var base = 'bitcoin:' + address; + var base = 'bitcoin:$address'; if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; @@ -91,12 +87,11 @@ class BitcoinURI extends PaymentURI { } class LitecoinURI extends PaymentURI { - LitecoinURI({required String amount, required String address}) - : super(amount: amount, address: address); + LitecoinURI({required super.amount, required super.address}); @override String toString() { - var base = 'litecoin:' + address; + var base = 'litecoin:$address'; if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; @@ -107,12 +102,11 @@ class LitecoinURI extends PaymentURI { } class EthereumURI extends PaymentURI { - EthereumURI({required String amount, required String address}) - : super(amount: amount, address: address); + EthereumURI({required super.amount, required super.address}); @override String toString() { - var base = 'ethereum:' + address; + var base = 'ethereum:$address'; if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; @@ -123,8 +117,7 @@ class EthereumURI extends PaymentURI { } class BitcoinCashURI extends PaymentURI { - BitcoinCashURI({required String amount, required String address}) - : super(amount: amount, address: address); + BitcoinCashURI({required super.amount, required super.address}); @override String toString() { @@ -139,12 +132,11 @@ class BitcoinCashURI extends PaymentURI { } class NanoURI extends PaymentURI { - NanoURI({required String amount, required String address}) - : super(amount: amount, address: address); + NanoURI({required super.amount, required super.address}); @override String toString() { - var base = 'nano:' + address; + var base = 'nano:$address'; if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; } @@ -154,12 +146,11 @@ class NanoURI extends PaymentURI { } class PolygonURI extends PaymentURI { - PolygonURI({required String amount, required String address}) - : super(amount: amount, address: address); + PolygonURI({required super.amount, required super.address}); @override String toString() { - var base = 'polygon:' + address; + var base = 'polygon:$address'; if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; @@ -170,12 +161,12 @@ class PolygonURI extends PaymentURI { } class SolanaURI extends PaymentURI { - SolanaURI({required String amount, required String address}) - : super(amount: amount, address: address); + SolanaURI({required super.amount, required super.address}); @override String toString() { - var base = 'solana:' + address; + var base = 'solana:$address'; + if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; } @@ -185,12 +176,12 @@ class SolanaURI extends PaymentURI { } class TronURI extends PaymentURI { - TronURI({required String amount, required String address}) - : super(amount: amount, address: address); + TronURI({required super.amount, required super.address}); @override String toString() { - var base = 'tron:' + address; + var base = 'tron:$address'; + if (amount.isNotEmpty) { base += '?amount=${amount.replaceAll(',', '.')}'; } @@ -200,12 +191,11 @@ class TronURI extends PaymentURI { } class WowneroURI extends PaymentURI { - WowneroURI({required String amount, required String address}) - : super(amount: amount, address: address); + WowneroURI({required super.amount, required super.address}); @override String toString() { - var base = 'wownero:' + address; + var base = 'wownero:$address'; if (amount.isNotEmpty) { base += '?tx_amount=${amount.replaceAll(',', '.')}'; @@ -215,7 +205,8 @@ class WowneroURI extends PaymentURI { } } -abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store { +abstract class WalletAddressListViewModelBase + extends WalletChangeListenerViewModel with Store { WalletAddressListViewModelBase({ required AppStore appStore, required this.yatStore, @@ -223,9 +214,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo }) : _baseItems = [], selectedCurrency = walletTypeToCryptoCurrency(appStore.wallet!.type), _cryptoNumberFormat = NumberFormat(_cryptoNumberPattern), - hasAccounts = appStore.wallet!.type == WalletType.monero || - appStore.wallet!.type == WalletType.wownero || - appStore.wallet!.type == WalletType.haven, + hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven] + .contains(appStore.wallet!.type), amount = '', _settingsStore = appStore.settingsStore, super(appStore: appStore) { @@ -237,9 +227,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo _init(); selectedCurrency = walletTypeToCryptoCurrency(wallet.type); - hasAccounts = wallet.type == WalletType.monero || - wallet.type == WalletType.wownero || - wallet.type == WalletType.haven; + hasAccounts = [WalletType.monero, WalletType.wownero, WalletType.haven] + .contains(wallet.type); } static const String _cryptoNumberPattern = '0.00000000'; @@ -249,7 +238,11 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo final FiatConversionStore fiatConversionStore; final SettingsStore _settingsStore; - List get currencies => [walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all]; + double? _fiatRate; + String _rawAmount = ''; + + List get currencies => + [walletTypeToCryptoCurrency(wallet.type), ...FiatCurrency.all]; String get buttonTitle { if (isElectrumWallet) { @@ -275,9 +268,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo WalletType get type => wallet.type; @computed - WalletAddressListItem get address { - return WalletAddressListItem(address: wallet.walletAddresses.address, isPrimary: false); - } + WalletAddressListItem get address => WalletAddressListItem( + address: wallet.walletAddresses.address, isPrimary: false); @computed PaymentURI get uri { @@ -321,8 +313,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo final addressList = ObservableList(); if (wallet.type == WalletType.monero) { - final primaryAddress = monero!.getSubaddressList(wallet).subaddresses.first; - final addressItems = monero!.getSubaddressList(wallet).subaddresses.map((subaddress) { + final primaryAddress = + monero!.getSubaddressList(wallet).subaddresses.first; + final addressItems = + monero!.getSubaddressList(wallet).subaddresses.map((subaddress) { final isPrimary = subaddress == primaryAddress; return WalletAddressListItem( @@ -338,8 +332,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo } if (wallet.type == WalletType.wownero) { - final primaryAddress = wownero!.getSubaddressList(wallet).subaddresses.first; - final addressItems = wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) { + final primaryAddress = + wownero!.getSubaddressList(wallet).subaddresses.first; + final addressItems = + wownero!.getSubaddressList(wallet).subaddresses.map((subaddress) { final isPrimary = subaddress == primaryAddress; return WalletAddressListItem( @@ -352,8 +348,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo } if (wallet.type == WalletType.haven) { - final primaryAddress = haven!.getSubaddressList(wallet).subaddresses.first; - final addressItems = haven!.getSubaddressList(wallet).subaddresses.map((subaddress) { + final primaryAddress = + haven!.getSubaddressList(wallet).subaddresses.first; + final addressItems = + haven!.getSubaddressList(wallet).subaddresses.map((subaddress) { final isPrimary = subaddress == primaryAddress; return WalletAddressListItem( @@ -367,7 +365,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo if (isElectrumWallet) { if (bitcoin!.hasSelectedSilentPayments(wallet)) { - final addressItems = bitcoin!.getSilentPaymentAddresses(wallet).map((address) { + final addressItems = + bitcoin!.getSilentPaymentAddresses(wallet).map((address) { final isPrimary = address.id == 0; return WalletAddressListItem( @@ -418,7 +417,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo if (wallet.type == WalletType.litecoin && addressItems.length >= 1000) { // find the index of the last item with a txCount > 0 final addressItemsList = addressItems.toList(); - int index = addressItemsList.lastIndexWhere((item) => (item.txCount ?? 0) > 0); + int index = addressItemsList + .lastIndexWhere((item) => (item.txCount ?? 0) > 0); if (index == -1) { index = 0; } @@ -432,19 +432,22 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo if (wallet.type == WalletType.ethereum) { final primaryAddress = ethereum!.getAddress(wallet); - addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress)); + addressList.add(WalletAddressListItem( + isPrimary: true, name: null, address: primaryAddress)); } if (wallet.type == WalletType.polygon) { final primaryAddress = polygon!.getAddress(wallet); - addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress)); + addressList.add(WalletAddressListItem( + isPrimary: true, name: null, address: primaryAddress)); } if (wallet.type == WalletType.solana) { final primaryAddress = solana!.getAddress(wallet); - addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress)); + addressList.add(WalletAddressListItem( + isPrimary: true, name: null, address: primaryAddress)); } if (wallet.type == WalletType.nano) { @@ -458,18 +461,21 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo if (wallet.type == WalletType.tron) { final primaryAddress = tron!.getAddress(wallet); - addressList.add(WalletAddressListItem(isPrimary: true, name: null, address: primaryAddress)); + addressList.add(WalletAddressListItem( + isPrimary: true, name: null, address: primaryAddress)); } for (var i = 0; i < addressList.length; i++) { if (!(addressList[i] is WalletAddressListItem)) continue; - (addressList[i] as WalletAddressListItem).isHidden = wallet.walletAddresses.hiddenAddresses + (addressList[i] as WalletAddressListItem).isHidden = wallet + .walletAddresses.hiddenAddresses .contains((addressList[i] as WalletAddressListItem).address); } for (var i = 0; i < addressList.length; i++) { if (!(addressList[i] is WalletAddressListItem)) continue; - (addressList[i] as WalletAddressListItem).isManual = wallet.walletAddresses.manualAddresses + (addressList[i] as WalletAddressListItem).isManual = wallet + .walletAddresses.manualAddresses .contains((addressList[i] as WalletAddressListItem).address); } @@ -487,7 +493,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo Future toggleHideAddress(WalletAddressListItem item) async { if (item.isHidden) { - wallet.walletAddresses.hiddenAddresses.removeWhere((element) => element == item.address); + wallet.walletAddresses.hiddenAddresses + .removeWhere((element) => element == item.address); } else { wallet.walletAddresses.hiddenAddresses.add(item.address); } @@ -512,57 +519,58 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo @computed String get accountLabel { - if (wallet.type == WalletType.monero) { - return monero!.getCurrentAccount(wallet).label; + switch (wallet.type) { + case WalletType.monero: + return monero!.getCurrentAccount(wallet).label; + case WalletType.wownero: + wownero!.getCurrentAccount(wallet).label; + case WalletType.haven: + return haven!.getCurrentAccount(wallet).label; + default: + return ''; } - - if (wallet.type == WalletType.wownero) { - return wownero!.getCurrentAccount(wallet).label; - } - - if (wallet.type == WalletType.haven) { - return haven!.getCurrentAccount(wallet).label; - } - return ''; } @computed - bool get hasAddressList => - wallet.type == WalletType.monero || - wallet.type == WalletType.wownero || - wallet.type == WalletType.haven || - wallet.type == WalletType.bitcoinCash || - wallet.type == WalletType.bitcoin || - wallet.type == WalletType.litecoin; + bool get hasAddressList => [ + WalletType.monero, + WalletType.wownero, + WalletType.haven, + WalletType.bitcoinCash, + WalletType.bitcoin, + WalletType.litecoin + ].contains(wallet.type); @computed - bool get isElectrumWallet => - wallet.type == WalletType.bitcoin || - wallet.type == WalletType.litecoin || - wallet.type == WalletType.bitcoinCash; + bool get isElectrumWallet => [ + WalletType.bitcoin, + WalletType.litecoin, + WalletType.bitcoinCash + ].contains(wallet.type); @computed bool get isBalanceAvailable => isElectrumWallet; @computed bool get isReceivedAvailable => - wallet.type == WalletType.monero || wallet.type == WalletType.wownero; + [WalletType.monero, WalletType.wownero].contains(wallet.type); @computed bool get isSilentPayments => - wallet.type == WalletType.bitcoin && bitcoin!.hasSelectedSilentPayments(wallet); + wallet.type == WalletType.bitcoin && + bitcoin!.hasSelectedSilentPayments(wallet); @computed bool get isAutoGenerateSubaddressEnabled => - _settingsStore.autoGenerateSubaddressStatus != AutoGenerateSubaddressStatus.disabled && + _settingsStore.autoGenerateSubaddressStatus != + AutoGenerateSubaddressStatus.disabled && !isSilentPayments; @computed bool get showAddManualAddresses => !isAutoGenerateSubaddressEnabled || - wallet.type == WalletType.monero || - wallet.type == WalletType.wownero; + [WalletType.monero, WalletType.wownero].contains(wallet.type); List _baseItems; @@ -574,7 +582,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo @action Future setAddressType(dynamic option) async { - if (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) { + if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type)) { await bitcoin!.setAddressType(wallet, option); } } @@ -586,13 +594,15 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo _baseItems.add(WalletAddressHiddenListHeader()); } - if (wallet.type == WalletType.monero || - wallet.type == WalletType.wownero || - wallet.type == WalletType.haven) { + if ([ + WalletType.monero, + WalletType.wownero, + WalletType.haven, + ].contains(wallet.type)) { _baseItems.add(WalletAccountListHeader()); } - if (wallet.type != WalletType.nano && wallet.type != WalletType.banano) { + if (![WalletType.nano, WalletType.banano].contains(wallet.type)) { _baseItems.add(WalletAddressListHeader()); } if (wallet.isEnabledAutoGenerateSubaddress) { @@ -603,11 +613,27 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo @action void selectCurrency(Currency currency) { selectedCurrency = currency; + + if (currency is FiatCurrency && _settingsStore.fiatCurrency != currency) { + final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type); + + dev.log("Requesting Fiat rate for $cryptoCurrency-$currency"); + FiatConversionService.fetchPrice( + crypto: cryptoCurrency, + fiat: currency, + torOnly: _settingsStore.fiatApiMode == FiatApiMode.torOnly, + ).then((value) { + dev.log("Received Fiat rate 1 $cryptoCurrency = $value $currency"); + _fiatRate = value; + _convertAmountToCrypto(); + }); + } } @action void changeAmount(String amount) { this.amount = amount; + this._rawAmount = amount; if (selectedCurrency is FiatCurrency) { _convertAmountToCrypto(); } @@ -618,11 +644,20 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo searchText = text; } + @action void _convertAmountToCrypto() { final cryptoCurrency = walletTypeToCryptoCurrency(wallet.type); + final fiatRate = + _fiatRate ?? (fiatConversionStore.prices[cryptoCurrency] ?? 0.0); + + if (fiatRate <= 0.0) { + dev.log("Invalid Fiat Rate $fiatRate"); + amount = ''; + return; + } + try { - final crypto = - double.parse(amount.replaceAll(',', '.')) / fiatConversionStore.prices[cryptoCurrency]!; + final crypto = double.parse(_rawAmount.replaceAll(',', '.')) / fiatRate; final cryptoAmountTmp = _cryptoNumberFormat.format(crypto); if (amount != cryptoAmountTmp) { amount = cryptoAmountTmp;