diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index f224efde6..630ecf27f 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -51,6 +51,10 @@ class CWBitcoin extends Bitcoin { TransactionPriority deserializeBitcoinTransactionPriority(int raw) => BitcoinTransactionPriority.deserialize(raw: raw); + @override + TransactionPriority deserializeLitecoinTransactionPriority(int raw) + => LitecoinTransactionPriority.deserialize(raw: raw); + @override int getFeeRate(Object wallet, TransactionPriority priority) { final bitcoinWallet = wallet as ElectrumWallet; diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index 999b67120..46868cf1a 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -214,6 +214,7 @@ class BackupService { final currentBitcoinElectrumSererId = data[PreferencesKey.currentBitcoinElectrumSererIdKey] as int?; final currentLanguageCode = data[PreferencesKey.currentLanguageCode] as String?; final displayActionListMode = data[PreferencesKey.displayActionListModeKey] as int?; + final fiatApiMode = data[PreferencesKey.currentFiatApiModeKey] as int?; final currentPinLength = data[PreferencesKey.currentPinLength] as int?; final currentTheme = data[PreferencesKey.currentTheme] as int?; final currentDefaultSettingsMigrationVersion = data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int?; @@ -266,6 +267,10 @@ class BackupService { await _sharedPreferences.setInt(PreferencesKey.displayActionListModeKey, displayActionListMode); + if (fiatApiMode != null) + await _sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, + fiatApiMode); + if (currentPinLength != null) await _sharedPreferences.setInt(PreferencesKey.currentPinLength, currentPinLength); @@ -427,6 +432,8 @@ class BackupService { _sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority), PreferencesKey.moneroTransactionPriority: _sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority), + PreferencesKey.currentFiatApiModeKey: + _sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey), }; return json.encode(preferences); diff --git a/lib/di.dart b/lib/di.dart index bf926cbda..b506700f3 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -35,6 +35,7 @@ import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cake_wallet/core/backup_service.dart'; import 'package:cw_core/wallet_service.dart'; @@ -159,6 +160,7 @@ import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart'; +import 'package:cw_core/crypto_currency.dart'; final getIt = GetIt.instance; @@ -349,7 +351,7 @@ Future setup( onAuthenticationFinished: onAuthFinished, closable: closable ?? false)); - getIt.registerFactory(() => + getIt.registerFactory(() => BalancePage(dashboardViewModel: getIt.get(), settingsStore: getIt.get())); getIt.registerFactory(() => DashboardPage( balancePage: getIt.get(), walletViewModel: getIt.get(), addressListViewModel: getIt.get())); @@ -471,12 +473,11 @@ Future setup( (ContactRecord? contact, _) => ContactViewModel(_contactSource, contact: contact)); - getIt.registerFactory( - () => ContactListViewModel(_contactSource, _walletInfoSource)); + getIt.registerFactoryParam( + (CryptoCurrency? cur, _) => ContactListViewModel(_contactSource, _walletInfoSource, cur)); - getIt.registerFactoryParam( - (bool isEditable, _) => ContactListPage(getIt.get(), - isEditable: isEditable)); + getIt.registerFactoryParam((CryptoCurrency? cur, _) + => ContactListPage(getIt.get(param1: cur))); getIt.registerFactoryParam( (ContactRecord? contact, _) => @@ -498,8 +499,12 @@ Future setup( getIt.registerFactory(() => OtherSettingsPage(getIt.get())); - getIt.registerFactory(() => - NodeCreateOrEditViewModel(_nodeSource, getIt.get().wallet!)); + getIt.registerFactoryParam( + (WalletType? type, _) => NodeCreateOrEditViewModel( + _nodeSource, + type ?? getIt.get().wallet!.type, + getIt.get(), + )); getIt.registerFactory( () => NodeCreateOrEditPage(getIt.get())); @@ -698,7 +703,7 @@ Future setup( getIt.registerFactoryParam( (String qrData, bool isLight) => FullscreenQRPage(qrData: qrData, isLight: isLight,)); - + getIt.registerFactory(() => IoniaApi()); getIt.registerFactory(() => AnyPayApi()); @@ -718,7 +723,7 @@ Future setup( getIt.registerFactoryParam((double amount, merchant) { return IoniaMerchPurchaseViewModel( - ioniaAnyPayService: getIt.get(), + ioniaAnyPayService: getIt.get(), amount: amount, ioniaMerchant: merchant, sendViewModel: getIt.get() @@ -761,31 +766,31 @@ Future setup( ioniaService: getIt.get(), giftCard: giftCard); }); - + getIt.registerFactoryParam((List args, _) { final amount = args[0] as double; final merchant = args[1] as IoniaMerchant; final tip = args[2] as IoniaTip; - + return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant); }); - + getIt.registerFactoryParam((IoniaGiftCard giftCard, _) { return IoniaGiftCardDetailPage(getIt.get(param1: giftCard)); }); getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; - - return IoniaMoreOptionsPage(giftCard); + + return IoniaMoreOptionsPage(giftCard); }); getIt.registerFactoryParam((IoniaGiftCard giftCard, _) => IoniaCustomRedeemViewModel(giftCard)); getIt.registerFactoryParam((List args, _){ final giftCard = args.first as IoniaGiftCard; - - return IoniaCustomRedeemPage(getIt.get(param1: giftCard) ); + + return IoniaCustomRedeemPage(getIt.get(param1: giftCard) ); }); @@ -814,5 +819,8 @@ Future setup( (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => IoniaPaymentStatusPage(getIt.get(param1: paymentInfo, param2: committedInfo))); + getIt.registerFactoryParam((type, _) => + AdvancedPrivacySettingsViewModel(type, getIt.get())); + _isSetupFinished = true; } \ No newline at end of file diff --git a/lib/entities/fiat_api_mode.dart b/lib/entities/fiat_api_mode.dart new file mode 100644 index 000000000..bb16ca5a4 --- /dev/null +++ b/lib/entities/fiat_api_mode.dart @@ -0,0 +1,39 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cw_core/enumerable_item.dart'; + +class FiatApiMode extends EnumerableItem with Serializable { + const FiatApiMode({required String title, required int raw}) : super(title: title, raw: raw); + + static const all = [FiatApiMode.enabled, FiatApiMode.torOnly, FiatApiMode.disabled]; + + static const enabled = FiatApiMode(raw: 0, title: 'Enabled'); + static const torOnly = FiatApiMode(raw: 1, title: 'Tor only'); + static const disabled = FiatApiMode(raw: 2, title: 'Disabled'); + + static FiatApiMode deserialize({required int raw}) { + switch (raw) { + case 0: + return enabled; + case 1: + return torOnly; + case 2: + return disabled; + default: + throw Exception('Unexpected token: $raw for FiatApiMode deserialize'); + } + } + + @override + String toString() { + switch (this) { + case FiatApiMode.enabled: + return S.current.enabled; + case FiatApiMode.torOnly: + return S.current.tor_only; + case FiatApiMode.disabled: + return S.current.disabled; + default: + return ''; + } + } +} diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 8c0758d86..90d4dcad7 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -9,6 +9,7 @@ class PreferencesKey { static const currentTransactionPriorityKeyLegacy = 'current_fee_priority'; static const currentBalanceDisplayModeKey = 'current_balance_display_mode'; static const shouldSaveRecipientAddressKey = 'save_recipient_address'; + static const currentFiatApiModeKey = 'current_fiat_api_mode'; static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication'; static const disableExchangeKey = 'disable_exchange'; @@ -21,6 +22,8 @@ class PreferencesKey { 'current_default_settings_migration_version'; static const moneroTransactionPriority = 'current_fee_priority_monero'; static const bitcoinTransactionPriority = 'current_fee_priority_bitcoin'; + static const havenTransactionPriority = 'current_fee_priority_haven'; + static const litecoinTransactionPriority = 'current_fee_priority_litecoin'; static const shouldShowReceiveWarning = 'should_show_receive_warning'; static const shouldShowYatPopup = 'should_show_yat_popup'; static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1'; diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index 96b6142e6..a9fb7c9ca 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -11,7 +11,6 @@ import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/changenow/changenow_request.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart'; -import 'package:cake_wallet/exchange/trade_not_created_exeption.dart'; class ChangeNowExchangeProvider extends ExchangeProvider { ChangeNowExchangeProvider() @@ -21,8 +20,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { .where((i) => i != CryptoCurrency.xhv) .map((i) => CryptoCurrency.all .where((i) => i != CryptoCurrency.xhv) - .map((k) => ExchangePair(from: i, to: k, reverse: true)) - .where((c) => c != null)) + .map((k) => ExchangePair(from: i, to: k, reverse: true))) .expand((i) => i) .toList()); @@ -43,6 +41,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => true; + @override ExchangeProviderDescription get description => ExchangeProviderDescription.changeNow; @@ -96,19 +97,30 @@ class ChangeNowExchangeProvider extends ExchangeProvider { apiHeaderKey: apiKey, 'Content-Type': 'application/json'}; final flow = getFlow(isFixedRateMode); + final type = isFixedRateMode ? 'reverse' : 'direct'; final body = { 'fromCurrency': normalizeCryptoCurrency(_request.from), 'toCurrency': normalizeCryptoCurrency(_request.to), 'fromNetwork': networkFor(_request.from), 'toNetwork': networkFor(_request.to), - 'fromAmount': _request.fromAmount, - 'toAmount': _request.toAmount, + if (!isFixedRateMode) 'fromAmount': _request.fromAmount, + if (isFixedRateMode) 'toAmount': _request.toAmount, 'address': _request.address, 'flow': flow, + 'type': type, 'refundAddress': _request.refundAddress }; if (isFixedRateMode) { + // since we schedule to calculate the rate every 5 seconds we need to ensure that + // we have the latest rate id with the given inputs before creating the trade + await fetchRate( + from: _request.from, + to: _request.to, + amount: double.tryParse(_request.toAmount) ?? 0, + isFixedRateMode: true, + isReceiveAmount: true, + ); body['rateId'] = _lastUsedRateId; } @@ -141,7 +153,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { refundAddress: refundAddress, extraId: extraId, createdAt: DateTime.now(), - amount: _request.fromAmount, + amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount, state: TradeState.created); } @@ -180,9 +192,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final extraId = responseJSON['payinExtraId'] as String; final outputTransaction = responseJSON['payoutHash'] as String; final expiredAtRaw = responseJSON['validUntil'] as String; - final expiredAt = expiredAtRaw != null - ? DateTime.parse(expiredAtRaw).toLocal() - : null; + final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal(); return Trade( id: id, @@ -198,7 +208,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { } @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, @@ -214,10 +224,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider { final type = isReverse ? 'reverse' : 'direct'; final flow = getFlow(isFixedRateMode); final params = { - 'fromCurrency': isReverse ? normalizeCryptoCurrency(to) : normalizeCryptoCurrency(from), - 'toCurrency': isReverse ? normalizeCryptoCurrency(from) : normalizeCryptoCurrency(to), - 'fromNetwork': isReverse ? networkFor(to) : networkFor(from), - 'toNetwork': isReverse ? networkFor(from) : networkFor(to), + 'fromCurrency': normalizeCryptoCurrency(from), + 'toCurrency': normalizeCryptoCurrency(to), + 'fromNetwork': networkFor(from), + 'toNetwork': networkFor(to), 'type': type, 'flow': flow}; @@ -238,7 +248,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { _lastUsedRateId = rateId; } - return isReverse ? fromAmount : toAmount; + return isReverse ? (amount / fromAmount) : (toAmount / amount); } catch(e) { print(e.toString()); return 0.0; diff --git a/lib/exchange/exchange_provider.dart b/lib/exchange/exchange_provider.dart index 14fba803f..763350c94 100644 --- a/lib/exchange/exchange_provider.dart +++ b/lib/exchange/exchange_provider.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/exchange_pair.dart'; @@ -14,6 +13,7 @@ abstract class ExchangeProvider { ExchangeProviderDescription get description; bool get isAvailable; bool get isEnabled; + bool get supportsFixedRate; @override String toString() => title; @@ -26,7 +26,7 @@ abstract class ExchangeProvider { required TradeRequest request, required bool isFixedRateMode}); Future findTradeById({required String id}); - Future calculateAmount({ + Future fetchRate({ required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/morphtoken/morphtoken_exchange_provider.dart b/lib/exchange/morphtoken/morphtoken_exchange_provider.dart index 1df4fef87..a2a72b24f 100644 --- a/lib/exchange/morphtoken/morphtoken_exchange_provider.dart +++ b/lib/exchange/morphtoken/morphtoken_exchange_provider.dart @@ -66,6 +66,9 @@ class MorphTokenExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => false; + @override ExchangeProviderDescription get description => ExchangeProviderDescription.morphToken; @@ -200,7 +203,7 @@ class MorphTokenExchangeProvider extends ExchangeProvider { } @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/exchange/sideshift/sideshift_exchange_provider.dart b/lib/exchange/sideshift/sideshift_exchange_provider.dart index a732f7ef2..98f18f058 100644 --- a/lib/exchange/sideshift/sideshift_exchange_provider.dart +++ b/lib/exchange/sideshift/sideshift_exchange_provider.dart @@ -12,7 +12,6 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/exchange/limits.dart'; -import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; class SideShiftExchangeProvider extends ExchangeProvider { @@ -48,8 +47,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { return supportedCurrencies .map((i) => supportedCurrencies - .map((k) => ExchangePair(from: i, to: k, reverse: true)) - .where((c) => c != null)) + .map((k) => ExchangePair(from: i, to: k, reverse: true))) .expand((i) => i) .toList(); } @@ -59,7 +57,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { ExchangeProviderDescription.sideShift; @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, @@ -81,9 +79,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { if (amount > max) return 0.00; - final estimatedAmount = rate * amount; - - return estimatedAmount; + return rate; } catch (_) { return 0.00; } @@ -249,15 +245,15 @@ class SideShiftExchangeProvider extends ExchangeProvider { final expectedSendAmount = responseJSON['depositAmount'].toString(); final deposits = responseJSON['deposits'] as List?; TradeState? state; + String? status; - if (deposits != null && deposits.isNotEmpty) { - final status = deposits[0]['status'] as String; - state = TradeState.deserialize(raw: status); + if (deposits?.isNotEmpty ?? false) { + status = deposits![0]['status'] as String?; } + state = TradeState.deserialize(raw: status ?? 'created'); final expiredAtRaw = responseJSON['expiresAtISO'] as String; - final expiredAt = - expiredAtRaw != null ? DateTime.parse(expiredAtRaw).toLocal() : null; + final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal(); return Trade( id: id, @@ -277,6 +273,9 @@ class SideShiftExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => true; + @override String get title => 'SideShift'; diff --git a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart index c6e1baeea..2521c1486 100644 --- a/lib/exchange/simpleswap/simpleswap_exchange_provider.dart +++ b/lib/exchange/simpleswap/simpleswap_exchange_provider.dart @@ -20,8 +20,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { .where((i) => i != CryptoCurrency.zaddr) .map((i) => CryptoCurrency.all .where((i) => i != CryptoCurrency.zaddr) - .map((k) => ExchangePair(from: i, to: k, reverse: true)) - .where((c) => c != null)) + .map((k) => ExchangePair(from: i, to: k, reverse: true))) .expand((i) => i) .toList()); @@ -37,7 +36,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { ExchangeProviderDescription.simpleSwap; @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, @@ -59,9 +58,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { final uri = Uri.https(apiAuthority, getEstimatePath, params); final response = await get(uri); - if (response.body == null || response.body == "null") return 0.00; + if (response.body == "null") return 0.00; final data = json.decode(response.body) as String; - return double.parse(data); + return double.parse(data) / amount; } catch (_) { return 0.00; } @@ -210,6 +209,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => false; + @override String get title => 'SimpleSwap'; diff --git a/lib/exchange/xmrto/xmrto_exchange_provider.dart b/lib/exchange/xmrto/xmrto_exchange_provider.dart index d5f79361e..536754e18 100644 --- a/lib/exchange/xmrto/xmrto_exchange_provider.dart +++ b/lib/exchange/xmrto/xmrto_exchange_provider.dart @@ -48,6 +48,9 @@ class XMRTOExchangeProvider extends ExchangeProvider { @override bool get isEnabled => true; + @override + bool get supportsFixedRate => false; + @override ExchangeProviderDescription get description => ExchangeProviderDescription.xmrto; @@ -191,7 +194,7 @@ class XMRTOExchangeProvider extends ExchangeProvider { } @override - Future calculateAmount( + Future fetchRate( {required CryptoCurrency from, required CryptoCurrency to, required double amount, diff --git a/lib/main.dart b/lib/main.dart index e1fade7b4..11eee146b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -261,7 +261,7 @@ class AppState extends State with SingleTickerProviderStateMixin { final statusBarColor = Colors.transparent; final authenticationStore = getIt.get(); final initialRoute = - authenticationStore.state == AuthenticationState.denied + authenticationStore.state == AuthenticationState.uninitialized ? Routes.disclaimer : Routes.login; final currentTheme = settingsStore.currentTheme; diff --git a/lib/reactions/bootstrap.dart b/lib/reactions/bootstrap.dart index 8d9950e64..4b65ed9d2 100644 --- a/lib/reactions/bootstrap.dart +++ b/lib/reactions/bootstrap.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'package:cake_wallet/reactions/fiat_rate_update.dart'; import 'package:cake_wallet/reactions/on_current_node_change.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/widgets.dart'; @@ -22,13 +23,14 @@ Future bootstrap(GlobalKey navigatorKey) async { final currentWalletName = getIt .get() .getString(PreferencesKey.currentWalletName); - authenticationStore.state = currentWalletName == null - ? AuthenticationState.denied - : AuthenticationState.installed; + if (currentWalletName != null) { + authenticationStore.state = AuthenticationState.installed; + } startAuthenticationStateChange(authenticationStore, navigatorKey); startCurrentWalletChangeReaction( appStore, settingsStore, fiatConversionStore); startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore); startOnCurrentNodeChangeReaction(appStore); + startFiatRateUpdate(appStore, settingsStore, fiatConversionStore); } diff --git a/lib/reactions/fiat_rate_update.dart b/lib/reactions/fiat_rate_update.dart index 784a14e82..48c61d8ca 100644 --- a/lib/reactions/fiat_rate_update.dart +++ b/lib/reactions/fiat_rate_update.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:cake_wallet/core/fiat_conversion_service.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/update_haven_rate.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; @@ -8,30 +9,27 @@ import 'package:cw_core/wallet_type.dart'; Timer? _timer; -Future startFiatRateUpdate(AppStore appStore, SettingsStore settingsStore, - FiatConversionStore fiatConversionStore) async { +Future startFiatRateUpdate( + AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) async { if (_timer != null) { return; } - if (appStore.wallet != null) { - fiatConversionStore.prices[appStore.wallet!.currency] = - await FiatConversionService.fetchPrice( - appStore.wallet!.currency, settingsStore.fiatCurrency); - } + _timer = Timer.periodic(Duration(seconds: 30), (_) async { + try { + if (appStore.wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) { + return; + } - _timer = Timer.periodic( - Duration(seconds: 30), - (_) async { - try { - if (appStore.wallet!.type == WalletType.haven) { - await updateHavenRate(fiatConversionStore); - } else { - fiatConversionStore.prices[appStore.wallet!.currency] = await FiatConversionService.fetchPrice( - appStore.wallet!.currency, settingsStore.fiatCurrency); - } - } catch(e) { - print(e); - } - }); + if (appStore.wallet!.type == WalletType.haven) { + await updateHavenRate(fiatConversionStore); + } else { + fiatConversionStore.prices[appStore.wallet!.currency] = + await FiatConversionService.fetchPrice( + appStore.wallet!.currency, settingsStore.fiatCurrency); + } + } catch (e) { + print(e); + } + }); } diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index c91f5277e..edadf33b0 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -26,10 +26,5 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore, await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); return; } - - if (state == AuthenticationState.denied) { - await navigatorKey.currentState!.pushNamedAndRemoveUntil(Routes.welcome, (_) => false); - return; - } }); } diff --git a/lib/reactions/on_current_fiat_change.dart b/lib/reactions/on_current_fiat_change.dart index 86a5ee881..5170c4576 100644 --- a/lib/reactions/on_current_fiat_change.dart +++ b/lib/reactions/on_current_fiat_change.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; @@ -12,7 +13,7 @@ void startCurrentFiatChangeReaction(AppStore appStore, _onCurrentFiatCurrencyChangeDisposer?.reaction.dispose(); _onCurrentFiatCurrencyChangeDisposer = reaction( (_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async { - if (appStore.wallet == null) { + if (appStore.wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) { return; } diff --git a/lib/reactions/on_current_wallet_change.dart b/lib/reactions/on_current_wallet_change.dart index cce972368..270415820 100644 --- a/lib/reactions/on_current_wallet_change.dart +++ b/lib/reactions/on_current_wallet_change.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/update_haven_rate.dart'; import 'package:cw_core/transaction_history.dart'; @@ -87,7 +88,7 @@ void startCurrentWalletChangeReaction(AppStore appStore, TransactionHistoryBase, TransactionInfo>? wallet) async { try { - if (wallet == null) { + if (wallet == null || settingsStore.fiatApiMode == FiatApiMode.disabled) { return; } diff --git a/lib/router.dart b/lib/router.dart index 4d3d61f5f..b59294428 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -15,6 +15,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart'; +import 'package:cake_wallet/src/screens/new_wallet/advanced_privacy_settings_page.dart'; import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart'; @@ -25,6 +26,8 @@ import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/routes.dart'; @@ -77,6 +80,7 @@ import 'package:cake_wallet/src/screens/ionia/ionia.dart'; import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart'; import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; +import 'package:cw_core/crypto_currency.dart'; late RouteSettings currentRouteSettings; @@ -317,11 +321,13 @@ Route createRoute(RouteSettings settings) { case Routes.addressBook: return MaterialPageRoute( - builder: (_) => getIt.get(param1: true)); + builder: (_) => + getIt.get()); case Routes.pickerAddressBook: + final selectedCurrency = settings.arguments as CryptoCurrency; return MaterialPageRoute( - builder: (_) => getIt.get(param1: false)); + builder: (_) => getIt.get(param1: selectedCurrency)); case Routes.addressBookAddContact: return CupertinoPageRoute( @@ -491,6 +497,15 @@ Route createRoute(RouteSettings settings) { case Routes.onramperPage: return CupertinoPageRoute(builder: (_) => getIt.get()); + case Routes.advancedPrivacySettings: + final type = settings.arguments as WalletType; + + return CupertinoPageRoute( + builder: (_) => AdvancedPrivacySettingsPage( + getIt.get(param1: type), + getIt.get(param1: type), + )); + default: return MaterialPageRoute( builder: (_) => Scaffold( diff --git a/lib/routes.dart b/lib/routes.dart index d738b13e8..5ea250310 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -81,4 +81,5 @@ class Routes { static const privacyPage = '/privacy_page'; static const displaySettingsPage = '/display_settings_page'; static const otherSettingsPage = '/other_settings_page'; + static const advancedPrivacySettings = '/advanced_privacy_settings'; } diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 7912472d8..7cd7a0157 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -9,24 +9,22 @@ import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; import 'package:cake_wallet/src/widgets/collapsible_standart_list.dart'; class ContactListPage extends BasePage { - ContactListPage(this.contactListViewModel, {this.isEditable = true}); + ContactListPage(this.contactListViewModel); final ContactListViewModel contactListViewModel; - final bool isEditable; @override String get title => S.current.address_book; @override Widget? trailing(BuildContext context) { - if (!isEditable) { + if (!contactListViewModel.isEditable) { return null; } @@ -60,11 +58,14 @@ class ContactListPage extends BasePage { @override Widget body(BuildContext context) { + return Container( padding: EdgeInsets.only(top: 20.0, bottom: 20.0), child: Observer( - builder: (_) { - return CollapsibleSectionList( + builder: (_) { + final contacts = contactListViewModel.contactsToShow; + final walletContacts = contactListViewModel.walletContactsToShow; + return CollapsibleSectionList( context: context, sectionCount: 2, themeColor: Theme.of(context).primaryTextTheme.headline6!.color!, @@ -82,35 +83,37 @@ class ContactListPage extends BasePage { child: Text(title, style: TextStyle(fontSize: 36))); }, itemCounter: (int sectionIndex) => sectionIndex == 0 - ? contactListViewModel.walletContacts.length - : contactListViewModel.contacts.length, + ? walletContacts.length + : contacts.length, itemBuilder: (_, sectionIndex, index) { if (sectionIndex == 0) { - final walletInfo = contactListViewModel.walletContacts[index]; + final walletInfo = walletContacts[index]; return generateRaw(context, walletInfo); } - final contact = contactListViewModel.contacts[index]; + final contact = contacts[index]; final content = generateRaw(context, contact); - return !isEditable - ? content - : Slidable( + return contactListViewModel.isEditable + ? Slidable( key: Key('${contact.key}'), endActionPane: _actionPane(context, contact), child: content, - ); + ) + : content; }, - ); - }, - )); + );}) + ); } Widget generateRaw(BuildContext context, ContactBase contact) { - final image = _getCurrencyImage(contact.type); + final image = contact.type.iconPath; + final currencyIcon = image != null ? Image.asset(image, height: 24, width: 24) + : const SizedBox(height: 24, width: 24); + return GestureDetector( onTap: () async { - if (!isEditable) { + if (!contactListViewModel.isEditable) { Navigator.of(context).pop(contact); return; } @@ -131,12 +134,10 @@ class ContactListPage extends BasePage { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, children: [ - image ?? Offstage(), + currencyIcon, Expanded( child: Padding( - padding: image != null - ? EdgeInsets.only(left: 12) - : EdgeInsets.only(left: 0), + padding: EdgeInsets.only(left: 12), child: Text( contact.name, style: TextStyle( @@ -152,69 +153,6 @@ class ContactListPage extends BasePage { ); } - Image? _getCurrencyImage(CryptoCurrency currency) { - Image? image; - - switch (currency) { - case CryptoCurrency.xmr: - image = - Image.asset('assets/images/monero_logo.png', height: 24, width: 24); - break; - case CryptoCurrency.ada: - image = Image.asset('assets/images/ada.png', height: 24, width: 24); - break; - case CryptoCurrency.bch: - image = Image.asset('assets/images/bch.png', height: 24, width: 24); - break; - case CryptoCurrency.bnb: - image = Image.asset('assets/images/bnb.png', height: 24, width: 24); - break; - case CryptoCurrency.btc: - image = Image.asset('assets/images/bitcoin.png', height: 24, width: 24); - break; - case CryptoCurrency.dai: - image = Image.asset('assets/images/dai.png', height: 24, width: 24); - break; - case CryptoCurrency.dash: - image = Image.asset('assets/images/dash.png', height: 24, width: 24); - break; - case CryptoCurrency.eos: - image = Image.asset('assets/images/eos.png', height: 24, width: 24); - break; - case CryptoCurrency.eth: - image = Image.asset('assets/images/eth.png', height: 24, width: 24); - break; - case CryptoCurrency.ltc: - image = - Image.asset('assets/images/litecoin.png', height: 24, width: 24); - break; - case CryptoCurrency.nano: - image = Image.asset('assets/images/nano.png', height: 24, width: 24); - break; - case CryptoCurrency.trx: - image = Image.asset('assets/images/trx.png', height: 24, width: 24); - break; - case CryptoCurrency.usdt: - image = Image.asset('assets/images/usdt.png', height: 24, width: 24); - break; - case CryptoCurrency.usdterc20: - image = Image.asset('assets/images/usdterc.png', height: 24, width: 24); - break; - case CryptoCurrency.xlm: - image = Image.asset('assets/images/xlm.png', height: 24, width: 24); - break; - case CryptoCurrency.xrp: - image = Image.asset('assets/images/xrp.png', height: 24, width: 24); - break; - case CryptoCurrency.xhv: - image = Image.asset('assets/images/haven_logo.png', height: 24, width: 24); - break; - default: - image = null; - } - return image; - } - Future showAlertDialog(BuildContext context) async { return await showPopUp( context: context, diff --git a/lib/src/screens/dashboard/widgets/transactions_page.dart b/lib/src/screens/dashboard/widgets/transactions_page.dart index 8ab7c0efb..64f02c73c 100644 --- a/lib/src/screens/dashboard/widgets/transactions_page.dart +++ b/lib/src/screens/dashboard/widgets/transactions_page.dart @@ -57,7 +57,9 @@ class TransactionsPage extends StatelessWidget { formattedDate: DateFormat('HH:mm') .format(transaction.date), formattedAmount: item.formattedCryptoAmount, - formattedFiatAmount: item.formattedFiatAmount, + formattedFiatAmount: + dashboardViewModel.balanceViewModel.isFiatDisabled + ? '' : item.formattedFiatAmount, isPending: transaction.isPending)); } diff --git a/lib/src/screens/exchange/widgets/exchange_card.dart b/lib/src/screens/exchange/widgets/exchange_card.dart index 98843b1fb..40aa679a4 100644 --- a/lib/src/screens/exchange/widgets/exchange_card.dart +++ b/lib/src/screens/exchange/widgets/exchange_card.dart @@ -395,7 +395,8 @@ class ExchangeCardState extends State { buttonColor: widget.addressButtonsColor, validator: widget.addressTextFieldValidator, onPushPasteButton: widget.onPushPasteButton, - onPushAddressBookButton: widget.onPushAddressBookButton + onPushAddressBookButton: widget.onPushAddressBookButton, + selectedCurrency: _selectedCurrency ), ) diff --git a/lib/src/screens/exchange_trade/exchange_trade_page.dart b/lib/src/screens/exchange_trade/exchange_trade_page.dart index aa3079197..7c9fc1be7 100644 --- a/lib/src/screens/exchange_trade/exchange_trade_page.dart +++ b/lib/src/screens/exchange_trade/exchange_trade_page.dart @@ -378,12 +378,10 @@ class ExchangeTradeState extends State { }); }, actionLeftButton: () => Navigator.of(context).pop(), - feeFiatAmount: widget.exchangeTradeViewModel.sendViewModel.pendingTransactionFeeFiatAmount - + ' ' + widget.exchangeTradeViewModel.sendViewModel.fiat.title, - fiatAmountValue: widget.exchangeTradeViewModel.sendViewModel - .pendingTransactionFiatAmount + - ' ' + - widget.exchangeTradeViewModel.sendViewModel.fiat.title, + feeFiatAmount: widget.exchangeTradeViewModel + .pendingTransactionFeeFiatAmountFormatted, + fiatAmountValue: widget.exchangeTradeViewModel + .pendingTransactionFiatAmountValueFormatted, outputs: widget.exchangeTradeViewModel.sendViewModel .outputs); }); diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart new file mode 100644 index 000000000..6c2f996df --- /dev/null +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -0,0 +1,111 @@ +import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; + +class AdvancedPrivacySettingsPage extends BasePage { + AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel); + + final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel; + final NodeCreateOrEditViewModel nodeViewModel; + + @override + String get title => S.current.privacy_settings; + + @override + Widget body(BuildContext context) => + AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel); +} + +class AdvancedPrivacySettingsBody extends StatefulWidget { + const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key}) + : super(key: key); + + final AdvancedPrivacySettingsViewModel privacySettingsViewModel; + final NodeCreateOrEditViewModel nodeViewModel; + + @override + _AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState(); +} + +class _AdvancedPrivacySettingsBodyState extends State { + _AdvancedPrivacySettingsBodyState(); + + final _formKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.only(top: 24), + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.only(bottom: 24), + content: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ...widget.privacySettingsViewModel.settings.map( + (item) => Observer( + builder: (_) => SettingsSwitcherCell( + title: item.title, + value: item.value(), + onValueChange: item.onValueChange, + ), + ), + ), + Observer( + builder: (_) { + if (widget.privacySettingsViewModel.addCustomNode) { + return Padding( + padding: EdgeInsets.only(left: 24, right: 24, top: 24), + child: NodeForm( + formKey: _formKey, + nodeViewModel: widget.nodeViewModel, + ), + ); + } + return const SizedBox(); + }, + ), + ], + ), + bottomSectionPadding: EdgeInsets.all(24), + bottomSection: Column( + children: [ + LoadingPrimaryButton( + onPressed: () { + if (widget.privacySettingsViewModel.addCustomNode) { + if (_formKey.currentState != null && !_formKey.currentState!.validate()) { + return; + } + + widget.nodeViewModel.save(saveAsCurrent: true); + } + + Navigator.pop(context); + }, + text: S.of(context).continue_text, + color: Theme.of(context).accentTextTheme.bodyText1!.color!, + textColor: Colors.white, + ), + const SizedBox(height: 25), + Padding( + padding: EdgeInsets.symmetric(horizontal: MediaQuery.of(context).size.width * 0.15), + child: Text( + S.of(context).settings_can_be_changed_later, + textAlign: TextAlign.center, + style: TextStyle( + color: Theme.of(context).accentTextTheme.headline2?.color, + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index cd08cfb61..9e0cd898c 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -200,18 +200,30 @@ class _WalletNameFormState extends State { ] ]), bottomSectionPadding: - EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Observer( - builder: (context) { - return LoadingPrimaryButton( - onPressed: _confirmForm, - text: S.of(context).seed_language_next, - color: Colors.green, - textColor: Colors.white, - isLoading: _walletNewVM.state is IsExecutingState, - isDisabled: _walletNewVM.name.isEmpty, - ); - }, + EdgeInsets.all(24), + bottomSection: Column( + children: [ + Observer( + builder: (context) { + return LoadingPrimaryButton( + onPressed: _confirmForm, + text: S.of(context).seed_language_next, + color: Colors.green, + textColor: Colors.white, + isLoading: _walletNewVM.state is IsExecutingState, + isDisabled: _walletNewVM.name.isEmpty, + ); + }, + ), + const SizedBox(height: 25), + GestureDetector( + onTap: () { + Navigator.of(context) + .pushNamed(Routes.advancedPrivacySettings, arguments: _walletNewVM.type); + }, + child: Text(S.of(context).advanced_privacy_settings), + ), + ], )), ); } diff --git a/lib/src/screens/nodes/node_create_or_edit_page.dart b/lib/src/screens/nodes/node_create_or_edit_page.dart index e84b6bdad..8173af2f0 100644 --- a/lib/src/screens/nodes/node_create_or_edit_page.dart +++ b/lib/src/screens/nodes/node_create_or_edit_page.dart @@ -1,16 +1,13 @@ import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/core/node_address_validator.dart'; -import 'package:cake_wallet/core/node_port_validator.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; @@ -108,91 +105,10 @@ class NodeCreateOrEditPage extends BasePage { padding: EdgeInsets.only(left: 24, right: 24), child: ScrollableWithBottomSection( contentPadding: EdgeInsets.only(bottom: 24.0), - content: Form( - key: _formKey, - child: Column( - children: [ - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _addressController, - hintText: S.of(context).node_address, - validator: NodeAddressValidator(), - ) - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _portController, - hintText: S.of(context).node_port, - keyboardType: TextInputType.numberWithOptions( - signed: false, decimal: false), - validator: NodePortValidator(), - ) - ) - ], - ), - SizedBox(height: 10.0), - if (nodeCreateOrEditViewModel.hasAuthCredentials) ...[ - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _loginController, - hintText: S.of(context).login, - ) - ) - ], - ), - SizedBox(height: 10.0), - Row( - children: [ - Expanded( - child: BaseTextFormField( - controller: _passwordController, - hintText: S.of(context).password, - ) - ) - ], - ), - Padding( - padding: EdgeInsets.only(top: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Observer( - builder: (_) => StandardCheckbox( - value: nodeCreateOrEditViewModel.useSSL, - onChanged: (value) => - nodeCreateOrEditViewModel.useSSL = value, - caption: S.of(context).use_ssl, - )) - ], - )), - Padding( - padding: EdgeInsets.only(top: 20), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Observer( - builder: (_) => StandardCheckbox( - value: nodeCreateOrEditViewModel.trusted, - onChanged: (value) => - nodeCreateOrEditViewModel.trusted = value, - caption: S.of(context).trusted, - )) - ], - )), - ] - ], - )), + content: NodeForm( + formKey: _formKey, + nodeViewModel: nodeCreateOrEditViewModel, + ), bottomSectionPadding: EdgeInsets.only(bottom: 24), bottomSection: Observer( builder: (_) => Row( diff --git a/lib/src/screens/nodes/widgets/node_form.dart b/lib/src/screens/nodes/widgets/node_form.dart new file mode 100644 index 000000000..52851e063 --- /dev/null +++ b/lib/src/screens/nodes/widgets/node_form.dart @@ -0,0 +1,151 @@ +import 'package:cake_wallet/core/node_address_validator.dart'; +import 'package:cake_wallet/core/node_port_validator.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; +import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:mobx/mobx.dart'; + +class NodeForm extends StatelessWidget { + NodeForm({ + required this.nodeViewModel, + required this.formKey, + }) : _addressController = TextEditingController(), + _portController = TextEditingController(), + _loginController = TextEditingController(), + _passwordController = TextEditingController() { + reaction((_) => nodeViewModel.address, (String address) { + if (address != _addressController.text) { + _addressController.text = address; + } + }); + + reaction((_) => nodeViewModel.port, (String port) { + if (port != _portController.text) { + _portController.text = port; + } + }); + + if (nodeViewModel.hasAuthCredentials) { + reaction((_) => nodeViewModel.login, (String login) { + if (login != _loginController.text) { + _loginController.text = login; + } + }); + + reaction((_) => nodeViewModel.password, (String password) { + if (password != _passwordController.text) { + _passwordController.text = password; + } + }); + } + + _addressController + .addListener(() => nodeViewModel.address = _addressController.text); + _portController + .addListener(() => nodeViewModel.port = _portController.text); + _loginController + .addListener(() => nodeViewModel.login = _loginController.text); + _passwordController + .addListener(() => nodeViewModel.password = _passwordController.text); + } + + final NodeCreateOrEditViewModel nodeViewModel; + final GlobalKey formKey; + + final TextEditingController _addressController; + final TextEditingController _portController; + final TextEditingController _loginController; + final TextEditingController _passwordController; + + @override + Widget build(BuildContext context) { + return Form( + key: formKey, + child: Column( + children: [ + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _addressController, + hintText: S.of(context).node_address, + validator: NodeAddressValidator(), + ), + ) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _portController, + hintText: S.of(context).node_port, + keyboardType: TextInputType.numberWithOptions( + signed: false, decimal: false), + validator: NodePortValidator(), + )) + ], + ), + SizedBox(height: 10.0), + if (nodeViewModel.hasAuthCredentials) ...[ + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _loginController, + hintText: S.of(context).login, + )) + ], + ), + SizedBox(height: 10.0), + Row( + children: [ + Expanded( + child: BaseTextFormField( + controller: _passwordController, + hintText: S.of(context).password, + )) + ], + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Observer( + builder: (_) => StandardCheckbox( + value: nodeViewModel.useSSL, + onChanged: (value) => nodeViewModel.useSSL = value, + caption: S.of(context).use_ssl, + ), + ) + ], + ), + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Observer( + builder: (_) => StandardCheckbox( + value: nodeViewModel.trusted, + onChanged: (value) => nodeViewModel.trusted = value, + caption: S.of(context).trusted, + ), + ), + ], + ), + ), + ] + ], + ), + ); + } +} diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index b051a3afb..190127c0c 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -381,16 +381,10 @@ class SendPage extends BasePage { amount: S.of(context).send_amount, amountValue: sendViewModel.pendingTransaction!.amountFormatted, - fiatAmountValue: - sendViewModel.pendingTransactionFiatAmount + - ' ' + - sendViewModel.fiat.title, + fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted, fee: S.of(context).send_fee, feeValue: sendViewModel.pendingTransaction!.feeFormatted, - feeFiatAmount: - sendViewModel.pendingTransactionFeeFiatAmount + - ' ' + - sendViewModel.fiat.title, + feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted, outputs: sendViewModel.outputs, rightButtonText: S.of(context).ok, leftButtonText: S.of(context).cancel, diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index d5775e2b5..8f0d6675d 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -154,6 +154,7 @@ class SendCardState extends State await output.fetchParsedAddress(context); }, validator: validator, + selectedCurrency: sendViewModel.currency, ); }), if (output.isParsedAddress) Padding( @@ -331,7 +332,8 @@ class SendCardState extends State ], ), )), - Padding( + if (!sendViewModel.isFiatDisabled) + Padding( padding: const EdgeInsets.only(top: 20), child: BaseTextFormField( focusNode: fiatAmountFocus, @@ -437,8 +439,9 @@ class SendCardState extends State Padding( padding: EdgeInsets.only(top: 5), - child: Text( - output + child: sendViewModel.isFiatDisabled + ? const SizedBox(height: 14) + : Text(output .estimatedFeeFiatAmount + ' ' + sendViewModel diff --git a/lib/src/screens/settings/display_settings_page.dart b/lib/src/screens/settings/display_settings_page.dart index cd413ff45..39123a7eb 100644 --- a/lib/src/screens/settings/display_settings_page.dart +++ b/lib/src/screens/settings/display_settings_page.dart @@ -34,7 +34,8 @@ class DisplaySettingsPage extends BasePage { onValueChange: (_, bool value) { _displaySettingsViewModel.setShouldDisplayBalance(value); }), - if (!isHaven) + //if (!isHaven) it does not work correctly + if(!_displaySettingsViewModel.disabledFiatApiMode) SettingsPickerCell( title: S.current.settings_currency, searchHintText: S.current.search_currency, diff --git a/lib/src/screens/settings/privacy_page.dart b/lib/src/screens/settings/privacy_page.dart index 128d864f4..2f15cc225 100644 --- a/lib/src/screens/settings/privacy_page.dart +++ b/lib/src/screens/settings/privacy_page.dart @@ -18,10 +18,15 @@ class PrivacyPage extends BasePage { return Container( padding: EdgeInsets.only(top: 10), child: Observer(builder: (_) { - return Observer(builder: (_) { return Column( mainAxisSize: MainAxisSize.min, children: [ + SettingsSwitcherCell( + title: S.current.disable_fiat, + value: _privacySettingsViewModel.isFiatDisabled, + onValueChange: (BuildContext context, bool value) { + _privacySettingsViewModel.setFiatMode(value); + }), SettingsSwitcherCell( title: S.current.disable_exchange, value: _privacySettingsViewModel.disableExchange, @@ -36,7 +41,6 @@ class PrivacyPage extends BasePage { }) ], ); - }); }), ); } diff --git a/lib/src/widgets/address_text_field.dart b/lib/src/widgets/address_text_field.dart index 35bf3ed85..7e0727312 100644 --- a/lib/src/widgets/address_text_field.dart +++ b/lib/src/widgets/address_text_field.dart @@ -4,6 +4,7 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/entities/qr_scanner.dart'; import 'package:cake_wallet/entities/contact_base.dart'; +import 'package:cw_core/crypto_currency.dart'; enum AddressTextFieldOption { paste, qrCode, addressBook } @@ -26,7 +27,8 @@ class AddressTextField extends StatelessWidget { this.hintStyle, this.validator, this.onPushPasteButton, - this.onPushAddressBookButton}); + this.onPushAddressBookButton, + this.selectedCurrency}); static const prefixIconWidth = 34.0; static const prefixIconHeight = 34.0; @@ -47,6 +49,7 @@ class AddressTextField extends StatelessWidget { final FocusNode? focusNode; final Function(BuildContext context)? onPushPasteButton; final Function(BuildContext context)? onPushAddressBookButton; + final CryptoCurrency? selectedCurrency; @override Widget build(BuildContext context) { @@ -207,7 +210,7 @@ class AddressTextField extends StatelessWidget { Future _presetAddressBookPicker(BuildContext context) async { final contact = await Navigator.of(context, rootNavigator: true) - .pushNamed(Routes.pickerAddressBook); + .pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency); if (contact is ContactBase && contact.address != null) { controller?.text = contact.address; diff --git a/lib/store/authentication_store.dart b/lib/store/authentication_store.dart index 626ca2a91..b734d7acb 100644 --- a/lib/store/authentication_store.dart +++ b/lib/store/authentication_store.dart @@ -4,7 +4,7 @@ part 'authentication_store.g.dart'; class AuthenticationStore = AuthenticationStoreBase with _$AuthenticationStore; -enum AuthenticationState { uninitialized, installed, allowed, denied } +enum AuthenticationState { uninitialized, installed, allowed } abstract class AuthenticationStoreBase with Store { AuthenticationStoreBase() : state = AuthenticationState.uninitialized; @@ -17,7 +17,4 @@ abstract class AuthenticationStoreBase with Store { @action void allowed() => state = AuthenticationState.allowed; - - @action - void denied() => state = AuthenticationState.denied; } diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 15fb2cf77..378d14aab 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -17,6 +17,9 @@ import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cw_core/node.dart'; import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/entities/action_list_display_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/.secrets.g.dart' as secrets; + part 'settings_store.g.dart'; @@ -28,6 +31,7 @@ abstract class SettingsStoreBase with Store { required FiatCurrency initialFiatCurrency, required BalanceDisplayMode initialBalanceDisplayMode, required bool initialSaveRecipientAddress, + required FiatApiMode initialFiatMode, required bool initialAllowBiometricalAuthentication, required bool initialExchangeEnabled, required ThemeBase initialTheme, @@ -41,12 +45,15 @@ abstract class SettingsStoreBase with Store { required this.actionlistDisplayMode, required this.pinTimeOutDuration, TransactionPriority? initialBitcoinTransactionPriority, - TransactionPriority? initialMoneroTransactionPriority}) + TransactionPriority? initialMoneroTransactionPriority, + TransactionPriority? initialHavenTransactionPriority, + TransactionPriority? initialLitecoinTransactionPriority}) : nodes = ObservableMap.of(nodes), _sharedPreferences = sharedPreferences, fiatCurrency = initialFiatCurrency, balanceDisplayMode = initialBalanceDisplayMode, shouldSaveRecipientAddress = initialSaveRecipientAddress, + fiatApiMode = initialFiatMode, allowBiometricalAuthentication = initialAllowBiometricalAuthentication, disableExchange = initialExchangeEnabled, currentTheme = initialTheme, @@ -63,6 +70,14 @@ abstract class SettingsStoreBase with Store { priority[WalletType.bitcoin] = initialBitcoinTransactionPriority; } + if (initialHavenTransactionPriority != null) { + priority[WalletType.haven] = initialHavenTransactionPriority; + } + + if (initialLitecoinTransactionPriority != null) { + priority[WalletType.litecoin] = initialLitecoinTransactionPriority; + } + reaction( (_) => fiatCurrency, (FiatCurrency fiatCurrency) => sharedPreferences.setString( @@ -74,11 +89,25 @@ abstract class SettingsStoreBase with Store { .setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup)); priority.observe((change) { - final key = change.key == WalletType.monero - ? PreferencesKey.moneroTransactionPriority - : PreferencesKey.bitcoinTransactionPriority; + final String? key; + switch (change.key) { + case WalletType.monero: + key = PreferencesKey.moneroTransactionPriority; + break; + case WalletType.bitcoin: + key = PreferencesKey.bitcoinTransactionPriority; + break; + case WalletType.litecoin: + key = PreferencesKey.litecoinTransactionPriority; + break; + case WalletType.haven: + key = PreferencesKey.havenTransactionPriority; + break; + default: + key = null; + } - if (change.newValue != null) { + if (change.newValue != null && key != null) { sharedPreferences.setInt(key, change.newValue!.serialize()); } }); @@ -89,6 +118,11 @@ abstract class SettingsStoreBase with Store { PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress)); + reaction( + (_) => fiatApiMode, + (FiatApiMode mode) => sharedPreferences.setInt( + PreferencesKey.currentFiatApiModeKey, mode.serialize())); + reaction( (_) => currentTheme, (ThemeBase theme) => @@ -120,6 +154,11 @@ abstract class SettingsStoreBase with Store { (BalanceDisplayMode mode) => sharedPreferences.setInt( PreferencesKey.currentBalanceDisplayModeKey, mode.serialize())); + reaction( + (_) => disableExchange, + (bool disableExchange) => sharedPreferences.setBool( + PreferencesKey.disableExchangeKey, disableExchange)); + this .nodes .observe((change) { @@ -145,6 +184,9 @@ abstract class SettingsStoreBase with Store { @observable BalanceDisplayMode balanceDisplayMode; + @observable + FiatApiMode fiatApiMode; + @observable bool shouldSaveRecipientAddress; @@ -199,39 +241,48 @@ abstract class SettingsStoreBase with Store { static Future load( {required Box nodeSource, required bool isBitcoinBuyEnabled, - TransactionPriority? initialMoneroTransactionPriority, - TransactionPriority? initialBitcoinTransactionPriority, FiatCurrency initialFiatCurrency = FiatCurrency.usd, BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance}) async { - if (initialBitcoinTransactionPriority == null) { - initialBitcoinTransactionPriority = bitcoin?.getMediumTransactionPriority(); - } - - if (initialMoneroTransactionPriority == null) { - initialMoneroTransactionPriority = monero?.getDefaultTransactionPriority(); - } final sharedPreferences = await getIt.getAsync(); final currentFiatCurrency = FiatCurrency.deserialize(raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!); - final savedMoneroTransactionPriority = + + TransactionPriority? moneroTransactionPriority = monero?.deserializeMoneroTransactionPriority( raw: sharedPreferences .getInt(PreferencesKey.moneroTransactionPriority)!); - final savedBitcoinTransactionPriority = + TransactionPriority? bitcoinTransactionPriority = bitcoin?.deserializeBitcoinTransactionPriority(sharedPreferences .getInt(PreferencesKey.bitcoinTransactionPriority)!); - final moneroTransactionPriority = - savedMoneroTransactionPriority ?? initialMoneroTransactionPriority; - final bitcoinTransactionPriority = - savedBitcoinTransactionPriority ?? initialBitcoinTransactionPriority; + + TransactionPriority? havenTransactionPriority; + TransactionPriority? litecoinTransactionPriority; + + if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) { + havenTransactionPriority = monero?.deserializeMoneroTransactionPriority( + raw: sharedPreferences.getInt(PreferencesKey.havenTransactionPriority)!); + } + if (sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority) != null) { + litecoinTransactionPriority = bitcoin?.deserializeLitecoinTransactionPriority( + sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!); + } + + moneroTransactionPriority ??= monero?.getDefaultTransactionPriority(); + bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority(); + havenTransactionPriority ??= monero?.getDefaultTransactionPriority(); + litecoinTransactionPriority ??= bitcoin?.getLitecoinTransactionPriorityMedium(); + final currentBalanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences .getInt(PreferencesKey.currentBalanceDisplayModeKey)!); // FIX-ME: Check for which default value we should have here final shouldSaveRecipientAddress = sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? false; + final currentFiatApiMode = FiatApiMode.deserialize( + raw: sharedPreferences + .getInt(PreferencesKey.currentFiatApiModeKey) ?? FiatApiMode.enabled.raw); final allowBiometricalAuthentication = sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? false; @@ -292,7 +343,7 @@ abstract class SettingsStoreBase with Store { if (havenNode != null) { nodes[WalletType.haven] = havenNode; } - + return SettingsStore( sharedPreferences: sharedPreferences, nodes: nodes, @@ -301,6 +352,7 @@ abstract class SettingsStoreBase with Store { initialFiatCurrency: currentFiatCurrency, initialBalanceDisplayMode: currentBalanceDisplayMode, initialSaveRecipientAddress: shouldSaveRecipientAddress, + initialFiatMode: currentFiatApiMode, initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialExchangeEnabled: disableExchange, initialTheme: savedTheme, @@ -310,6 +362,8 @@ abstract class SettingsStoreBase with Store { initialLanguageCode: savedLanguageCode, initialMoneroTransactionPriority: moneroTransactionPriority, initialBitcoinTransactionPriority: bitcoinTransactionPriority, + initialHavenTransactionPriority: havenTransactionPriority, + initialLitecoinTransactionPriority: litecoinTransactionPriority, shouldShowYatPopup: shouldShowYatPopup); } @@ -322,7 +376,7 @@ abstract class SettingsStoreBase with Store { // TransactionPriority? initialBitcoinTransactionPriority, // BalanceDisplayMode initialBalanceDisplayMode = // BalanceDisplayMode.availableBalance}) async { - + // if (initialBitcoinTransactionPriority == null) { // initialBitcoinTransactionPriority = bitcoin?.getMediumTransactionPriority(); // } diff --git a/lib/view_model/advanced_privacy_settings_view_model.dart b/lib/view_model/advanced_privacy_settings_view_model.dart new file mode 100644 index 000000000..f800e3418 --- /dev/null +++ b/lib/view_model/advanced_privacy_settings_view_model.dart @@ -0,0 +1,56 @@ +import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/view_model/settings/switcher_list_item.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +part 'advanced_privacy_settings_view_model.g.dart'; + +class AdvancedPrivacySettingsViewModel = AdvancedPrivacySettingsViewModelBase + with _$AdvancedPrivacySettingsViewModel; + +abstract class AdvancedPrivacySettingsViewModelBase with Store { + AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore) + : _addCustomNode = false { + settings = [ + SwitcherListItem( + title: S.current.disable_fiat, + value: () => _settingsStore.fiatApiMode == FiatApiMode.disabled, + onValueChange: (_, bool value) => setFiatMode(value), + ), + SwitcherListItem( + title: S.current.disable_exchange, + value: () => _settingsStore.disableExchange, + onValueChange: (_, bool value) { + _settingsStore.disableExchange = value; + }, + ), + SwitcherListItem( + title: S.current.add_custom_node, + value: () => _addCustomNode, + onValueChange: (_, bool value) => _addCustomNode = value, + ), + ]; + } + + late List settings; + + @observable + bool _addCustomNode = false; + + final WalletType type; + final SettingsStore _settingsStore; + + @computed + bool get addCustomNode => _addCustomNode; + + @action + void setFiatMode(bool value) { + if (value) { + _settingsStore.fiatApiMode = FiatApiMode.disabled; + return; + } + _settingsStore.fiatApiMode = FiatApiMode.enabled; + } +} diff --git a/lib/view_model/contact_list/contact_list_view_model.dart b/lib/view_model/contact_list/contact_list_view_model.dart index ec145ad44..5b0187fc8 100644 --- a/lib/view_model/contact_list/contact_list_view_model.dart +++ b/lib/view_model/contact_list/contact_list_view_model.dart @@ -7,27 +7,26 @@ import 'package:mobx/mobx.dart'; import 'package:cake_wallet/entities/contact_record.dart'; import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/utils/mobx.dart'; +import 'package:cw_core/crypto_currency.dart'; part 'contact_list_view_model.g.dart'; -class ContactListViewModel = ContactListViewModelBase - with _$ContactListViewModel; +class ContactListViewModel = ContactListViewModelBase with _$ContactListViewModel; abstract class ContactListViewModelBase with Store { - ContactListViewModelBase(this.contactSource, this.walletInfoSource) + ContactListViewModelBase(this.contactSource, this.walletInfoSource, this._currency) : contacts = ObservableList(), walletContacts = [] { walletInfoSource.values.forEach((info) { if (info.addresses?.isNotEmpty ?? false) { info.addresses?.forEach((address, label) { - final name = label.isNotEmpty - ? info.name + ' ($label)' - : info.name; + final name = label.isNotEmpty ? info.name + ' ($label)' : info.name; walletContacts.add(WalletContact( - address, - name, - walletTypeToCryptoCurrency(info.type))); + address, + name, + walletTypeToCryptoCurrency(info.type), + )); }); } }); @@ -41,7 +40,18 @@ abstract class ContactListViewModelBase with Store { final Box walletInfoSource; final ObservableList contacts; final List walletContacts; + final CryptoCurrency? _currency; StreamSubscription? _subscription; + bool get isEditable => _currency == null; + Future delete(ContactRecord contact) async => contact.original.delete(); + + @computed + List get contactsToShow => + contacts.where((element) => _currency == null || element.type == _currency).toList(); + + @computed + List get walletContactsToShow => + walletContacts.where((element) => _currency == null || element.type == _currency).toList(); } diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart index 75d107b89..33fe01ba9 100644 --- a/lib/view_model/dashboard/balance_view_model.dart +++ b/lib/view_model/dashboard/balance_view_model.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/balance.dart'; @@ -10,7 +11,6 @@ import 'package:cake_wallet/entities/calculate_fiat_amount.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; -import 'package:flutter/cupertino.dart'; import 'package:mobx/mobx.dart'; part 'balance_view_model.g.dart'; @@ -71,6 +71,9 @@ abstract class BalanceViewModelBase with Store { @computed BalanceDisplayMode get savedDisplayMode => settingsStore.balanceDisplayMode; + @computed + bool get isFiatDisabled => settingsStore.fiatApiMode == FiatApiMode.disabled; + @computed String get asset { final typeFormatted = walletTypeToString(appStore.wallet!.type); @@ -180,8 +183,8 @@ abstract class BalanceViewModelBase with Store { return MapEntry(key, BalanceRecord( availableBalance: '---', additionalBalance: '---', - fiatAdditionalBalance: '---', - fiatAvailableBalance: '---', + fiatAdditionalBalance: isFiatDisabled ? '' : '---', + fiatAvailableBalance: isFiatDisabled ? '' : '---', asset: key, formattedAssetTitle: _formatterAsset(key))); } @@ -192,17 +195,17 @@ abstract class BalanceViewModelBase with Store { // throw Exception('Price is null for: $key'); // } - final additionalFiatBalance = fiatCurrency.toString() - + ' ' + final additionalFiatBalance = isFiatDisabled ? '' : (fiatCurrency.toString() + + ' ' + _getFiatBalance( price: price, - cryptoAmount: value.formattedAdditionalBalance); + cryptoAmount: value.formattedAdditionalBalance)); - final availableFiatBalance = fiatCurrency.toString() - + ' ' + final availableFiatBalance = isFiatDisabled ? '' : (fiatCurrency.toString() + + ' ' + _getFiatBalance( price: price, - cryptoAmount: value.formattedAvailableBalance); + cryptoAmount: value.formattedAvailableBalance)); return MapEntry(key, BalanceRecord( availableBalance: value.formattedAvailableBalance, diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index 796397429..10ddf25e4 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -72,6 +72,18 @@ abstract class ExchangeTradeViewModelBase with Store { ? '\n\n' + S.current.xrp_extra_info : ''; + @computed + String get pendingTransactionFiatAmountValueFormatted => + sendViewModel.isFiatDisabled + ? '' : sendViewModel.pendingTransactionFiatAmount + + ' ' + sendViewModel.fiat.title; + + @computed + String get pendingTransactionFeeFiatAmountFormatted => + sendViewModel.isFiatDisabled + ? '' : sendViewModel.pendingTransactionFeeFiatAmount + + ' ' + sendViewModel.fiat.title; + @observable ObservableList items; diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index b19434166..5c1f696b8 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -44,7 +44,6 @@ abstract class ExchangeViewModelBase with Store { ExchangeViewModelBase(this.wallet, this.trades, this._exchangeTemplateStore, this.tradesStore, this._settingsStore, this.sharedPreferences) : _cryptoNumberFormat = NumberFormat(), - isReverse = false, isFixedRateMode = false, isReceiveAmountEntered = false, depositAmount = '', @@ -112,7 +111,11 @@ abstract class ExchangeViewModelBase with Store { loadLimits(); reaction( (_) => isFixedRateMode, - (Object _) => loadLimits()); + (Object _) { + loadLimits(); + _bestRate = 0; + _calculateBestRate(); + }); } final WalletBase wallet; @@ -227,8 +230,6 @@ abstract class ExchangeViewModelBase with Store { Limits limits; - bool isReverse; - NumberFormat _cryptoNumberFormat; final SettingsStore _settingsStore; @@ -258,7 +259,6 @@ abstract class ExchangeViewModelBase with Store { @action Future changeReceiveAmount({required String amount}) async { receiveAmount = amount; - isReverse = true; if (amount.isEmpty) { depositAmount = ''; @@ -283,7 +283,6 @@ abstract class ExchangeViewModelBase with Store { @action Future changeDepositAmount({required String amount}) async { depositAmount = amount; - isReverse = false; if (amount.isEmpty) { depositAmount = ''; @@ -311,12 +310,13 @@ abstract class ExchangeViewModelBase with Store { final result = await Future.wait( _tradeAvailableProviders - .map((element) => element.calculateAmount( + .where((element) => !isFixedRateMode || element.supportsFixedRate) + .map((element) => element.fetchRate( from: depositCurrency, to: receiveCurrency, amount: amount, isFixedRateMode: isFixedRateMode, - isReceiveAmount: false)) + isReceiveAmount: isFixedRateMode)) ); _sortedAvailableProviders.clear(); @@ -324,7 +324,7 @@ abstract class ExchangeViewModelBase with Store { for (int i=0;i limits.max!) { continue; diff --git a/lib/view_model/node_list/node_create_or_edit_view_model.dart b/lib/view_model/node_list/node_create_or_edit_view_model.dart index e24692059..a8f184589 100644 --- a/lib/view_model/node_list/node_create_or_edit_view_model.dart +++ b/lib/view_model/node_list/node_create_or_edit_view_model.dart @@ -1,7 +1,7 @@ import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/store/settings_store.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; -import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/wallet_type.dart'; @@ -11,7 +11,7 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase with _$NodeCreateOrEditViewModel; abstract class NodeCreateOrEditViewModelBase with Store { - NodeCreateOrEditViewModelBase(this._nodeSource, this._wallet) + NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType, this._settingsStore) : state = InitialExecutionState(), connectionState = InitialExecutionState(), useSSL = false, @@ -49,8 +49,8 @@ abstract class NodeCreateOrEditViewModelBase with Store { bool get isReady => address.isNotEmpty && port.isNotEmpty; - bool get hasAuthCredentials => _wallet.type == WalletType.monero || - _wallet.type == WalletType.haven; + bool get hasAuthCredentials => _walletType == WalletType.monero || + _walletType == WalletType.haven; String get uri { var uri = address; @@ -62,8 +62,9 @@ abstract class NodeCreateOrEditViewModelBase with Store { return uri; } - final WalletBase _wallet; + final WalletType _walletType; final Box _nodeSource; + final SettingsStore _settingsStore; @action void reset() { @@ -76,13 +77,18 @@ abstract class NodeCreateOrEditViewModelBase with Store { } @action - Future save() async { + Future save({bool saveAsCurrent = false}) async { try { state = IsExecutingState(); final node = - Node(uri: uri, type: _wallet.type, login: login, password: password, + Node(uri: uri, type: _walletType, login: login, password: password, useSSL: useSSL, trusted: trusted); await _nodeSource.add(node); + + if (saveAsCurrent) { + _settingsStore.nodes[_walletType] = node; + } + state = ExecutedSuccessfullyState(); } catch (e) { state = FailureState(e.toString()); @@ -94,7 +100,7 @@ abstract class NodeCreateOrEditViewModelBase with Store { try { connectionState = IsExecutingState(); final node = - Node(uri: uri, type: _wallet.type, login: login, password: password); + Node(uri: uri, type: _walletType, login: login, password: password); final isAlive = await node.requestNode(); connectionState = ExecutedSuccessfullyState(payload: isAlive); } catch (e) { diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 25a5cc7ee..fd783cf6f 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -142,6 +142,19 @@ abstract class SendViewModelBase with Store { @computed String get balance => balanceViewModel.availableBalance; + @computed + bool get isFiatDisabled => balanceViewModel.isFiatDisabled; + + @computed + String get pendingTransactionFiatAmountFormatted => + isFiatDisabled ? '' : pendingTransactionFiatAmount + + ' ' + fiat.title; + + @computed + String get pendingTransactionFeeFiatAmountFormatted => + isFiatDisabled ? '' : pendingTransactionFeeFiatAmount + + ' ' + fiat.title; + @computed bool get isReadyForSend => _wallet.syncStatus is SyncedSyncStatus; diff --git a/lib/view_model/settings/display_settings_view_model.dart b/lib/view_model/settings/display_settings_view_model.dart index 4e73b3399..bac6d9994 100644 --- a/lib/view_model/settings/display_settings_view_model.dart +++ b/lib/view_model/settings/display_settings_view_model.dart @@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; part 'display_settings_view_model.g.dart'; @@ -30,6 +31,9 @@ abstract class DisplaySettingsViewModelBase with Store { @computed ThemeBase get theme => _settingsStore.currentTheme; + @computed + bool get disabledFiatApiMode => _settingsStore.fiatApiMode == FiatApiMode.disabled; + @action void setBalanceDisplayMode(BalanceDisplayMode value) => _settingsStore.balanceDisplayMode = value; diff --git a/lib/view_model/settings/privacy_settings_view_model.dart b/lib/view_model/settings/privacy_settings_view_model.dart index 88311bf1f..f8c3e5b50 100644 --- a/lib/view_model/settings/privacy_settings_view_model.dart +++ b/lib/view_model/settings/privacy_settings_view_model.dart @@ -1,5 +1,6 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; part 'privacy_settings_view_model.g.dart'; @@ -16,9 +17,22 @@ abstract class PrivacySettingsViewModelBase with Store { @computed bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; + @computed + bool get isFiatDisabled => _settingsStore.fiatApiMode == FiatApiMode.disabled; + @action void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value; @action void setEnableExchange(bool value) => _settingsStore.disableExchange = value; + + @action + void setFiatMode(bool value) { + if (value) { + _settingsStore.fiatApiMode = FiatApiMode.disabled; + return; + } + _settingsStore.fiatApiMode = FiatApiMode.enabled; + } + } diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 07aa19549..ed5c92c99 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -652,7 +652,7 @@ "low_fee_alert": "Sie verwenden derzeit eine niedrige Netzwerkgebührenpriorität. Dies kann zu langen Wartezeiten, unterschiedlichen Kursen oder stornierten Trades führen. Wir empfehlen, für ein besseres Erlebnis eine höhere Gebühr festzulegen.", "ignor": "Ignorieren", "use_suggested": "Vorgeschlagen verwenden", - "do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich des Supports.\n\nSie werden Ihr Geld stehlen!", + "do_not_share_warning_text" : "Teilen Sie diese nicht mit anderen, einschließlich Support.\n\nIhr Geld kann und wird gestohlen werden!", "help": "hilfe", "connection_sync": "Verbindung und Synchronisierung", "security_and_backup": "Sicherheit und Datensicherung", @@ -664,5 +664,13 @@ "require_pin_after": "PIN anfordern nach", "always": "immer", "minutes_to_pin_code": "${minute} Minuten", - "disable_exchange": "Exchange deaktivieren" + "disable_exchange": "Exchange deaktivieren", + "advanced_privacy_settings": "Erweiterte Datenschutzeinstellungen", + "settings_can_be_changed_later": "Diese Einstellungen können später in den App-Einstellungen geändert werden", + "add_custom_node": "Neuen benutzerdefinierten Knoten hinzufügen", + "disable_fiat": "Fiat deaktivieren", + "fiat_api": "Fiat API", + "disabled": "Deaktiviert", + "enabled": "Ermöglicht", + "tor_only": "Nur Tor" } diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 7e3f3c196..608488b86 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -652,7 +652,7 @@ "low_fee_alert": "You currently are using a low network fee priority. This could cause long waits, different rates, or canceled trades. We recommend setting a higher fee for a better experience.", "ignor": "Ignore", "use_suggested": "Use Suggested", - "do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nThey will steal your money!", + "do_not_share_warning_text" : "Do not share these with anyone else, including support.\n\nYour funds can and will be stolen!", "help": "help", "connection_sync": "Connection and sync", "security_and_backup": "Security and backup", @@ -664,5 +664,13 @@ "require_pin_after": "Require PIN after", "always": "Always", "minutes_to_pin_code": "${minute} minutes", - "disable_exchange": "Disable exchange" + "disable_exchange": "Disable exchange", + "advanced_privacy_settings": "Advanced Privacy Settings", + "settings_can_be_changed_later": "These settings can be changed later in the app settings", + "add_custom_node": "Add New Custom Node", + "disable_fiat": "Disable fiat", + "fiat_api": "Fiat API", + "disabled": "Disabled", + "enabled": "Enabled", + "tor_only": "Tor only" } diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 649231e77..076b33579 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -652,7 +652,7 @@ "low_fee_alert": "Actualmente está utilizando una prioridad de tarifa de red baja. Esto podría causar largas esperas, tarifas diferentes o transacciones canceladas. Recomendamos establecer una tarifa más alta para una mejor experiencia.", "ignor": "Pasar por alto", "use_suggested": "Usar sugerido", - "do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Te robarán tu dinero!", + "do_not_share_warning_text" : "No comparta estos con nadie más, incluido el soporte.\n\n¡Sus fondos pueden ser y serán robados!", "help": "ayuda", "connection_sync": "Conexión y sincronización", "security_and_backup": "Seguridad y respaldo", @@ -664,5 +664,13 @@ "require_pin_after": "Requerir PIN después de", "always": "siempre", "minutes_to_pin_code": "${minute} minutos", - "disable_exchange": "Deshabilitar intercambio" + "disable_exchange": "Deshabilitar intercambio", + "advanced_privacy_settings": "Configuración avanzada de privacidad", + "settings_can_be_changed_later": "Estas configuraciones se pueden cambiar más tarde en la configuración de la aplicación", + "add_custom_node": "Agregar nuevo nodo personalizado", + "disable_fiat": "Deshabilitar fiat", + "fiat_api": "Fiat API", + "disabled": "Desactivado", + "enabled": "Activado", + "tor_only": "solo Tor" } diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 47caa9617..8047e958a 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -650,7 +650,7 @@ "low_fee_alert": "Vous utilisez actuellement une priorité de frais de réseau peu élevés. Cela pourrait entraîner de longues attentes, des taux différents ou des transactions annulées. Nous vous recommandons de fixer des frais plus élevés pour une meilleure expérience.", "ignor": "Ignorer", "use_suggested": "Utilisation suggérée", - "do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nIls vont voler votre argent!", + "do_not_share_warning_text" : "Ne les partagez avec personne d'autre, y compris avec l'assistance.\n\nVos fonds peuvent et seront volés!", "help": "aider", "connection_sync": "Connexion et synchronisation", "security_and_backup": "Sécurité et sauvegarde", @@ -662,5 +662,13 @@ "require_pin_after": "NIP requis après", "always": "toujours", "minutes_to_pin_code": "${minute} minutes", - "disable_exchange": "Désactiver l'échange" + "disable_exchange": "Désactiver l'échange", + "advanced_privacy_settings": "Paramètres de confidentialité avancés", + "settings_can_be_changed_later": "Ces paramètres peuvent être modifiés ultérieurement dans les paramètres de l'application", + "add_custom_node": "Ajouter un nouveau nœud personnalisé", + "disable_fiat": "Désactiver fiat", + "fiat_api": "Fiat API", + "disabled": "Handicapé", + "enabled": "Activé", + "tor_only": "Tor uniquement" } diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index be00ba7ef..8a9cfe05a 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -652,7 +652,7 @@ "low_fee_alert": "आप वर्तमान में कम नेटवर्क शुल्क प्राथमिकता का उपयोग कर रहे हैं। यह लंबे इंतजार, अलग-अलग दरों या रद्द किए गए ट्रेडों का कारण बन सकता है। हम बेहतर अनुभव के लिए अधिक शुल्क निर्धारित करने की सलाह देते हैं।", "ignor": "नज़रअंदाज़ करना", "use_suggested": "सुझाए गए का प्रयोग करें", - "do_not_share_warning_text" : "इन्हें समर्थन सहित किसी और के साथ साझा न करें।\n\nवे आपका पैसा चुरा लेंगे!", + "do_not_share_warning_text" : "समर्थन सहित, इन्हें किसी और के साथ साझा न करें।\n\nआपके धन की चोरी हो सकती है और होगी!", "help": "मदद करना", "connection_sync": "कनेक्शन और सिंक", "security_and_backup": "सुरक्षा और बैकअप", @@ -664,5 +664,13 @@ "require_pin_after": "इसके बाद पिन आवश्यक है", "always": "हमेशा", "minutes_to_pin_code": "${minute} मिनट", - "disable_exchange": "एक्सचेंज अक्षम करें" + "disable_exchange": "एक्सचेंज अक्षम करें", + "advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स", + "settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है", + "add_custom_node": "नया कस्टम नोड जोड़ें", + "disable_exchange": "एक्सचेंज अक्षम करें", + "fiat_api": "फिएट पैसे API", + "disabled": "अक्षम", + "enabled": "सक्रिय", + "tor_only": "Tor केवल" } diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 115f2f3fc..db6526c19 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -652,7 +652,7 @@ "low_fee_alert": "Trenutačno koristite niski prioritet mrežne naknade. To bi moglo uzrokovati duga čekanja, različite tečajeve ili otkazane trgovine. Preporučujemo postavljanje veće naknade za bolje iskustvo.", "ignor": "Zanemariti", "use_suggested": "Koristite predloženo", - "do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nUkrast će vam novac!", + "do_not_share_warning_text" : "Nemojte ih dijeliti ni s kim, uključujući podršku.\n\nVaša sredstva mogu i bit će ukradena!", "help": "pomozite", "connection_sync": "Povezivanje i sinkronizacija", "security_and_backup": "Sigurnost i sigurnosna kopija", @@ -664,5 +664,13 @@ "require_pin_after": "Zahtijevaj PIN nakon", "always": "Uvijek", "minutes_to_pin_code": "${minute} minuta", - "disable_exchange": "Onemogući exchange" + "disable_exchange": "Onemogući exchange", + "advanced_privacy_settings": "Napredne postavke privatnosti", + "settings_can_be_changed_later": "Te se postavke mogu promijeniti kasnije u postavkama aplikacije", + "add_custom_node": "Dodaj novi prilagođeni čvor", + "disable_fiat": "Isključi, fiat", + "fiat_api": "Fiat API", + "disabled": "Onemogućeno", + "enabled": "Omogućeno", + "tor_only": "Samo Tor" } diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index fffc765aa..a92401652 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -652,7 +652,7 @@ "low_fee_alert": "Attualmente stai utilizzando una priorità a tariffa di rete bassa. Ciò potrebbe causare lunghe attese, tariffe diverse o operazioni annullate. Ti consigliamo di impostare una tariffa più alta per un'esperienza migliore.", "ignor": "Ignorare", "use_suggested": "Usa suggerito", - "do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nTi ruberanno i soldi!", + "do_not_share_warning_text" : "Non condividerli con nessun altro, incluso il supporto.\n\nI tuoi fondi possono e saranno rubati!", "help": "aiuto", "connection_sync": "Connessione e sincronizzazione", "security_and_backup": "Sicurezza e backup", @@ -664,5 +664,13 @@ "require_pin_after": "Richiedi PIN dopo", "always": "sempre", "minutes_to_pin_code": "${minute} minuti", - "disable_exchange": "Disabilita scambio" + "disable_exchange": "Disabilita scambio", + "advanced_privacy_settings": "Impostazioni avanzate sulla privacy", + "settings_can_be_changed_later": "Queste impostazioni possono essere modificate in seguito nelle impostazioni dell'app", + "add_custom_node": "Aggiungi nuovo nodo personalizzato", + "disable_fiat": "Disabilita fiat", + "fiat_api": "Fiat API", + "disabled": "Disabilitato", + "enabled": "Abilitato", + "tor_only": "Solo Tor" } diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index bec36d01e..a7b647558 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -652,7 +652,7 @@ "low_fee_alert": "現在、低ネットワーク料金優先度を使用しています。これにより、長い待ち時間、異なるレート、またはキャンセルされた取引が発生する可能性があります。より良い体験のために、より高い料金を設定することをお勧めします。", "ignor": "無視", "use_suggested": "推奨を使用", - "do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\n彼らはあなたのお金を盗みます!", + "do_not_share_warning_text" : "サポートを含め、これらを他の誰とも共有しないでください。\n\nあなたの資金は盗まれる可能性があります!", "help": "ヘルプ", "connection_sync": "接続と同期", "security_and_backup": "セキュリティとバックアップ", @@ -664,5 +664,13 @@ "require_pin_after": "後に PIN が必要", "always": "いつも", "minutes_to_pin_code": "${minute} 分", - "disable_exchange": "交換を無効にする" + "disable_exchange": "交換を無効にする", + "advanced_privacy_settings": "高度なプライバシー設定", + "settings_can_be_changed_later": "これらの設定は、後でアプリの設定で変更できます", + "add_custom_node": "新しいカスタム ノードを追加", + "disable_fiat": "フィアットを無効にする", + "fiat_api": "不換紙幣 API", + "disabled": "無効", + "enabled": "有効", + "tor_only": "Torのみ" } diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 89c1df817..5966766f9 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -652,7 +652,7 @@ "low_fee_alert": "현재 낮은 네트워크 요금 우선 순위를 사용하고 있습니다. 이로 인해 긴 대기 시간, 다른 요금 또는 취소된 거래가 발생할 수 있습니다. 더 나은 경험을 위해 더 높은 요금을 설정하는 것이 좋습니다.", "ignor": "무시하다", "use_suggested": "추천 사용", - "do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n그들은 당신의 돈을 훔칠 것입니다!", + "do_not_share_warning_text" : "지원을 포함하여 다른 사람과 이러한 정보를 공유하지 마십시오.\n\n귀하의 자금은 도난당할 수 있고 도난당할 수 있습니다!", "help": "돕다", "connection_sync": "연결 및 동기화", "security_and_backup": "보안 및 백업", @@ -664,5 +664,13 @@ "require_pin_after": "다음 이후에 PIN 필요", "always": "언제나", "minutes_to_pin_code": "${minute}분", - "disable_exchange": "교환 비활성화" + "disable_exchange": "교환 비활성화", + "advanced_privacy_settings": "고급 개인 정보 설정", + "settings_can_be_changed_later": "이 설정은 나중에 앱 설정에서 변경할 수 있습니다.", + "add_custom_node": "새 사용자 정의 노드 추가", + "disable_fiat": "법정화폐 비활성화", + "fiat_api": "명목 화폐 API", + "disabled": "장애가 있는", + "enabled": "사용", + "tor_only": "Tor 뿐" } diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 636993d52..1d26afb93 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -652,7 +652,7 @@ "low_fee_alert": "U gebruikt momenteel een lage prioriteit voor netwerkkosten. Dit kan lange wachttijden, andere tarieven of geannuleerde transacties veroorzaken. We raden aan een hogere vergoeding in te stellen voor een betere ervaring.", "ignor": "Negeren", "use_suggested": "Gebruik aanbevolen", - "do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nZe zullen je geld stelen!", + "do_not_share_warning_text" : "Deel deze met niemand anders, ook niet met support.\n\nUw geld kan en zal worden gestolen!", "help": "helpen", "connection_sync": "Verbinding en synchronisatie", "security_and_backup": "Beveiliging en back-up", @@ -664,5 +664,13 @@ "require_pin_after": "Pincode vereist na", "always": "altijd", "minutes_to_pin_code": "${minute} minuten", - "disable_exchange": "Uitwisseling uitschakelen" + "disable_exchange": "Uitwisseling uitschakelen", + "advanced_privacy_settings": "Geavanceerde privacy-instellingen", + "settings_can_be_changed_later": "Deze instellingen kunnen later worden gewijzigd in de app-instellingen", + "add_custom_node": "Voeg een nieuw aangepast knooppunt toe", + "disable_fiat": "Schakel Fiat uit", + "fiat_api": "Fiat API", + "disabled": "Gehandicapt", + "enabled": "Ingeschakeld", + "tor_only": "Alleen Tor" } diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 6a61cd368..386de98b7 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -652,7 +652,7 @@ "low_fee_alert": "Obecnie korzystasz z niskiego priorytetu opłaty sieciowej. Może to spowodować długie oczekiwanie, różne stawki lub anulowane transakcje. Zalecamy ustawienie wyższej opłaty, aby zapewnić lepsze wrażenia.", "ignor": "Ignorować", "use_suggested": "Użyj sugerowane", - "do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym wsparcia.\n\nUkradną twoje pieniądze!", + "do_not_share_warning_text" : "Nie udostępniaj ich nikomu innemu, w tym pomocy.\n\nTwoje środki mogą i zostaną skradzione!", "help": "pomoc", "connection_sync": "Połączenie i synchronizacja", "security_and_backup": "Bezpieczeństwo i kopia zapasowa", @@ -664,5 +664,13 @@ "require_pin_after": "Wymagaj kodu PIN po", "always": "zawsze", "minutes_to_pin_code": "${minute} minut", - "disable_exchange": "Wyłącz wymianę" + "disable_exchange": "Wyłącz wymianę", + "advanced_privacy_settings": "Zaawansowane ustawienia prywatności", + "settings_can_be_changed_later": "Te ustawienia można później zmienić w ustawieniach aplikacji", + "add_custom_node": "Dodaj nowy węzeł niestandardowy", + "disable_fiat": "Wyłącz fiat", + "fiat_api": "API Fiata", + "disabled": "Wyłączone", + "enabled": "Włączony", + "tor_only": "Tylko Tor" } diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 41a235e33..38fd02c7e 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -651,7 +651,7 @@ "low_fee_alert": "No momento, você está usando uma prioridade de taxa de rede baixa. Isso pode causar longas esperas, taxas diferentes ou negociações canceladas. Recomendamos definir uma taxa mais alta para uma melhor experiência.", "ignor": "Ignorar", "use_suggested": "Uso sugerido", - "do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nEles vão roubar seu dinheiro!", + "do_not_share_warning_text" : "Não os compartilhe com mais ninguém, incluindo suporte.\n\nSeus fundos podem e serão roubados!", "help": "ajuda", "connection_sync": "Conexão e sincronização", "security_and_backup": "Segurança e backup", @@ -663,5 +663,13 @@ "require_pin_after": "Exigir PIN após", "always": "sempre", "minutes_to_pin_code": "${minute} minutos", - "disable_exchange": "Desativar troca" + "disable_exchange": "Desativar troca", + "advanced_privacy_settings": "Configurações de privacidade avançadas", + "settings_can_be_changed_later": "Essas configurações podem ser alteradas posteriormente nas configurações do aplicativo", + "add_custom_node": "Adicionar novo nó personalizado", + "disable_fiat": "Desativar fiat", + "fiat_api": "API da Fiat", + "disabled": "Desabilitado", + "enabled": "Habilitado", + "tor_only": "Tor apenas" } diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 76a10750a..3d1ac3945 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -652,7 +652,7 @@ "low_fee_alert": "В настоящее время вы используете низкий приоритет платы за сеть. Это может привести к длительному ожиданию, изменению ставок или отмене сделок. Мы рекомендуем установить более высокую плату для лучшего опыта.", "ignor": "Игнорировать", "use_suggested": "Использовать предложенный", - "do_not_share_warning_text" : "Не делитесь ими с кем-либо еще, в том числе со службой поддержки.\n\nОни украдут ваши деньги!", + "do_not_share_warning_text" : "Не сообщайте их никому, включая техподдержку.\n\nВаши средства могут и будут украдены!", "help": "помощь", "connection_sync": "Подключение и синхронизация", "security_and_backup": "Безопасность и резервное копирование", @@ -664,5 +664,13 @@ "require_pin_after": "Требовать ПИН после", "always": "всегда", "minutes_to_pin_code": "${minute} минут", - "disable_exchange": "Отключить обмен" + "disable_exchange": "Отключить обмен", + "advanced_privacy_settings": "Расширенные настройки конфиденциальности", + "settings_can_be_changed_later": "Эти настройки можно изменить позже в настройках приложения.", + "add_custom_node": "Добавить новый пользовательский узел", + "disable_fiat": "Отключить фиат", + "fiat_api": "Фиат API", + "disabled": "Отключено", + "enabled": "Включено", + "tor_only": "Только Tor" } diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 215e003c0..03dd263ec 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -651,7 +651,7 @@ "low_fee_alert": "Зараз ви використовуєте низький пріоритет плати за мережу. Це може спричинити тривале очікування, інший курс або скасування угод. Ми рекомендуємо встановити вищу плату для кращого досвіду.", "ignor": "Ігнорувати", "use_suggested": "Використати запропоноване", - "do_not_share_warning_text" : "Не повідомляйте їх нікому, включно зі службою підтримки.\n\nВони вкрадуть ваші гроші!", + "do_not_share_warning_text" : "Не діліться цим нікому, включно зі службою підтримки.\n\nВаші кошти можуть і будуть вкрадені!", "help": "допомога", "connection_sync": "Підключення та синхронізація", "security_and_backup": "Безпека та резервне копіювання", @@ -663,5 +663,14 @@ "require_pin_after": "Вимагати PIN після", "always": "Завжди", "minutes_to_pin_code": "${minute} хвилин", - "disable_exchange": "Вимкнути exchange" + "disable_exchange": "Вимкнути exchange", + "advanced_privacy_settings": "Розширені налаштування конфіденційності", + "settings_can_be_changed_later": "Ці параметри можна змінити пізніше в налаштуваннях програми", + "add_custom_node": "Додати новий спеціальний вузол", + "disable_fiat": "Вимкнути фиат", + "fiat_api": "Фіат API", + "disabled": "Вимкнено", + "enabled": "Увімкнено", + "tor_only": "Тільки Tor" + } diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index a3bb9af88..40ea2e18a 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -650,7 +650,7 @@ "low_fee_alert": "您当前正在使用低网络费用优先级。这可能会导致长时间等待、不同的费率或取消交易。我们建议设置更高的费用以获得更好的体验。", "ignor": "忽视", "use_suggested": "使用建议", - "do_not_share_warning_text" : "不要與其他任何人分享這些內容,包括支持。\n\n他們會偷你的錢!", + "do_not_share_warning_text" : "请勿与其他任何人分享这些信息,包括支持人员。\n\n您的资金可能而且将会被盗!", "help": "帮助", "connection_sync": "连接和同步", "security_and_backup": "安全和备份", @@ -662,5 +662,13 @@ "require_pin_after": "之后需要 PIN", "always": "总是", "minutes_to_pin_code": "${minute} 分钟", - "disable_exchange": "禁用交换" + "disable_exchange": "禁用交换", + "advanced_privacy_settings": "高级隐私设置", + "settings_can_be_changed_later": "稍后可以在应用设置中更改这些设置", + "add_custom_node": "添加新的自定义节点", + "disable_fiat": "禁用法令", + "fiat_api": "法币API", + "disabled": "禁用", + "enabled": "启用", + "tor_only": "仅限 Tor" } diff --git a/tool/configure.dart b/tool/configure.dart index 0d3d175c4..5ae5a2111 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -75,6 +75,7 @@ abstract class Bitcoin { List getTransactionPriorities(); List getLitecoinTransactionPriorities(); TransactionPriority deserializeBitcoinTransactionPriority(int raw); + TransactionPriority deserializeLitecoinTransactionPriority(int raw); int getFeeRate(Object wallet, TransactionPriority priority); Future generateNewAddress(Object wallet); Object createBitcoinTransactionCredentials(List outputs, {required TransactionPriority priority, int? feeRate});