import React, { createContext, useCallback, useEffect, useMemo, useState } from 'react'; import DefaultPreference from 'react-native-default-preference'; import { isReadClipboardAllowed, setReadClipboardAllowed } from '../../blue_modules/clipboard'; import { getPreferredCurrency, GROUP_IO_BLUEWALLET, initCurrencyDaemon, PREFERRED_CURRENCY_STORAGE_KEY } from '../../blue_modules/currency'; import { clearUseURv1, isURv1Enabled, setUseURv1 } from '../../blue_modules/ur'; import { BlueApp } from '../../class'; import { saveLanguage, STORAGE_KEY } from '../../loc'; import { FiatUnit, TFiatUnit } from '../../models/fiatUnit'; import { getEnabled as getIsDeviceQuickActionsEnabled, setEnabled as setIsDeviceQuickActionsEnabled } from '../DeviceQuickActions'; import { getIsHandOffUseEnabled, setIsHandOffUseEnabled } from '../HandOffComponent'; import { useStorage } from '../../hooks/context/useStorage'; import { BitcoinUnit } from '../../models/bitcoinUnits'; import { TotalWalletsBalanceKey, TotalWalletsBalancePreferredUnit } from '../TotalWalletsBalance'; import { BLOCK_EXPLORERS, getBlockExplorerUrl, saveBlockExplorer, BlockExplorer, normalizeUrl } from '../../models/blockExplorer'; import * as BlueElectrum from '../../blue_modules/BlueElectrum'; import { isBalanceDisplayAllowed, setBalanceDisplayAllowed } from '../../hooks/useWidgetCommunication'; import AsyncStorage from '@react-native-async-storage/async-storage'; const getDoNotTrackStorage = async (): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); const doNotTrack = await DefaultPreference.get(BlueApp.DO_NOT_TRACK); return doNotTrack === '1'; } catch { console.error('Error getting DoNotTrack'); return false; } }; export const setTotalBalanceViewEnabledStorage = async (value: boolean): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); await DefaultPreference.set(TotalWalletsBalanceKey, value ? 'true' : 'false'); console.debug('setTotalBalanceViewEnabledStorage value:', value); } catch (e) { console.error('Error setting TotalBalanceViewEnabled:', e); } }; export const getIsTotalBalanceViewEnabled = async (): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); const isEnabledValue = (await DefaultPreference.get(TotalWalletsBalanceKey)) ?? 'true'; console.debug('getIsTotalBalanceViewEnabled', isEnabledValue); return isEnabledValue === 'true'; } catch (e) { console.error('Error getting TotalBalanceViewEnabled:', e); return true; } }; export const setTotalBalancePreferredUnitStorageFunc = async (unit: BitcoinUnit): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); await DefaultPreference.set(TotalWalletsBalancePreferredUnit, unit); } catch (e) { console.error('Error setting TotalBalancePreferredUnit:', e); } }; export const getTotalBalancePreferredUnit = async (): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); const unit = (await DefaultPreference.get(TotalWalletsBalancePreferredUnit)) as BitcoinUnit | null; return unit ?? BitcoinUnit.BTC; } catch (e) { console.error('Error getting TotalBalancePreferredUnit:', e); return BitcoinUnit.BTC; } }; interface SettingsContextType { preferredFiatCurrency: TFiatUnit; setPreferredFiatCurrencyStorage: (currency: TFiatUnit) => Promise; language: string; setLanguageStorage: (language: string) => Promise; isHandOffUseEnabled: boolean; setIsHandOffUseEnabledAsyncStorage: (value: boolean) => Promise; isPrivacyBlurEnabled: boolean; setIsPrivacyBlurEnabled: (value: boolean) => void; isDoNotTrackEnabled: boolean; setDoNotTrackStorage: (value: boolean) => Promise; isWidgetBalanceDisplayAllowed: boolean; setIsWidgetBalanceDisplayAllowedStorage: (value: boolean) => Promise; isLegacyURv1Enabled: boolean; setIsLegacyURv1EnabledStorage: (value: boolean) => Promise; isClipboardGetContentEnabled: boolean; setIsClipboardGetContentEnabledStorage: (value: boolean) => Promise; isQuickActionsEnabled: boolean; setIsQuickActionsEnabledStorage: (value: boolean) => Promise; isTotalBalanceEnabled: boolean; setIsTotalBalanceEnabledStorage: (value: boolean) => Promise; totalBalancePreferredUnit: BitcoinUnit; setTotalBalancePreferredUnitStorage: (unit: BitcoinUnit) => Promise; isDrawerShouldHide: boolean; setIsDrawerShouldHide: (value: boolean) => void; selectedBlockExplorer: BlockExplorer; setBlockExplorerStorage: (explorer: BlockExplorer) => Promise; isElectrumDisabled: boolean; setIsElectrumDisabled: (value: boolean) => void; } const defaultSettingsContext: SettingsContextType = { preferredFiatCurrency: FiatUnit.USD, setPreferredFiatCurrencyStorage: async () => {}, language: 'en', setLanguageStorage: async () => {}, isHandOffUseEnabled: false, setIsHandOffUseEnabledAsyncStorage: async () => {}, isPrivacyBlurEnabled: true, setIsPrivacyBlurEnabled: () => {}, isDoNotTrackEnabled: false, setDoNotTrackStorage: async () => {}, isWidgetBalanceDisplayAllowed: true, setIsWidgetBalanceDisplayAllowedStorage: async () => {}, isLegacyURv1Enabled: false, setIsLegacyURv1EnabledStorage: async () => {}, isClipboardGetContentEnabled: true, setIsClipboardGetContentEnabledStorage: async () => {}, isQuickActionsEnabled: true, setIsQuickActionsEnabledStorage: async () => {}, isTotalBalanceEnabled: true, setIsTotalBalanceEnabledStorage: async () => {}, totalBalancePreferredUnit: BitcoinUnit.BTC, setTotalBalancePreferredUnitStorage: async () => {}, isDrawerShouldHide: false, setIsDrawerShouldHide: () => {}, selectedBlockExplorer: BLOCK_EXPLORERS.default, setBlockExplorerStorage: async () => false, isElectrumDisabled: false, setIsElectrumDisabled: () => {}, }; export const SettingsContext = createContext(defaultSettingsContext); export const SettingsProvider: React.FC<{ children: React.ReactNode }> = React.memo(({ children }) => { const [preferredFiatCurrency, setPreferredFiatCurrency] = useState(FiatUnit.USD); const [language, setLanguage] = useState('en'); const [isHandOffUseEnabled, setIsHandOffUseEnabledState] = useState(false); const [isPrivacyBlurEnabled, setIsPrivacyBlurEnabled] = useState(true); const [isDoNotTrackEnabled, setIsDoNotTrackEnabled] = useState(false); const [isWidgetBalanceDisplayAllowed, setIsWidgetBalanceDisplayAllowed] = useState(true); const [isLegacyURv1Enabled, setIsLegacyURv1Enabled] = useState(false); const [isClipboardGetContentEnabled, setIsClipboardGetContentEnabled] = useState(true); const [isQuickActionsEnabled, setIsQuickActionsEnabled] = useState(true); const [isTotalBalanceEnabled, setIsTotalBalanceEnabled] = useState(true); const [totalBalancePreferredUnit, setTotalBalancePreferredUnit] = useState(BitcoinUnit.BTC); const [isDrawerShouldHide, setIsDrawerShouldHide] = useState(false); const [selectedBlockExplorer, setSelectedBlockExplorer] = useState(BLOCK_EXPLORERS.default); const [isElectrumDisabled, setIsElectrumDisabled] = useState(true); const { walletsInitialized } = useStorage(); useEffect(() => { const loadSettings = async () => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); } catch (e) { console.error('Error setting preference name:', e); } const promises: Promise[] = [ BlueElectrum.isDisabled().then(disabled => { setIsElectrumDisabled(disabled); }), getIsHandOffUseEnabled().then(handOff => { setIsHandOffUseEnabledState(handOff); }), AsyncStorage.getItem(STORAGE_KEY).then(lang => { setLanguage(lang ?? 'en'); }), isBalanceDisplayAllowed().then(balanceDisplayAllowed => { setIsWidgetBalanceDisplayAllowed(balanceDisplayAllowed); }), isURv1Enabled().then(urv1Enabled => { setIsLegacyURv1Enabled(urv1Enabled); }), isReadClipboardAllowed().then(clipboardEnabled => { setIsClipboardGetContentEnabled(clipboardEnabled); }), getIsDeviceQuickActionsEnabled().then(quickActionsEnabled => { setIsQuickActionsEnabled(quickActionsEnabled); }), getDoNotTrackStorage().then(doNotTrack => { setIsDoNotTrackEnabled(doNotTrack); }), getIsTotalBalanceViewEnabled().then(totalBalanceEnabled => { setIsTotalBalanceEnabled(totalBalanceEnabled); }), getTotalBalancePreferredUnit().then(preferredUnit => { setTotalBalancePreferredUnit(preferredUnit); }), getBlockExplorerUrl().then(url => { const predefinedExplorer = Object.values(BLOCK_EXPLORERS).find(explorer => normalizeUrl(explorer.url) === normalizeUrl(url)); setSelectedBlockExplorer(predefinedExplorer ?? ({ key: 'custom', name: 'Custom', url } as BlockExplorer)); }), ]; const results = await Promise.allSettled(promises); results.forEach((result, index) => { if (result.status === 'rejected') { console.error(`Error loading setting ${index}:`, result.reason); } }); }; loadSettings(); }, []); useEffect(() => { if (walletsInitialized) { initCurrencyDaemon() .then(getPreferredCurrency) .then(currency => { console.debug('SettingsContext currency:', currency); setPreferredFiatCurrency(currency as TFiatUnit); }) .catch(e => { console.error('Error initializing currency daemon or getting preferred currency:', e); }); } }, [walletsInitialized]); useEffect(() => { if (walletsInitialized) { isElectrumDisabled ? BlueElectrum.forceDisconnect() : BlueElectrum.connectMain(); } }, [isElectrumDisabled, walletsInitialized]); const setPreferredFiatCurrencyStorage = useCallback(async (currency: TFiatUnit): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, currency.endPointKey); setPreferredFiatCurrency(currency); } catch (e) { console.error('Error setting preferredFiatCurrency:', e); } }, []); const setLanguageStorage = useCallback(async (newLanguage: string): Promise => { try { await saveLanguage(newLanguage); setLanguage(newLanguage); } catch (e) { console.error('Error setting language:', e); } }, []); const setDoNotTrackStorage = useCallback(async (value: boolean): Promise => { try { await DefaultPreference.setName(GROUP_IO_BLUEWALLET); if (value) { await DefaultPreference.set(BlueApp.DO_NOT_TRACK, '1'); } else { await DefaultPreference.clear(BlueApp.DO_NOT_TRACK); } setIsDoNotTrackEnabled(value); } catch (e) { console.error('Error setting DoNotTrack:', e); } }, []); const setIsHandOffUseEnabledAsyncStorage = useCallback(async (value: boolean): Promise => { try { console.debug('setIsHandOffUseEnabledAsyncStorage', value); await setIsHandOffUseEnabled(value); setIsHandOffUseEnabledState(value); } catch (e) { console.error('Error setting isHandOffUseEnabled:', e); } }, []); const setIsWidgetBalanceDisplayAllowedStorage = useCallback(async (value: boolean): Promise => { try { await setBalanceDisplayAllowed(value); setIsWidgetBalanceDisplayAllowed(value); } catch (e) { console.error('Error setting isWidgetBalanceDisplayAllowed:', e); } }, []); const setIsLegacyURv1EnabledStorage = useCallback(async (value: boolean): Promise => { try { if (value) { await setUseURv1(); } else { await clearUseURv1(); } setIsLegacyURv1Enabled(value); } catch (e) { console.error('Error setting isLegacyURv1Enabled:', e); } }, []); const setIsClipboardGetContentEnabledStorage = useCallback(async (value: boolean): Promise => { try { await setReadClipboardAllowed(value); setIsClipboardGetContentEnabled(value); } catch (e) { console.error('Error setting isClipboardGetContentEnabled:', e); } }, []); const setIsQuickActionsEnabledStorage = useCallback(async (value: boolean): Promise => { try { await setIsDeviceQuickActionsEnabled(value); setIsQuickActionsEnabled(value); } catch (e) { console.error('Error setting isQuickActionsEnabled:', e); } }, []); const setIsTotalBalanceEnabledStorage = useCallback(async (value: boolean): Promise => { try { await setTotalBalanceViewEnabledStorage(value); setIsTotalBalanceEnabled(value); } catch (e) { console.error('Error setting isTotalBalanceEnabled:', e); } }, []); const setTotalBalancePreferredUnitStorage = useCallback(async (unit: BitcoinUnit): Promise => { try { await setTotalBalancePreferredUnitStorageFunc(unit); setTotalBalancePreferredUnit(unit); } catch (e) { console.error('Error setting totalBalancePreferredUnit:', e); } }, []); const setBlockExplorerStorage = useCallback(async (explorer: BlockExplorer): Promise => { try { const success = await saveBlockExplorer(explorer.url); if (success) { setSelectedBlockExplorer(explorer); } return success; } catch (e) { console.error('Error setting BlockExplorer:', e); return false; } }, []); const value = useMemo( () => ({ preferredFiatCurrency, setPreferredFiatCurrencyStorage, language, setLanguageStorage, isHandOffUseEnabled, setIsHandOffUseEnabledAsyncStorage, isPrivacyBlurEnabled, setIsPrivacyBlurEnabled, isDoNotTrackEnabled, setDoNotTrackStorage, isWidgetBalanceDisplayAllowed, setIsWidgetBalanceDisplayAllowedStorage, isLegacyURv1Enabled, setIsLegacyURv1EnabledStorage, isClipboardGetContentEnabled, setIsClipboardGetContentEnabledStorage, isQuickActionsEnabled, setIsQuickActionsEnabledStorage, isTotalBalanceEnabled, setIsTotalBalanceEnabledStorage, totalBalancePreferredUnit, setTotalBalancePreferredUnitStorage, isDrawerShouldHide, setIsDrawerShouldHide, selectedBlockExplorer, setBlockExplorerStorage, isElectrumDisabled, setIsElectrumDisabled, }), [ preferredFiatCurrency, setPreferredFiatCurrencyStorage, language, setLanguageStorage, isHandOffUseEnabled, setIsHandOffUseEnabledAsyncStorage, isPrivacyBlurEnabled, setIsPrivacyBlurEnabled, isDoNotTrackEnabled, setDoNotTrackStorage, isWidgetBalanceDisplayAllowed, setIsWidgetBalanceDisplayAllowedStorage, isLegacyURv1Enabled, setIsLegacyURv1EnabledStorage, isClipboardGetContentEnabled, setIsClipboardGetContentEnabledStorage, isQuickActionsEnabled, setIsQuickActionsEnabledStorage, isTotalBalanceEnabled, setIsTotalBalanceEnabledStorage, totalBalancePreferredUnit, setTotalBalancePreferredUnitStorage, isDrawerShouldHide, setIsDrawerShouldHide, selectedBlockExplorer, setBlockExplorerStorage, isElectrumDisabled, ], ); return {children}; });