import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_list.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:package_info/package_info.dart'; import 'package:cake_wallet/di.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/entities/balance_display_mode.dart'; 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:cw_core/set_app_secure_native.dart'; import 'dart:io' show Platform; part 'settings_store.g.dart'; class SettingsStore = SettingsStoreBase with _$SettingsStore; abstract class SettingsStoreBase with Store { SettingsStoreBase( {required SharedPreferences sharedPreferences, required bool initialShouldShowMarketPlaceInDashboard, required FiatCurrency initialFiatCurrency, required BalanceDisplayMode initialBalanceDisplayMode, required bool initialSaveRecipientAddress, required bool initialAppSecure, required FiatApiMode initialFiatMode, required bool initialAllowBiometricalAuthentication, required bool initialShowHistoricalFiatRate, required ExchangeApiMode initialExchangeStatus, required ThemeBase initialTheme, required int initialPinLength, required String initialLanguageCode, // required String initialCurrentLocale, required this.appVersion, required Map nodes, required this.shouldShowYatPopup, required this.isBitcoinBuyEnabled, required this.actionlistDisplayMode, required this.pinTimeOutDuration, TransactionPriority? initialBitcoinTransactionPriority, TransactionPriority? initialMoneroTransactionPriority, TransactionPriority? initialHavenTransactionPriority, TransactionPriority? initialLitecoinTransactionPriority}) : nodes = ObservableMap.of(nodes), _sharedPreferences = sharedPreferences, fiatCurrency = initialFiatCurrency, balanceDisplayMode = initialBalanceDisplayMode, shouldSaveRecipientAddress = initialSaveRecipientAddress, isAppSecure = initialAppSecure, fiatApiMode = initialFiatMode, allowBiometricalAuthentication = initialAllowBiometricalAuthentication, showHistoricalFiatRate = initialShowHistoricalFiatRate, shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard, exchangeStatus = initialExchangeStatus, currentTheme = initialTheme, pinCodeLength = initialPinLength, languageCode = initialLanguageCode, priority = ObservableMap() { //this.nodes = ObservableMap.of(nodes); if (initialMoneroTransactionPriority != null) { priority[WalletType.monero] = initialMoneroTransactionPriority; } if (initialBitcoinTransactionPriority != null) { priority[WalletType.bitcoin] = initialBitcoinTransactionPriority; } if (initialHavenTransactionPriority != null) { priority[WalletType.haven] = initialHavenTransactionPriority; } if (initialLitecoinTransactionPriority != null) { priority[WalletType.litecoin] = initialLitecoinTransactionPriority; } reaction( (_) => fiatCurrency, (FiatCurrency fiatCurrency) => sharedPreferences.setString( PreferencesKey.currentFiatCurrencyKey, fiatCurrency.serialize())); reaction( (_) => shouldShowYatPopup, (bool shouldShowYatPopup) => sharedPreferences .setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup)); priority.observe((change) { 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 && key != null) { sharedPreferences.setInt(key, change.newValue!.serialize()); } }); reaction( (_) => shouldSaveRecipientAddress, (bool shouldSaveRecipientAddress) => sharedPreferences.setBool( PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress)); reaction((_) => isAppSecure, (bool isAppSecure) { sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure); if (Platform.isAndroid) { setIsAppSecureNative(isAppSecure); } }); if (Platform.isAndroid) { setIsAppSecureNative(isAppSecure); } reaction( (_) => fiatApiMode, (FiatApiMode mode) => sharedPreferences.setInt( PreferencesKey.currentFiatApiModeKey, mode.serialize())); reaction( (_) => currentTheme, (ThemeBase theme) => sharedPreferences.setInt(PreferencesKey.currentTheme, theme.raw)); reaction( (_) => allowBiometricalAuthentication, (bool biometricalAuthentication) => sharedPreferences.setBool( PreferencesKey.allowBiometricalAuthenticationKey, biometricalAuthentication)); reaction( (_) => showHistoricalFiatRate, (bool historicalFiatRate) => sharedPreferences.setBool( PreferencesKey.showHistoricalFiatRateKey, historicalFiatRate)); reaction( (_) => shouldShowMarketPlaceInDashboard, (bool value) => sharedPreferences.setBool(PreferencesKey.shouldShowMarketPlaceInDashboard, value)); reaction( (_) => pinCodeLength, (int pinLength) => sharedPreferences.setInt( PreferencesKey.currentPinLength, pinLength)); reaction( (_) => languageCode, (String languageCode) => sharedPreferences.setString( PreferencesKey.currentLanguageCode, languageCode)); reaction( (_) => pinTimeOutDuration, (PinCodeRequiredDuration pinCodeInterval) => sharedPreferences.setInt( PreferencesKey.pinTimeOutDuration, pinCodeInterval.value)); reaction( (_) => balanceDisplayMode, (BalanceDisplayMode mode) => sharedPreferences.setInt( PreferencesKey.currentBalanceDisplayModeKey, mode.serialize())); reaction( (_) => exchangeStatus, (ExchangeApiMode mode) => sharedPreferences.setInt( PreferencesKey.exchangeStatusKey, mode.serialize())); this .nodes .observe((change) { if (change.newValue != null && change.key != null) { _saveCurrentNode(change.newValue!, change.key!); } }); } static const defaultPinLength = 4; static const defaultActionsMode = 11; static const defaultPinCodeTimeOutDuration = PinCodeRequiredDuration.tenminutes; @observable FiatCurrency fiatCurrency; @observable bool shouldShowYatPopup; @observable bool shouldShowMarketPlaceInDashboard; @observable ObservableList actionlistDisplayMode; @observable BalanceDisplayMode balanceDisplayMode; @observable FiatApiMode fiatApiMode; @observable bool shouldSaveRecipientAddress; @observable bool isAppSecure; @observable bool allowBiometricalAuthentication; @observable bool showHistoricalFiatRate; @observable ExchangeApiMode exchangeStatus; @observable ThemeBase currentTheme; @observable int pinCodeLength; @observable PinCodeRequiredDuration pinTimeOutDuration; @computed ThemeData get theme => currentTheme.themeData; @observable String languageCode; @observable ObservableMap priority; String appVersion; SharedPreferences _sharedPreferences; ObservableMap nodes; Node getCurrentNode(WalletType walletType) { final node = nodes[walletType]; if (node == null) { throw Exception('No node found for wallet type: ${walletType.toString()}'); } return node; } bool isBitcoinBuyEnabled; bool get shouldShowReceiveWarning => _sharedPreferences.getBool(PreferencesKey.shouldShowReceiveWarning) ?? true; Future setShouldShowReceiveWarning(bool value) async => _sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value); static Future load( {required Box nodeSource, required bool isBitcoinBuyEnabled, FiatCurrency initialFiatCurrency = FiatCurrency.usd, BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance, ThemeBase? initialTheme}) async { final sharedPreferences = await getIt.getAsync(); final currentFiatCurrency = FiatCurrency.deserialize(raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!); TransactionPriority? moneroTransactionPriority = monero?.deserializeMoneroTransactionPriority( raw: sharedPreferences .getInt(PreferencesKey.moneroTransactionPriority)!); TransactionPriority? bitcoinTransactionPriority = bitcoin?.deserializeBitcoinTransactionPriority(sharedPreferences .getInt(PreferencesKey.bitcoinTransactionPriority)!); 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 isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false; final currentFiatApiMode = FiatApiMode.deserialize( raw: sharedPreferences .getInt(PreferencesKey.currentFiatApiModeKey) ?? FiatApiMode.enabled.raw); final allowBiometricalAuthentication = sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? false; final showHistoricalFiatRate = sharedPreferences .getBool(PreferencesKey.showHistoricalFiatRateKey) ?? false; final shouldShowMarketPlaceInDashboard = sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? true; final exchangeStatus = ExchangeApiMode.deserialize( raw: sharedPreferences .getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) ? ThemeType.dark.index : ThemeType.bright.index; final savedTheme = initialTheme ?? ThemeList.deserialize( raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? legacyTheme); final actionListDisplayMode = ObservableList(); actionListDisplayMode.addAll(deserializeActionlistDisplayModes( sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode)); var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength); final timeOutDuration = sharedPreferences.getInt(PreferencesKey.pinTimeOutDuration); final pinCodeTimeOutDuration = timeOutDuration != null ? PinCodeRequiredDuration.deserialize(raw: timeOutDuration) : defaultPinCodeTimeOutDuration; // If no value if (pinLength == null || pinLength == 0) { pinLength = defaultPinLength; } final savedLanguageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? await LanguageService.localeDetection(); final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); final bitcoinElectrumServerId = sharedPreferences .getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); final litecoinElectrumServerId = sharedPreferences .getInt(PreferencesKey.currentLitecoinElectrumSererIdKey); final havenNodeId = sharedPreferences .getInt(PreferencesKey.currentHavenNodeIdKey); final moneroNode = nodeSource.get(nodeId); final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId); final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId); final havenNode = nodeSource.get(havenNodeId); final packageInfo = await PackageInfo.fromPlatform(); final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true; final nodes = {}; if (moneroNode != null) { nodes[WalletType.monero] = moneroNode; } if (bitcoinElectrumServer != null) { nodes[WalletType.bitcoin] = bitcoinElectrumServer; } if (litecoinElectrumServer != null) { nodes[WalletType.litecoin] = litecoinElectrumServer; } if (havenNode != null) { nodes[WalletType.haven] = havenNode; } return SettingsStore( sharedPreferences: sharedPreferences, initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard, nodes: nodes, appVersion: packageInfo.version, isBitcoinBuyEnabled: isBitcoinBuyEnabled, initialFiatCurrency: currentFiatCurrency, initialBalanceDisplayMode: currentBalanceDisplayMode, initialSaveRecipientAddress: shouldSaveRecipientAddress, initialAppSecure: isAppSecure, initialFiatMode: currentFiatApiMode, initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialShowHistoricalFiatRate: showHistoricalFiatRate, initialExchangeStatus: exchangeStatus, initialTheme: savedTheme, actionlistDisplayMode: actionListDisplayMode, initialPinLength: pinLength, pinTimeOutDuration: pinCodeTimeOutDuration, initialLanguageCode: savedLanguageCode, initialMoneroTransactionPriority: moneroTransactionPriority, initialBitcoinTransactionPriority: bitcoinTransactionPriority, initialHavenTransactionPriority: havenTransactionPriority, initialLitecoinTransactionPriority: litecoinTransactionPriority, shouldShowYatPopup: shouldShowYatPopup); } Future reload({required Box nodeSource}) async { final sharedPreferences = await getIt.getAsync(); fiatCurrency = FiatCurrency.deserialize( raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!); priority[WalletType.monero] = monero?.deserializeMoneroTransactionPriority( raw: sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ?? priority[WalletType.monero]!; priority[WalletType.bitcoin] = bitcoin?.deserializeBitcoinTransactionPriority( sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority)!) ?? priority[WalletType.bitcoin]!; if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) { priority[WalletType.haven] = monero?.deserializeMoneroTransactionPriority( raw: sharedPreferences.getInt(PreferencesKey.havenTransactionPriority)!) ?? priority[WalletType.haven]!; } if (sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority) != null) { priority[WalletType.litecoin] = bitcoin?.deserializeLitecoinTransactionPriority( sharedPreferences.getInt(PreferencesKey.litecoinTransactionPriority)!) ?? priority[WalletType.litecoin]!; } balanceDisplayMode = BalanceDisplayMode.deserialize( raw: sharedPreferences .getInt(PreferencesKey.currentBalanceDisplayModeKey)!); shouldSaveRecipientAddress = sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey) ?? shouldSaveRecipientAddress; isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure; allowBiometricalAuthentication = sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? allowBiometricalAuthentication; showHistoricalFiatRate = sharedPreferences .getBool(PreferencesKey.showHistoricalFiatRateKey) ?? showHistoricalFiatRate; shouldShowMarketPlaceInDashboard = sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? shouldShowMarketPlaceInDashboard; exchangeStatus = ExchangeApiMode.deserialize( raw: sharedPreferences .getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) ? ThemeType.dark.index : ThemeType.bright.index; currentTheme = ThemeList.deserialize( raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ?? legacyTheme); actionlistDisplayMode = ObservableList(); actionlistDisplayMode.addAll(deserializeActionlistDisplayModes( sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ?? defaultActionsMode)); var pinLength = sharedPreferences.getInt(PreferencesKey.currentPinLength); // If no value if (pinLength == null || pinLength == 0) { pinLength = pinCodeLength; } pinCodeLength = pinLength; languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode; shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup; final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); final bitcoinElectrumServerId = sharedPreferences .getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); final litecoinElectrumServerId = sharedPreferences .getInt(PreferencesKey.currentLitecoinElectrumSererIdKey); final havenNodeId = sharedPreferences .getInt(PreferencesKey.currentHavenNodeIdKey); final moneroNode = nodeSource.get(nodeId); final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId); final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId); final havenNode = nodeSource.get(havenNodeId); if (moneroNode != null) { nodes[WalletType.monero] = moneroNode; } if (bitcoinElectrumServer != null) { nodes[WalletType.bitcoin] = bitcoinElectrumServer; } if (litecoinElectrumServer != null) { nodes[WalletType.litecoin] = litecoinElectrumServer; } if (havenNode != null) { nodes[WalletType.haven] = havenNode; } } Future _saveCurrentNode(Node node, WalletType walletType) async { switch (walletType) { case WalletType.bitcoin: await _sharedPreferences.setInt( PreferencesKey.currentBitcoinElectrumSererIdKey, node.key as int); break; case WalletType.litecoin: await _sharedPreferences.setInt( PreferencesKey.currentLitecoinElectrumSererIdKey, node.key as int); break; case WalletType.monero: await _sharedPreferences.setInt( PreferencesKey.currentNodeIdKey, node.key as int); break; case WalletType.haven: await _sharedPreferences.setInt( PreferencesKey.currentHavenNodeIdKey, node.key as int); break; default: break; } nodes[walletType] = node; } }