diff --git a/.github/workflows/build-release-apk.yml b/.github/workflows/build-release-apk.yml index a5e6336f5..b23c04b24 100644 --- a/.github/workflows/build-release-apk.yml +++ b/.github/workflows/build-release-apk.yml @@ -40,14 +40,28 @@ jobs: - name: Install node_modules run: npm install --production + - name: Extract Version Name + id: version_name + run: | + VERSION_NAME=$(grep versionName android/app/build.gradle | awk '{print $2}' | tr -d '"') + echo "VERSION_NAME=$VERSION_NAME" >> $GITHUB_ENV + echo "::set-output name=version_name::$VERSION_NAME" + + - name: Generate Build Number based on timestamp + run: | + NEW_BUILD_NUMBER=$(date +%s) + echo "NEW_BUILD_NUMBER=$NEW_BUILD_NUMBER" >> $GITHUB_ENV + echo "::set-output name=build_number::$NEW_BUILD_NUMBER" + - name: Build env: KEYSTORE_FILE_HEX: ${{ secrets.KEYSTORE_FILE_HEX }} KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }} + BUILD_NUMBER: ${{ env.NEW_BUILD_NUMBER }} run: ./scripts/build-release-apk.sh - uses: actions/upload-artifact@v2 if: success() with: - name: apk - path: ./android/app/build/outputs/apk/release/app-release.apk + name: BlueWallet-${{ env.VERSION_NAME }}(${{ env.NEW_BUILD_NUMBER }}).apk + path: ./android/app/build/outputs/apk/release/BlueWallet-${{ env.VERSION_NAME }}(${{ env.NEW_BUILD_NUMBER }}).apk diff --git a/UnlockWith.js b/UnlockWith.js deleted file mode 100644 index 7dc43e290..000000000 --- a/UnlockWith.js +++ /dev/null @@ -1,140 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import { View, Image, TouchableOpacity, StyleSheet, ActivityIndicator, useColorScheme, NativeModules } from 'react-native'; -import { Icon } from 'react-native-elements'; -import Biometric from './class/biometrics'; -import { StackActions, useNavigation, useRoute } from '@react-navigation/native'; -import { BlueStorageContext } from './blue_modules/storage-context'; -import { isHandset } from './blue_modules/environment'; -import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback'; -import SafeArea from './components/SafeArea'; - -const styles = StyleSheet.create({ - root: { - flex: 1, - }, - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - - biometricRow: { - justifyContent: 'center', - flexDirection: 'row', - }, - icon: { - width: 64, - height: 64, - }, - logoImage: { - width: 100, - height: 75, - alignSelf: 'center', - }, -}); - -const { SplashScreen } = NativeModules; - -const UnlockWith = () => { - const { setWalletsInitialized, isStorageEncrypted, startAndDecrypt } = useContext(BlueStorageContext); - const { dispatch } = useNavigation(); - const { unlockOnComponentMount } = useRoute().params; - const [biometricType, setBiometricType] = useState(false); - const [isStorageEncryptedEnabled, setIsStorageEncryptedEnabled] = useState(false); - const [isAuthenticating, setIsAuthenticating] = useState(false); - const colorScheme = useColorScheme(); - - useEffect(() => { - SplashScreen?.dismissSplashScreen(); - startUnlock(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - const successfullyAuthenticated = () => { - setWalletsInitialized(true); - dispatch(StackActions.replace(isHandset ? 'Navigation' : 'DrawerRoot')); - }; - - const unlockWithBiometrics = async () => { - if (await isStorageEncrypted()) { - unlockWithKey(); - } else { - setIsAuthenticating(true); - - if (await Biometric.unlockWithBiometrics()) { - setIsAuthenticating(false); - await startAndDecrypt(); - return successfullyAuthenticated(); - } - setIsAuthenticating(false); - } - }; - - const unlockWithKey = async () => { - if (isAuthenticating) return; - setIsAuthenticating(true); - if (await startAndDecrypt()) { - triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess); - successfullyAuthenticated(); - } else { - setIsAuthenticating(false); - } - }; - - const renderUnlockOptions = () => { - if (isAuthenticating) { - return ; - } else { - const color = colorScheme === 'dark' ? '#FFFFFF' : '#000000'; - if ((biometricType === Biometric.TouchID || biometricType === Biometric.Biometrics) && !isStorageEncryptedEnabled) { - return ( - - - - ); - } else if (biometricType === Biometric.FaceID && !isStorageEncryptedEnabled) { - return ( - - - - ); - } else if (isStorageEncryptedEnabled) { - return ( - - - - ); - } - } - }; - - const startUnlock = async () => { - if (unlockOnComponentMount) { - const storageIsEncrypted = await isStorageEncrypted(); - setIsStorageEncryptedEnabled(storageIsEncrypted); - let bt = false; - if (await Biometric.isBiometricUseCapableAndEnabled()) { - bt = await Biometric.biometricType(); - } - - setBiometricType(bt); - if (!bt || storageIsEncrypted) { - unlockWithKey(); - } else if (typeof bt === 'string') unlockWithBiometrics(); - } - }; - - return ( - - - - - {renderUnlockOptions()} - - ); -}; - -export default UnlockWith; diff --git a/UnlockWith.tsx b/UnlockWith.tsx new file mode 100644 index 000000000..970828487 --- /dev/null +++ b/UnlockWith.tsx @@ -0,0 +1,196 @@ +import React, { useContext, useEffect, useReducer, useRef } from 'react'; +import { View, Image, TouchableOpacity, ActivityIndicator, useColorScheme, NativeModules, StyleSheet } from 'react-native'; +import { Icon } from 'react-native-elements'; +import Biometric, { BiometricType } from './class/biometrics'; +import { NavigationProp, RouteProp, StackActions, useNavigation, useRoute } from '@react-navigation/native'; +import { BlueStorageContext } from './blue_modules/storage-context'; +import { isHandset } from './blue_modules/environment'; +import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback'; +import SafeArea from './components/SafeArea'; +type RootStackParamList = { + UnlockWith: { unlockOnComponentMount?: boolean }; +}; + +type State = { + biometricType: BiometricType | undefined; + isStorageEncryptedEnabled: boolean; + isAuthenticating: boolean; +}; + +const SET_BIOMETRIC_TYPE = 'SET_BIOMETRIC_TYPE'; +const SET_IS_STORAGE_ENCRYPTED_ENABLED = 'SET_IS_STORAGE_ENCRYPTED_ENABLED'; +const SET_IS_AUTHENTICATING = 'SET_IS_AUTHENTICATING'; + +type Action = + | { type: typeof SET_BIOMETRIC_TYPE; payload: BiometricType | undefined } + | { type: typeof SET_IS_STORAGE_ENCRYPTED_ENABLED; payload: boolean } + | { type: typeof SET_IS_AUTHENTICATING; payload: boolean }; + +const initialState: State = { + biometricType: undefined, + isStorageEncryptedEnabled: false, + isAuthenticating: false, +}; + +function reducer(state: State, action: Action): State { + switch (action.type) { + case SET_BIOMETRIC_TYPE: + return { ...state, biometricType: action.payload }; + case SET_IS_STORAGE_ENCRYPTED_ENABLED: + return { ...state, isStorageEncryptedEnabled: action.payload }; + case SET_IS_AUTHENTICATING: + return { ...state, isAuthenticating: action.payload }; + default: + return state; + } +} + +const { SplashScreen } = NativeModules; + +const UnlockWith: React.FC = () => { + const [state, dispatch] = useReducer(reducer, initialState); + const isUnlockingWallets = useRef(false); + const { setWalletsInitialized, isStorageEncrypted, startAndDecrypt } = useContext(BlueStorageContext); + const navigation = useNavigation>(); + const route = useRoute>(); + const { unlockOnComponentMount } = route.params; + const colorScheme = useColorScheme(); + + useEffect(() => { + SplashScreen?.dismissSplashScreen(); + startUnlock(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const successfullyAuthenticated = () => { + setWalletsInitialized(true); + navigation.dispatch(StackActions.replace(isHandset ? 'Navigation' : 'DrawerRoot')); + isUnlockingWallets.current = false; + }; + + const unlockWithBiometrics = async () => { + if (isUnlockingWallets.current || state.isAuthenticating) return; + isUnlockingWallets.current = true; + dispatch({ type: SET_IS_AUTHENTICATING, payload: true }); + + if (await Biometric.unlockWithBiometrics()) { + await startAndDecrypt(); + successfullyAuthenticated(); + } + + dispatch({ type: SET_IS_AUTHENTICATING, payload: false }); + isUnlockingWallets.current = false; + }; + + const unlockWithKey = async () => { + if (isUnlockingWallets.current || state.isAuthenticating) return; + isUnlockingWallets.current = true; + dispatch({ type: SET_IS_AUTHENTICATING, payload: true }); + + if (await startAndDecrypt()) { + triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess); + successfullyAuthenticated(); + } else { + dispatch({ type: SET_IS_AUTHENTICATING, payload: false }); + isUnlockingWallets.current = false; + } + }; + + const renderUnlockOptions = () => { + if (state.isAuthenticating) { + return ; + } else { + const color = colorScheme === 'dark' ? '#FFFFFF' : '#000000'; + if ( + (state.biometricType === BiometricType.TouchID || state.biometricType === BiometricType.Biometrics) && + !state.isStorageEncryptedEnabled + ) { + return ( + + + + ); + } else if (state.biometricType === BiometricType.FaceID && !state.isStorageEncryptedEnabled) { + return ( + + + + ); + } else if (state.isStorageEncryptedEnabled) { + return ( + + + + ); + } + } + }; + + const startUnlock = async () => { + if (unlockOnComponentMount) { + const storageIsEncrypted = await isStorageEncrypted(); + dispatch({ type: SET_IS_STORAGE_ENCRYPTED_ENABLED, payload: storageIsEncrypted }); + const rawType = await Biometric.biometricType(); + + let type; + if (rawType === 'Biometrics') { + type = BiometricType.Biometrics; + } else if (rawType === 'Touch ID') { + type = BiometricType.TouchID; + } else if (rawType === 'Face ID') { + type = BiometricType.FaceID; + } + + dispatch({ type: SET_BIOMETRIC_TYPE, payload: type }); + + if (!type || storageIsEncrypted) { + unlockWithKey(); + } else { + unlockWithBiometrics(); + } + } + }; + + return ( + + + + + {renderUnlockOptions()} + + ); +}; + +const styles = StyleSheet.create({ + root: { + flex: 1, + justifyContent: 'space-between', + }, + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + }, + biometricRow: { + justifyContent: 'center', + flexDirection: 'row', + width: 64, + height: 64, + alignSelf: 'center', + marginBottom: 20, + }, + icon: { + width: 64, + height: 64, + }, + logoImage: { + width: 100, + height: 75, + alignSelf: 'center', + }, +}); + +export default UnlockWith; diff --git a/android/app/build.gradle b/android/app/build.gradle index 20229c192..3c787d7c3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -79,7 +79,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 - versionName "6.5.2" + versionName "6.5.3" testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } diff --git a/android/build.gradle b/android/build.gradle index f978417d6..5929f2cd8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -24,7 +24,7 @@ buildscript { dependencies { classpath("com.android.tools.build:gradle") classpath("com.bugsnag:bugsnag-android-gradle-plugin:5.+") - classpath 'com.google.gms:google-services:4.4.0' // Google Services plugin + classpath 'com.google.gms:google-services:4.4.1' // Google Services plugin classpath("com.facebook.react:react-native-gradle-plugin") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") diff --git a/blue_modules/currency.ts b/blue_modules/currency.ts index aa7e4d101..f23ae91e2 100644 --- a/blue_modules/currency.ts +++ b/blue_modules/currency.ts @@ -6,6 +6,7 @@ import { FiatUnit, FiatUnitType, getFiatRate } from '../models/fiatUnit'; import WidgetCommunication from './WidgetCommunication'; const PREFERRED_CURRENCY_STORAGE_KEY = 'preferredCurrency'; +const PREFERRED_CURRENCY_LOCALE_STORAGE_KEY = 'preferredCurrencyLocale'; const EXCHANGE_RATES_STORAGE_KEY = 'exchangeRates'; const LAST_UPDATED = 'LAST_UPDATED'; const GROUP_IO_BLUEWALLET = 'group.io.bluewallet.bluewallet'; @@ -27,10 +28,9 @@ let lastTimeUpdateExchangeRateWasCalled: number = 0; let skipUpdateExchangeRate: boolean = false; async function setPreferredCurrency(item: FiatUnitType): Promise { - await AsyncStorage.setItem(PREFERRED_CURRENCY_STORAGE_KEY, JSON.stringify(item)); await DefaultPreference.setName(GROUP_IO_BLUEWALLET); await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, item.endPointKey); - await DefaultPreference.set('preferredCurrencyLocale', item.locale.replace('-', '_')); + await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, item.locale.replace('-', '_')); // @ts-ignore: Convert to TSX later WidgetCommunication.reloadAllTimelines(); } @@ -39,7 +39,7 @@ async function getPreferredCurrency(): Promise { const preferredCurrency = JSON.parse((await AsyncStorage.getItem(PREFERRED_CURRENCY_STORAGE_KEY)) || '{}'); await DefaultPreference.setName(GROUP_IO_BLUEWALLET); await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, preferredCurrency.endPointKey); - await DefaultPreference.set('preferredCurrencyLocale', preferredCurrency.locale.replace('-', '_')); + await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, preferredCurrency.locale.replace('-', '_')); return preferredCurrency; } diff --git a/blue_modules/storage-context.js b/blue_modules/storage-context.js index b24e86034..50fbec3b3 100644 --- a/blue_modules/storage-context.js +++ b/blue_modules/storage-context.js @@ -28,6 +28,7 @@ export const BlueStorageProvider = ({ children }) => { const [isElectrumDisabled, setIsElectrumDisabled] = useState(true); const [isPrivacyBlurEnabled, setIsPrivacyBlurEnabled] = useState(true); const [currentSharedCosigner, setCurrentSharedCosigner] = useState(''); + const [reloadTransactionsMenuActionFunction, setReloadTransactionsMenuActionFunction] = useState(() => {}); useEffect(() => { BlueElectrum.isDisabled().then(setIsElectrumDisabled); @@ -277,6 +278,8 @@ export const BlueStorageProvider = ({ children }) => { setIsElectrumDisabled, isPrivacyBlurEnabled, setIsPrivacyBlurEnabled, + reloadTransactionsMenuActionFunction, + setReloadTransactionsMenuActionFunction, }} > {children} diff --git a/class/biometrics.ts b/class/biometrics.ts index 5d662e437..c4ef687cc 100644 --- a/class/biometrics.ts +++ b/class/biometrics.ts @@ -1,37 +1,41 @@ -import FingerprintScanner from 'react-native-fingerprint-scanner'; -import { Platform, Alert } from 'react-native'; -// @ts-ignore react-native-passcode-auth wants d.ts +import { useContext } from 'react'; +import { Alert, Platform } from 'react-native'; +import { CommonActions, StackActions } from '@react-navigation/native'; +import FingerprintScanner, { Biometrics as TBiometrics } from 'react-native-fingerprint-scanner'; import PasscodeAuth from 'react-native-passcode-auth'; -import * as NavigationService from '../NavigationService'; -import { StackActions, CommonActions } from '@react-navigation/native'; import RNSecureKeyStore from 'react-native-secure-key-store'; import loc from '../loc'; -import { useContext } from 'react'; +import * as NavigationService from '../NavigationService'; import { BlueStorageContext } from '../blue_modules/storage-context'; import presentAlert from '../components/Alert'; +const STORAGEKEY = 'Biometrics'; + +export enum BiometricType { + FaceID = 'FaceID', + TouchID = 'TouchID', + Biometrics = 'Biometrics', + None = 'None', +} + // Define a function type with properties type DescribableFunction = { - (): void; // Call signature - STORAGEKEY: string; // Property - FaceID: string; // Property etc... - TouchID: string; - Biometrics: string; - isBiometricUseCapableAndEnabled: () => Promise; - isDeviceBiometricCapable: () => Promise; + (): null; // Call signature + FaceID: 'Face ID'; + TouchID: 'Touch ID'; + Biometrics: 'Biometrics'; + isBiometricUseCapableAndEnabled: () => Promise; + isDeviceBiometricCapable: () => Promise; setBiometricUseEnabled: (arg: boolean) => Promise; - biometricType: () => Promise; + biometricType: () => Promise; isBiometricUseEnabled: () => Promise; - unlockWithBiometrics: () => Promise; - clearKeychain: () => Promise; - requestDevicePasscode: () => Promise; + unlockWithBiometrics: () => Promise; showKeychainWipeAlert: () => void; }; -// @ts-ignore Bastard component/module. All properties are added in runtime, not at definition phase -const Biometric: DescribableFunction = function () { +// Bastard component/module. All properties are added in runtime +const Biometric = function () { const { getItem, setItem } = useContext(BlueStorageContext); - Biometric.STORAGEKEY = 'Biometrics'; Biometric.FaceID = 'Face ID'; Biometric.TouchID = 'Touch ID'; Biometric.Biometrics = 'Biometrics'; @@ -46,8 +50,8 @@ const Biometric: DescribableFunction = function () { console.log('Biometrics isDeviceBiometricCapable failed'); console.log(e); Biometric.setBiometricUseEnabled(false); - return false; } + return false; }; Biometric.biometricType = async () => { @@ -63,7 +67,7 @@ const Biometric: DescribableFunction = function () { Biometric.isBiometricUseEnabled = async () => { try { - const enabledBiometrics = await getItem(Biometric.STORAGEKEY); + const enabledBiometrics = await getItem(STORAGEKEY); return !!enabledBiometrics; } catch (_) {} @@ -77,7 +81,7 @@ const Biometric: DescribableFunction = function () { }; Biometric.setBiometricUseEnabled = async value => { - await setItem(Biometric.STORAGEKEY, value === true ? '1' : ''); + await setItem(STORAGEKEY, value === true ? '1' : ''); }; Biometric.unlockWithBiometrics = async () => { @@ -97,14 +101,14 @@ const Biometric: DescribableFunction = function () { return false; }; - Biometric.clearKeychain = async () => { + const clearKeychain = async () => { await RNSecureKeyStore.remove('data'); await RNSecureKeyStore.remove('data_encrypted'); - await RNSecureKeyStore.remove(Biometric.STORAGEKEY); + await RNSecureKeyStore.remove(STORAGEKEY); NavigationService.dispatch(StackActions.replace('WalletsRoot')); }; - Biometric.requestDevicePasscode = async () => { + const requestDevicePasscode = async () => { let isDevicePasscodeSupported: boolean | undefined = false; try { isDevicePasscodeSupported = await PasscodeAuth.isSupported(); @@ -118,7 +122,7 @@ const Biometric: DescribableFunction = function () { { text: loc._.cancel, style: 'cancel' }, { text: loc._.ok, - onPress: () => Biometric.clearKeychain(), + onPress: () => clearKeychain(), }, ], { cancelable: false }, @@ -153,7 +157,7 @@ const Biometric: DescribableFunction = function () { }, { text: loc._.ok, - onPress: () => Biometric.requestDevicePasscode(), + onPress: () => requestDevicePasscode(), style: 'default', }, ], @@ -161,7 +165,8 @@ const Biometric: DescribableFunction = function () { ); } }; + return null; -}; +} as DescribableFunction; export default Biometric; diff --git a/class/wallet-import.js b/class/wallet-import.ts similarity index 88% rename from class/wallet-import.js rename to class/wallet-import.ts index 5367980df..abe17c68f 100644 --- a/class/wallet-import.js +++ b/class/wallet-import.ts @@ -20,43 +20,57 @@ import { SegwitP2SHWallet, WatchOnlyWallet, } from '.'; +import type { TWallet } from './wallets/types'; import loc from '../loc'; import bip39WalletFormats from './bip39_wallet_formats.json'; // https://github.com/spesmilo/electrum/blob/master/electrum/bip39_wallet_formats.json import bip39WalletFormatsBlueWallet from './bip39_wallet_formats_bluewallet.json'; // https://github.com/bitcoinjs/bip32/blob/master/ts-src/bip32.ts#L43 -export const validateBip32 = path => path.match(/^(m\/)?(\d+'?\/)*\d+'?$/) !== null; +export const validateBip32 = (path: string) => path.match(/^(m\/)?(\d+'?\/)*\d+'?$/) !== null; + +type TReturn = { + cancelled: boolean; + stopped: boolean; + wallets: TWallet[]; +}; /** * Function that starts wallet search and import process. It has async generator inside, so * that the process can be stoped at any time. It reporst all the progress through callbacks. * - * @param askPassphrase {bool} If true import process will call onPassword callback for wallet with optional password. - * @param searchAccounts {bool} If true import process will scan for all known derivation path from bip39_wallet_formats.json. If false it will use limited version. + * @param askPassphrase {boolean} If true import process will call onPassword callback for wallet with optional password. + * @param searchAccounts {boolean} If true import process will scan for all known derivation path from bip39_wallet_formats.json. If false it will use limited version. * @param onProgress {function} Callback to report scanning progress * @param onWallet {function} Callback to report wallet found * @param onPassword {function} Callback to ask for password if needed * @returns {{promise: Promise, stop: function}} */ -const startImport = (importTextOrig, askPassphrase = false, searchAccounts = false, onProgress, onWallet, onPassword) => { +const startImport = ( + importTextOrig: string, + askPassphrase: boolean = false, + searchAccounts: boolean = false, + onProgress: (name: string) => void, + onWallet: (wallet: TWallet) => void, + onPassword: (title: string, text: string) => Promise, +): { promise: Promise; stop: () => void } => { // state - let promiseResolve; - let promiseReject; + let promiseResolve: (arg: TReturn) => void; + let promiseReject: (reason?: any) => void; let running = true; // if you put it to false, internal generator stops - const wallets = []; - const promise = new Promise((resolve, reject) => { + const wallets: TWallet[] = []; + const promise = new Promise((resolve, reject) => { promiseResolve = resolve; promiseReject = reject; }); // actions - const reportProgress = name => { + const reportProgress = (name: string) => { onProgress(name); }; - const reportFinish = (cancelled, stopped) => { + const reportFinish = (cancelled: boolean = false, stopped: boolean = false) => { promiseResolve({ cancelled, stopped, wallets }); }; - const reportWallet = wallet => { + const reportWallet = (wallet: TWallet) => { if (wallets.some(w => w.getID() === wallet.getID())) return; // do not add duplicates wallets.push(wallet); onWallet(wallet); @@ -134,7 +148,7 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal } // is it bip38 encrypted - if (text.startsWith('6P')) { + if (text.startsWith('6P') && password) { const decryptedKey = await bip38.decryptAsync(text, password); if (decryptedKey) { @@ -184,7 +198,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal yield { progress: 'bip39' }; const hd2 = new HDSegwitBech32Wallet(); hd2.setSecret(text); - hd2.setPassphrase(password); + if (password) { + hd2.setPassphrase(password); + } if (hd2.validateMnemonic()) { let walletFound = false; // by default we don't try all the paths and options @@ -214,7 +230,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal for (const path of paths) { const wallet = new WalletClass(); wallet.setSecret(text); - wallet.setPassphrase(password); + if (password) { + wallet.setPassphrase(password); + } wallet.setDerivationPath(path); yield { progress: `bip39 ${i.script_type} ${path}` }; if (await wallet.wasEverUsed()) { @@ -230,7 +248,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal // to decide which one is it let's compare number of transactions const m0Legacy = new HDLegacyP2PKHWallet(); m0Legacy.setSecret(text); - m0Legacy.setPassphrase(password); + if (password) { + m0Legacy.setPassphrase(password); + } m0Legacy.setDerivationPath("m/0'"); yield { progress: "bip39 p2pkh m/0'" }; // BRD doesn't support passphrase and only works with 12 words seeds @@ -332,7 +352,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal yield { progress: 'electrum p2wpkh-p2sh' }; const el1 = new HDSegwitElectrumSeedP2WPKHWallet(); el1.setSecret(text); - el1.setPassphrase(password); + if (password) { + el1.setPassphrase(password); + } if (el1.validateMnemonic()) { yield { wallet: el1 }; // not fetching txs or balances, fuck it, yolo, life is too short } @@ -341,7 +363,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal yield { progress: 'electrum p2pkh' }; const el2 = new HDLegacyElectrumSeedP2PKHWallet(); el2.setSecret(text); - el2.setPassphrase(password); + if (password) { + el2.setPassphrase(password); + } if (el2.validateMnemonic()) { yield { wallet: el2 }; // not fetching txs or balances, fuck it, yolo, life is too short } @@ -350,7 +374,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal yield { progress: 'aezeed' }; const aezeed2 = new HDAezeedWallet(); aezeed2.setSecret(text); - aezeed2.setPassphrase(password); + if (password) { + aezeed2.setPassphrase(password); + } if (await aezeed2.validateMnemonicAsync()) { yield { wallet: aezeed2 }; // not fetching txs or balances, fuck it, yolo, life is too short } @@ -364,14 +390,18 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal if (s1.validateMnemonic()) { yield { progress: 'SLIP39 p2wpkh-p2sh' }; - s1.setPassphrase(password); + if (password) { + s1.setPassphrase(password); + } if (await s1.wasEverUsed()) { yield { wallet: s1 }; } yield { progress: 'SLIP39 p2pkh' }; const s2 = new SLIP39LegacyP2PKHWallet(); - s2.setPassphrase(password); + if (password) { + s2.setPassphrase(password); + } s2.setSecret(text); if (await s2.wasEverUsed()) { yield { wallet: s2 }; @@ -380,7 +410,9 @@ const startImport = (importTextOrig, askPassphrase = false, searchAccounts = fal yield { progress: 'SLIP39 p2wpkh' }; const s3 = new SLIP39SegwitBech32Wallet(); s3.setSecret(text); - s3.setPassphrase(password); + if (password) { + s3.setPassphrase(password); + } yield { wallet: s3 }; } } diff --git a/class/wallets/types.ts b/class/wallets/types.ts index e4d9b10a4..fdf56caf1 100644 --- a/class/wallets/types.ts +++ b/class/wallets/types.ts @@ -1,5 +1,20 @@ import bitcoin from 'bitcoinjs-lib'; import { CoinSelectOutput, CoinSelectReturnInput } from 'coinselect'; +import { HDAezeedWallet } from './hd-aezeed-wallet'; +import { HDLegacyBreadwalletWallet } from './hd-legacy-breadwallet-wallet'; +import { HDLegacyElectrumSeedP2PKHWallet } from './hd-legacy-electrum-seed-p2pkh-wallet'; +import { HDLegacyP2PKHWallet } from './hd-legacy-p2pkh-wallet'; +import { HDSegwitBech32Wallet } from './hd-segwit-bech32-wallet'; +import { HDSegwitElectrumSeedP2WPKHWallet } from './hd-segwit-electrum-seed-p2wpkh-wallet'; +import { HDSegwitP2SHWallet } from './hd-segwit-p2sh-wallet'; +import { LegacyWallet } from './legacy-wallet'; +import { LightningCustodianWallet } from './lightning-custodian-wallet'; +import { LightningLdkWallet } from './lightning-ldk-wallet'; +import { MultisigHDWallet } from './multisig-hd-wallet'; +import { SegwitBech32Wallet } from './segwit-bech32-wallet'; +import { SegwitP2SHWallet } from './segwit-p2sh-wallet'; +import { SLIP39LegacyP2PKHWallet, SLIP39SegwitBech32Wallet, SLIP39SegwitP2SHWallet } from './slip39-wallets'; +import { WatchOnlyWallet } from './watch-only-wallet'; export type Utxo = { // Returned by BlueElectrum @@ -80,3 +95,22 @@ export type Transaction = { received?: number; value?: number; }; + +export type TWallet = + | HDAezeedWallet + | HDLegacyBreadwalletWallet + | HDLegacyElectrumSeedP2PKHWallet + | HDLegacyP2PKHWallet + | HDSegwitBech32Wallet + | HDSegwitElectrumSeedP2WPKHWallet + | HDSegwitP2SHWallet + | LegacyWallet + | LightningCustodianWallet + | LightningLdkWallet + | MultisigHDWallet + | SLIP39LegacyP2PKHWallet + | SLIP39SegwitBech32Wallet + | SLIP39SegwitP2SHWallet + | SegwitBech32Wallet + | SegwitP2SHWallet + | WatchOnlyWallet; diff --git a/components/BottomModal.js b/components/BottomModal.tsx similarity index 68% rename from components/BottomModal.js rename to components/BottomModal.tsx index 05b678905..ecfb9e7d5 100644 --- a/components/BottomModal.js +++ b/components/BottomModal.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; import { StyleSheet, Platform, useWindowDimensions, View } from 'react-native'; import Modal from 'react-native-modal'; import { BlueSpacing10 } from '../BlueComponents'; @@ -18,19 +17,32 @@ const styles = StyleSheet.create({ }, }); -const BottomModal = ({ - onBackButtonPress = undefined, - onBackdropPress = undefined, +interface BottomModalProps { + children?: React.ReactNode; + onBackButtonPress?: () => void; + onBackdropPress?: () => void; + onClose: () => void; + windowHeight?: number; + windowWidth?: number; + doneButton?: boolean; + avoidKeyboard?: boolean; + allowBackdropPress?: boolean; + isVisible: boolean; +} + +const BottomModal: React.FC = ({ + onBackButtonPress, + onBackdropPress, onClose, - windowHeight = undefined, - windowWidth = undefined, - doneButton = undefined, + windowHeight, + windowWidth, + doneButton, + isVisible, avoidKeyboard = false, allowBackdropPress = true, ...props }) => { - const valueWindowHeight = useWindowDimensions().height; - const valueWindowWidth = useWindowDimensions().width; + const { height: valueWindowHeight, width: valueWindowWidth } = useWindowDimensions(); const handleBackButtonPress = onBackButtonPress ?? onClose; const handleBackdropPress = allowBackdropPress ? onBackdropPress ?? onClose : undefined; const { colors } = useTheme(); @@ -39,6 +51,7 @@ const BottomModal = ({ backgroundColor: colors.elevated, }, }); + return ( { - const { walletsInitialized } = useContext(BlueStorageContext); + const { walletsInitialized, reloadTransactionsMenuActionFunction } = useContext(BlueStorageContext); // BlueWallet -> Settings const openSettings = useCallback(() => { @@ -23,25 +23,50 @@ const MenuElements = () => { dispatchNavigate('AddWalletRoot'); }, []); - const dispatchNavigate = (routeName: string) => { - NavigationService.dispatch( - CommonActions.navigate({ - name: routeName, - }), - ); + // File -> Add Wallet + const importWalletMenuAction = useCallback(() => { + dispatchNavigate('AddWalletRoot', 'ImportWallet'); + }, []); + + const dispatchNavigate = (routeName: string, screen?: string) => { + const action = screen + ? CommonActions.navigate({ + name: routeName, + params: { screen }, + }) + : CommonActions.navigate({ + name: routeName, + }); + + NavigationService.dispatch(action); }; + const reloadTransactionsMenuElementsFunction = useCallback(() => { + reloadTransactionsMenuActionFunction(); + }, [reloadTransactionsMenuActionFunction]); + useEffect(() => { console.log('MenuElements: useEffect'); if (walletsInitialized) { eventEmitter?.addListener('openSettings', openSettings); eventEmitter?.addListener('addWalletMenuAction', addWalletMenuAction); + eventEmitter?.addListener('importWalletMenuAction', importWalletMenuAction); + eventEmitter?.addListener('reloadTransactionsMenuAction', reloadTransactionsMenuElementsFunction); } return () => { eventEmitter?.removeAllListeners('openSettings'); eventEmitter?.removeAllListeners('addWalletMenuAction'); + eventEmitter?.removeAllListeners('importWalletMenuAction'); + eventEmitter?.removeAllListeners('reloadTransactionsMenuAction'); }; - }, [addWalletMenuAction, openSettings, walletsInitialized]); + }, [ + addWalletMenuAction, + importWalletMenuAction, + openSettings, + reloadTransactionsMenuActionFunction, + reloadTransactionsMenuElementsFunction, + walletsInitialized, + ]); return <>; }; diff --git a/components/TransactionsNavigationHeader.tsx b/components/TransactionsNavigationHeader.tsx index b4bb0b2de..f34042a95 100644 --- a/components/TransactionsNavigationHeader.tsx +++ b/components/TransactionsNavigationHeader.tsx @@ -77,11 +77,9 @@ const TransactionsNavigationHeader: React.FC }; const handleBalanceVisibility = async () => { - // @ts-ignore: Gotta update this class const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled(); if (isBiometricsEnabled && wallet.hideBalance) { - // @ts-ignore: Ugh if (!(await Biometric.unlockWithBiometrics())) { return navigation.goBack(); } diff --git a/components/handoff.tsx b/components/handoff.tsx index cd8abdadf..73c773983 100644 --- a/components/handoff.tsx +++ b/components/handoff.tsx @@ -5,6 +5,9 @@ import { BlueStorageContext } from '../blue_modules/storage-context'; interface HandoffComponentProps { url?: string; + title?: string; + type: (typeof HandoffComponent.activityTypes)[keyof typeof HandoffComponent.activityTypes]; + userInfo?: object; } interface HandoffComponentWithActivityTypes extends React.FC { diff --git a/components/navigationStyle.tsx b/components/navigationStyle.tsx index 12202e968..a8f1f5b70 100644 --- a/components/navigationStyle.tsx +++ b/components/navigationStyle.tsx @@ -44,19 +44,23 @@ export type NavigationOptionsGetter = (theme: Theme) => (deps: { navigation: any const navigationStyle = ( { - closeButton = false, closeButtonFunc, headerBackVisible = true, ...opts }: NavigationOptions & { closeButton?: boolean; - closeButtonFunc?: (deps: { navigation: any; route: any }) => React.ReactElement; }, formatter: OptionsFormatter, ): NavigationOptionsGetter => { return theme => ({ navigation, route }) => { + // Determine if the current screen is the first one in the stack using the updated method + const isFirstRouteInStack = navigation.getState().index === 0; + + // Default closeButton to true if the current screen is the first one in the stack + const closeButton = opts.closeButton !== undefined ? opts.closeButton : isFirstRouteInStack; + let headerRight; let headerLeft; if (closeButton) { @@ -79,12 +83,11 @@ const navigationStyle = ( ); } - // Workaround for https://github.com/BlueWallet/BlueWallet/issues/6030 if (!headerBackVisible) { headerLeft = () => <>; + // @ts-ignore: Fix later opts.headerLeft = headerLeft; } - // let options: NavigationOptions = { headerShadowVisible: false, @@ -92,6 +95,7 @@ const navigationStyle = ( fontWeight: '600', color: theme.colors.foregroundColor, }, + // @ts-ignore: Fix later headerRight, headerBackTitleVisible: false, headerTintColor: theme.colors.foregroundColor, @@ -124,6 +128,7 @@ export const navigationStyleTx = (opts: NavigationOptions, formatter: OptionsFor // headerBackTitle: null, headerBackTitleVisible: false, headerTintColor: theme.colors.foregroundColor, + // @ts-ignore: Fix later headerLeft: () => ( resolve(data.data || data), 1); - navigateFunc(currentScreenName); navigateFunc({ name: currentScreenName, params: {}, merge: true }); }; diff --git a/helpers/select-wallet.ts b/helpers/select-wallet.ts index 4838eac00..6449e46a5 100644 --- a/helpers/select-wallet.ts +++ b/helpers/select-wallet.ts @@ -13,7 +13,7 @@ import { AbstractWallet } from '../class'; module.exports = function ( - navigateFunc: (scr: string, params?: any) => void, + navigateFunc: (scr: string | any, params?: any) => void, currentScreenName: string, chainType: string | null, availableWallets?: AbstractWallet[], @@ -40,7 +40,7 @@ module.exports = function ( setTimeout(() => resolve(selectedWallet), 1); console.warn('trying to navigate back to', currentScreenName); - navigateFunc(currentScreenName); + navigateFunc({ name: currentScreenName, params: {}, merge: true }); }; navigateFunc('SelectWallet', params); diff --git a/ios/BlueWallet.xcodeproj/project.pbxproj b/ios/BlueWallet.xcodeproj/project.pbxproj index 7c5ec9ed1..0b6bbb4fb 100644 --- a/ios/BlueWallet.xcodeproj/project.pbxproj +++ b/ios/BlueWallet.xcodeproj/project.pbxproj @@ -89,7 +89,7 @@ B4AB225D2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; }; B4AB225E2B02AD12001F4328 /* XMLParserDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4AB225C2B02AD12001F4328 /* XMLParserDelegate.swift */; }; B4EE583C226703320003363C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B40D4E35225841ED00428FCC /* Assets.xcassets */; }; - C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; + C978A716948AB7DEC5B6F677 /* (null) in Frameworks */ = {isa = PBXBuildFile; }; E5D4794B26781FC0007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; }; E5D4794C26781FC1007838C1 /* fiatUnits.json in Resources */ = {isa = PBXBuildFile; fileRef = 6DD410AD266CAF1F0087DE03 /* fiatUnits.json */; }; /* End PBXBuildFile section */ @@ -393,7 +393,7 @@ files = ( 782F075B5DD048449E2DECE9 /* libz.tbd in Frameworks */, 764B49B1420D4AEB8109BF62 /* libsqlite3.0.tbd in Frameworks */, - C978A716948AB7DEC5B6F677 /* BuildFile in Frameworks */, + C978A716948AB7DEC5B6F677 /* (null) in Frameworks */, 773E382FE62E836172AAB98B /* libPods-BlueWallet.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1001,7 +1001,7 @@ ); mainGroup = 83CBB9F61A601CBA00E9B192; packageReferences = ( - 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */, + 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */, B41B76832B66B2FF002C48D5 /* XCRemoteSwiftPackageReference "bugsnag-cocoa" */, ); productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; @@ -1526,7 +1526,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU; @@ -1551,7 +1551,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -1584,9 +1584,9 @@ CODE_SIGN_ENTITLEMENTS = BlueWallet/BlueWalletRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU; @@ -1606,7 +1606,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -1617,7 +1617,7 @@ PRODUCT_NAME = BlueWallet; PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore io.bluewallet.bluewallet"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "BlueWallet Mac App Store"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AppStore io.bluewallet.bluewallet catalyst"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; @@ -1643,7 +1643,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; @@ -1688,7 +1688,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; @@ -1733,7 +1733,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; @@ -1787,13 +1787,15 @@ CODE_SIGN_ENTITLEMENTS = WidgetsExtension.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU; + "DEVELOPMENT_TEAM[sdk=macosx*]" = A7W54YZ4WU; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.1; @@ -1814,6 +1816,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore io.bluewallet.bluewallet.MarketWidget"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AppStore io.bluewallet.bluewallet.MarketWidget catalyst"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = YES; @@ -1959,7 +1962,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; @@ -1976,7 +1979,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; @@ -2009,7 +2012,7 @@ "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; @@ -2026,7 +2029,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; MTL_FAST_MATH = YES; PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch.extension; @@ -2058,7 +2061,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; @@ -2071,7 +2074,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; @@ -2106,7 +2109,7 @@ "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; @@ -2119,7 +2122,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; MTL_FAST_MATH = YES; PRESERVE_DEAD_CODE_INITS_AND_TERMS = YES; PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet.watch; @@ -2149,7 +2152,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; @@ -2199,7 +2202,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; @@ -2238,7 +2241,7 @@ CODE_SIGN_ENTITLEMENTS = BlueWallet/BlueWallet.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1703112800; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_TEAM = A7W54YZ4WU; ENABLE_BITCODE = NO; @@ -2262,7 +2265,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -2278,7 +2281,7 @@ SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = 2; + TARGETED_DEVICE_FAMILY = "2,6"; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; @@ -2291,10 +2294,14 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = BlueWallet/BlueWalletRelease.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1703112800; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 1703112810; DEAD_CODE_STRIPPING = YES; - DEVELOPMENT_TEAM = A7W54YZ4WU; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU; + "DEVELOPMENT_TEAM[sdk=macosx*]" = A7W54YZ4WU; ENABLE_BITCODE = NO; "ENABLE_HARDENED_RUNTIME[sdk=macosx*]" = YES; HEADER_SEARCH_PATHS = "$(inherited)"; @@ -2311,7 +2318,7 @@ "$(SDKROOT)/System/iOSSupport/usr/lib/swift", "$(inherited)", ); - MARKETING_VERSION = 6.5.2; + MARKETING_VERSION = 6.5.3; OTHER_LDFLAGS = ( "$(inherited)", "-ObjC", @@ -2321,12 +2328,14 @@ PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet; PRODUCT_NAME = BlueWallet; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AppStore io.bluewallet.bluewallet"; + "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "match AppStore io.bluewallet.bluewallet catalyst"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = YES; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_OBJC_BRIDGING_HEADER = "BlueWallet-Bridging-Header.h"; SWIFT_VERSION = 4.2; - TARGETED_DEVICE_FAMILY = 2; + TARGETED_DEVICE_FAMILY = "2,6"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; @@ -2409,7 +2418,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */ = { + 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/EFPrefix/EFQRCode.git"; requirement = { @@ -2430,7 +2439,7 @@ /* Begin XCSwiftPackageProductDependency section */ 6DFC806F24EA0B6C007B8700 /* EFQRCode */ = { isa = XCSwiftPackageProductDependency; - package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode.git" */; + package = 6DFC806E24EA0B6C007B8700 /* XCRemoteSwiftPackageReference "EFQRCode" */; productName = EFQRCode; }; B41B76842B66B2FF002C48D5 /* Bugsnag */ = { diff --git a/ios/BlueWallet.xcodeproj/xcuserdata/marcosrodriguez.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/BlueWallet.xcodeproj/xcuserdata/marcosrodriguez.xcuserdatad/xcschemes/xcschememanagement.plist index 6b7385d04..eea6761b6 100644 --- a/ios/BlueWallet.xcodeproj/xcuserdata/marcosrodriguez.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/ios/BlueWallet.xcodeproj/xcuserdata/marcosrodriguez.xcuserdatad/xcschemes/xcschememanagement.plist @@ -24,6 +24,11 @@ orderHint 100 + BlueWallet-NoLDK.xcscheme_^#shared#^_ + + orderHint + 134 + BlueWallet.xcscheme_^#shared#^_ orderHint @@ -32,7 +37,7 @@ BlueWalletUITests.xcscheme_^#shared#^_ orderHint - 99 + 97 BlueWalletWatch (Complication).xcscheme_^#shared#^_ diff --git a/ios/BlueWallet/AppDelegate.mm b/ios/BlueWallet/AppDelegate.mm index 70102ca9e..749d70ceb 100644 --- a/ios/BlueWallet/AppDelegate.mm +++ b/ios/BlueWallet/AppDelegate.mm @@ -127,10 +127,6 @@ completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge); } -- (void)openSettings:(UIKeyCommand *)keyCommand { - [EventEmitter.sharedInstance openSettings]; -} - - (void)buildMenuWithBuilder:(id)builder { [super buildMenuWithBuilder:builder]; [builder removeMenuForIdentifier:UIMenuServices]; @@ -138,18 +134,27 @@ [builder removeMenuForIdentifier:UIMenuToolbar]; // File -> Add Wallet (Command + A) - UIKeyCommand *addWalletCommand = [UIKeyCommand keyCommandWithInput:@"A" modifierFlags:UIKeyModifierCommand action:@selector(addWalletAction:)]; - [addWalletCommand setTitle:@"Add Wallet"]; - UIMenu *addWalletMenu = [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[addWalletCommand]]; + UIKeyCommand *addWalletCommand = [UIKeyCommand keyCommandWithInput:@"A" modifierFlags:UIKeyModifierCommand action:@selector(addWalletAction:)]; + [addWalletCommand setTitle:@"Add Wallet"]; - - // Modify the existing File menu - UIMenu *fileMenu = [builder menuForIdentifier:UIMenuFile]; - if (fileMenu) { - // Replace the children of the File menu with the Add Wallet menu - UIMenu *newFileMenu = [UIMenu menuWithTitle:fileMenu.title image:nil identifier:fileMenu.identifier options:fileMenu.options children:@[addWalletMenu]]; - [builder replaceMenuForIdentifier:UIMenuFile withMenu:newFileMenu]; - } + // File -> Import Wallet + UIKeyCommand *importWalletCommand = [UIKeyCommand keyCommandWithInput:@"I" modifierFlags:UIKeyModifierCommand action:@selector(importWalletAction:)]; + [importWalletCommand setTitle:@"Import Wallet"]; + + // Group Add Wallet and Import Wallet in a displayInline menu + UIMenu *walletOperationsMenu = [UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[addWalletCommand, importWalletCommand]]; + + // Modify the existing File menu to include Wallet Operations + UIMenu *fileMenu = [builder menuForIdentifier:UIMenuFile]; + if (fileMenu) { + // Add "Reload Transactions" + UIKeyCommand *reloadTransactionsCommand = [UIKeyCommand keyCommandWithInput:@"R" modifierFlags:UIKeyModifierCommand action:@selector(reloadTransactionsAction:)]; + [reloadTransactionsCommand setTitle:@"Reload Transactions"]; + + // Combine wallet operations and Reload Transactions into the new File menu + UIMenu *newFileMenu = [UIMenu menuWithTitle:fileMenu.title image:nil identifier:fileMenu.identifier options:fileMenu.options children:@[walletOperationsMenu, reloadTransactionsCommand]]; + [builder replaceMenuForIdentifier:UIMenuFile withMenu:newFileMenu]; + } // BlueWallet -> Settings (Command + ,) UIKeyCommand *settingsCommand = [UIKeyCommand keyCommandWithInput:@"," modifierFlags:UIKeyModifierCommand action:@selector(openSettings:)]; @@ -159,7 +164,11 @@ [builder insertSiblingMenu:settings afterMenuForIdentifier:UIMenuAbout]; } -// Action for Add Wallet + +- (void)openSettings:(UIKeyCommand *)keyCommand { + [EventEmitter.sharedInstance openSettings]; +} + - (void)addWalletAction:(UIKeyCommand *)keyCommand { // Implement the functionality for adding a wallet [EventEmitter.sharedInstance addWalletMenuAction]; @@ -167,6 +176,21 @@ NSLog(@"Add Wallet action performed"); } +- (void)importWalletAction:(UIKeyCommand *)keyCommand { + // Implement the functionality for adding a wallet + [EventEmitter.sharedInstance importWalletMenuAction]; + + NSLog(@"Add Wallet action performed"); +} + +- (void)reloadTransactionsAction:(UIKeyCommand *)keyCommand { + // Implement the functionality for adding a wallet + [EventEmitter.sharedInstance reloadTransactionsMenuAction]; + + NSLog(@"Add Wallet action performed"); +} + + -(void)showHelp:(id)sender { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://bluewallet.io/docs"] options:@{} completionHandler:nil]; diff --git a/ios/EventEmitter.h b/ios/EventEmitter.h index 06c655470..5c24abeb3 100644 --- a/ios/EventEmitter.h +++ b/ios/EventEmitter.h @@ -15,6 +15,8 @@ - (void)sendNotification:(NSDictionary *)userInfo; - (void)openSettings; - (void)addWalletMenuAction; +- (void)importWalletMenuAction; +- (void)reloadTransactionsMenuAction; - (void)sendUserActivity:(NSDictionary *)userInfo; @end diff --git a/ios/EventEmitter.m b/ios/EventEmitter.m index 63ff60b8c..10dad3a94 100644 --- a/ios/EventEmitter.m +++ b/ios/EventEmitter.m @@ -32,7 +32,7 @@ RCT_EXPORT_MODULE(); } - (NSArray *)supportedEvents { - return @[@"onNotificationReceived",@"openSettings",@"onUserActivityOpen",@"addWalletMenuAction"]; + return @[@"onNotificationReceived",@"openSettings",@"onUserActivityOpen",@"addWalletMenuAction", @"importWalletMenuAction", @"reloadTransactionsMenuAction"]; } - (void)sendNotification:(NSDictionary *)userInfo @@ -62,4 +62,12 @@ RCT_REMAP_METHOD(getMostRecentUserActivity, resolve: (RCTPromiseResolveBlock)res [sharedInstance sendEventWithName:@"addWalletMenuAction" body:nil]; } +- (void)importWalletMenuAction { + [sharedInstance sendEventWithName:@"importWalletMenuAction" body:nil]; +} + +- (void)reloadTransactionsMenuAction { + [sharedInstance sendEventWithName:@"reloadTransactionsMenuAction" body:nil]; +} + @end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index b06a5abd3..4a9aa15b0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -352,7 +352,7 @@ PODS: - react-native-tcp-socket (6.0.6): - CocoaAsyncSocket - React-Core - - react-native-webview (13.7.1): + - react-native-webview (13.8.1): - RCT-Folly (= 2021.07.22.00) - React-Core - react-native-widget-center (0.0.9): @@ -504,7 +504,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (2.2.0): - React-Core - - RNReanimated (3.6.2): + - RNReanimated (3.7.0): - RCT-Folly (= 2021.07.22.00) - React-Core - ReactCommon/turbomodule/core @@ -823,7 +823,7 @@ SPEC CHECKSUMS: react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b react-native-secure-key-store: 910e6df6bc33cb790aba6ee24bc7818df1fe5898 react-native-tcp-socket: e724380c910c2e704816ec817ed28f1342246ff7 - react-native-webview: 83525c9ed4138faf5d5e4f8eb74bf050992935be + react-native-webview: bdc091de8cf7f8397653e30182efcd9f772e03b3 react-native-widget-center: 12dfba20a4fa995850b52cf0afecf734397f4b9c React-NativeModulesApple: c3e696ff867e4bc212266cbdf7e862e48a0166fd React-perflogger: 43287389ea08993c300897a46f95cfac04bb6c1a @@ -860,7 +860,7 @@ SPEC CHECKSUMS: RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93 RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a RNReactNativeHapticFeedback: ec56a5f81c3941206fd85625fa669ffc7b4545f9 - RNReanimated: ce6bef77caeee09d7f022532cee0c8d9bad09c9a + RNReanimated: 9dfe7a19dd7c3e123b23db42e74bf051725f2ea3 RNScreens: 3c5b9f4a9dcde752466854b6109b79c0e205dad3 RNShare: 859ff710211285676b0bcedd156c12437ea1d564 RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396 diff --git a/loc/es_419.json b/loc/es_419.json index a48400ed6..54bd90a96 100644 --- a/loc/es_419.json +++ b/loc/es_419.json @@ -281,6 +281,7 @@ "language": "Idioma", "last_updated": "Última actualización", "language_isRTL": "Es necesario reiniciar BlueWallet para que la orientación del idioma surta efecto.", + "license": "Licencia", "lightning_error_lndhub_uri": "URI de LNDHub inválido", "lightning_saved": "Tus cambios han sido guardados correctamente.", "lightning_settings": "Configuración de Lightning", diff --git a/package-lock.json b/package-lock.json index 868d1b332..d901c65c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bluewallet", - "version": "6.5.2", + "version": "6.5.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bluewallet", - "version": "6.5.2", + "version": "6.5.3", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -19,9 +19,9 @@ "@react-native-async-storage/async-storage": "1.21.0", "@react-native-clipboard/clipboard": "1.13.2", "@react-native-community/push-notification-ios": "1.11.0", - "@react-navigation/drawer": "6.6.6", - "@react-navigation/native": "6.1.9", - "@react-navigation/native-stack": "6.9.17", + "@react-navigation/drawer": "6.6.7", + "@react-navigation/native": "6.1.10", + "@react-navigation/native-stack": "6.9.18", "@remobile/react-native-qrcode-local-image": "https://github.com/BlueWallet/react-native-qrcode-local-image", "@spsina/bip47": "github:BlueWallet/bip47#0a2f02c90350802f2ec93afa4e6c8843be2d687c", "aezeed": "0.0.5", @@ -42,7 +42,7 @@ "coinselect": "3.1.13", "crypto-js": "4.2.0", "dayjs": "1.11.10", - "detox": "20.17.0", + "detox": "20.17.1", "ecpair": "2.0.1", "ecurve": "1.0.6", "electrum-client": "github:BlueWallet/rn-electrum-client#1bfe3cc", @@ -89,7 +89,7 @@ "react-native-quick-actions": "0.3.13", "react-native-randombytes": "3.6.1", "react-native-rate": "1.2.12", - "react-native-reanimated": "3.6.2", + "react-native-reanimated": "3.7.0", "react-native-safe-area-context": "4.9.0", "react-native-screens": "3.29.0", "react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48", @@ -98,7 +98,7 @@ "react-native-tcp-socket": "6.0.6", "react-native-vector-icons": "10.0.3", "react-native-watch-connectivity": "1.1.0", - "react-native-webview": "13.7.1", + "react-native-webview": "13.8.1", "react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38", "readable-stream": "3.6.2", "realm": "12.6.0", @@ -117,12 +117,14 @@ "@react-native/eslint-config": "^0.72.2", "@react-native/metro-config": "^0.73.0", "@tsconfig/react-native": "^3.0.2", + "@types/bip38": "^3.1.2", "@types/bs58check": "^2.1.0", "@types/create-hash": "^1.2.2", "@types/jest": "^29.4.0", "@types/react": "^18.2.16", "@types/react-native": "^0.72.0", "@types/react-test-renderer": "^18.0.0", + "@types/wif": "^2.0.5", "@typescript-eslint/eslint-plugin": "^6.2.0", "@typescript-eslint/parser": "^6.2.0", "eslint": "^8.45.0", @@ -6379,11 +6381,11 @@ } }, "node_modules/@react-navigation/drawer": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.6.6.tgz", - "integrity": "sha512-DW/oNRisSOGOqvZfCzfhKBxnzT97Teqtg1Gal85g+K3gnVbM1jOBE2PdnYsKU0fULfFtDwvp/QZSbcgjDpr12A==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.6.7.tgz", + "integrity": "sha512-9hSJySPQcG33vV199uzkI3jHewvAGjVFF2bhC28TkQYDKtp/DmtTvjCEiecOm+qep1Qp4ksh5vBo2P0A1hF6vQ==", "dependencies": { - "@react-navigation/elements": "^1.3.21", + "@react-navigation/elements": "^1.3.22", "color": "^4.2.3", "warn-once": "^0.1.0" }, @@ -6398,9 +6400,9 @@ } }, "node_modules/@react-navigation/elements": { - "version": "1.3.21", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.21.tgz", - "integrity": "sha512-eyS2C6McNR8ihUoYfc166O1D8VYVh9KIl0UQPI8/ZJVsStlfSTgeEEh+WXge6+7SFPnZ4ewzEJdSAHH+jzcEfg==", + "version": "1.3.22", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.22.tgz", + "integrity": "sha512-HYKucs0TwQT8zMvgoZbJsY/3sZfzeP8Dk9IDv4agst3zlA7ReTx4+SROCG6VGC7JKqBCyQykHIwkSwxhapoc+Q==", "peerDependencies": { "@react-navigation/native": "^6.0.0", "react": "*", @@ -6409,9 +6411,9 @@ } }, "node_modules/@react-navigation/native": { - "version": "6.1.9", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.9.tgz", - "integrity": "sha512-AMuJDpwXE7UlfyhIXaUCCynXmv69Kb8NzKgKJO7v0k0L+u6xUTbt6xvshmJ79vsvaFyaEH9Jg5FMzek5/S5qNw==", + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.10.tgz", + "integrity": "sha512-jDG89TbZItY7W7rIcS1RqT63vWOPD4XuQLNKqZO0DY7mKnKh/CGBd0eg3nDMXUl143Qp//IxJKe2TfBQRDEU4A==", "dependencies": { "@react-navigation/core": "^6.4.10", "escape-string-regexp": "^4.0.0", @@ -6424,11 +6426,11 @@ } }, "node_modules/@react-navigation/native-stack": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.17.tgz", - "integrity": "sha512-X8p8aS7JptQq7uZZNFEvfEcPf6tlK4PyVwYDdryRbG98B4bh2wFQYMThxvqa+FGEN7USEuHdv2mF0GhFKfX0ew==", + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.18.tgz", + "integrity": "sha512-PSe0qjROy8zD78ehW048NSuzWRktioSCJmB8LzWSR65ndgVaC2rO+xvgyjhHjqm01YdyVM1XTct2EorSjDV2Ow==", "dependencies": { - "@react-navigation/elements": "^1.3.21", + "@react-navigation/elements": "^1.3.22", "warn-once": "^0.1.0" }, "peerDependencies": { @@ -6556,6 +6558,15 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/bip38": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/bip38/-/bip38-3.1.2.tgz", + "integrity": "sha512-KF5aiS7DUJs2llJJeg1O1Io129PETszfUfDQotJ4VPBXzytpIUmb7n2MHWEdFYRHs2LYoaRivP/aJbTlF56J+Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", @@ -6719,6 +6730,15 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, + "node_modules/@types/wif": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.5.tgz", + "integrity": "sha512-addYBlYjDxLfJxDUoyTzICnu0u4snCdGJpICIIFk65zGcdjah3twTJq1Fdy+OdeZSRiof2raFtMqSqF9KeqthQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "16.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.9.tgz", @@ -9626,9 +9646,9 @@ } }, "node_modules/detox": { - "version": "20.17.0", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.17.0.tgz", - "integrity": "sha512-IasYgexfkrCoZuJTaqqKHQ2yflK+tnqifzdLwrp4hdTWlXUlG9j/YcM1Dn3ThSs3b6VNMtbSe6xoPkKD0oNiIQ==", + "version": "20.17.1", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.17.1.tgz", + "integrity": "sha512-10pey6CR9D5GSloRkH60ObBGZ8VS11H7iuBNY7qq6jO2swiqqckHhPLRXfH9+WGR7l3vDnfU+G/gQs7JxQkJwA==", "hasInstallScript": true, "dependencies": { "ajv": "^8.6.3", @@ -19875,9 +19895,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.2.tgz", - "integrity": "sha512-IIMREMOrxhtK35drfpzh2UhxNqAOHnuvGgtMofj7yHcMj16tmWZR2zFvMUf6z2MfmXv+aVgFQ6TRZ6yKYf7LNA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.7.0.tgz", + "integrity": "sha512-KM+MKa3CJWqsF4GlOLLKBxTR2NEcrg5/HP9J2b6Dfgvll1sjZPywCOEEIh967SboEU8N9LjYZuoVm2UoXGxp2Q==", "dependencies": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -20053,9 +20073,9 @@ } }, "node_modules/react-native-webview": { - "version": "13.7.1", - "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.7.1.tgz", - "integrity": "sha512-tnfTgjIYY3KnBfbN9hRCJf2y/6JZBev3aq2ZacLml0AZn4ufTe4MyCiE1NAZ/l5WHV/1eaqN0srxn45ATL0+Ow==", + "version": "13.8.1", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.1.tgz", + "integrity": "sha512-7Jqm1WzWJrOWraBAXQfKtr/Uo5Jw/IJHzC40jYLwgV/eVGmLJ9BpGKw6QVw7wpRkjmTZ2Typ4B1aHJLJJQFslA==", "dependencies": { "escape-string-regexp": "2.0.0", "invariant": "2.2.4" @@ -27344,24 +27364,24 @@ } }, "@react-navigation/drawer": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.6.6.tgz", - "integrity": "sha512-DW/oNRisSOGOqvZfCzfhKBxnzT97Teqtg1Gal85g+K3gnVbM1jOBE2PdnYsKU0fULfFtDwvp/QZSbcgjDpr12A==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/@react-navigation/drawer/-/drawer-6.6.7.tgz", + "integrity": "sha512-9hSJySPQcG33vV199uzkI3jHewvAGjVFF2bhC28TkQYDKtp/DmtTvjCEiecOm+qep1Qp4ksh5vBo2P0A1hF6vQ==", "requires": { - "@react-navigation/elements": "^1.3.21", + "@react-navigation/elements": "^1.3.22", "color": "^4.2.3", "warn-once": "^0.1.0" } }, "@react-navigation/elements": { - "version": "1.3.21", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.21.tgz", - "integrity": "sha512-eyS2C6McNR8ihUoYfc166O1D8VYVh9KIl0UQPI8/ZJVsStlfSTgeEEh+WXge6+7SFPnZ4ewzEJdSAHH+jzcEfg==" + "version": "1.3.22", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.22.tgz", + "integrity": "sha512-HYKucs0TwQT8zMvgoZbJsY/3sZfzeP8Dk9IDv4agst3zlA7ReTx4+SROCG6VGC7JKqBCyQykHIwkSwxhapoc+Q==" }, "@react-navigation/native": { - "version": "6.1.9", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.9.tgz", - "integrity": "sha512-AMuJDpwXE7UlfyhIXaUCCynXmv69Kb8NzKgKJO7v0k0L+u6xUTbt6xvshmJ79vsvaFyaEH9Jg5FMzek5/S5qNw==", + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.1.10.tgz", + "integrity": "sha512-jDG89TbZItY7W7rIcS1RqT63vWOPD4XuQLNKqZO0DY7mKnKh/CGBd0eg3nDMXUl143Qp//IxJKe2TfBQRDEU4A==", "requires": { "@react-navigation/core": "^6.4.10", "escape-string-regexp": "^4.0.0", @@ -27370,11 +27390,11 @@ } }, "@react-navigation/native-stack": { - "version": "6.9.17", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.17.tgz", - "integrity": "sha512-X8p8aS7JptQq7uZZNFEvfEcPf6tlK4PyVwYDdryRbG98B4bh2wFQYMThxvqa+FGEN7USEuHdv2mF0GhFKfX0ew==", + "version": "6.9.18", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.18.tgz", + "integrity": "sha512-PSe0qjROy8zD78ehW048NSuzWRktioSCJmB8LzWSR65ndgVaC2rO+xvgyjhHjqm01YdyVM1XTct2EorSjDV2Ow==", "requires": { - "@react-navigation/elements": "^1.3.21", + "@react-navigation/elements": "^1.3.22", "warn-once": "^0.1.0" } }, @@ -27490,6 +27510,15 @@ "@babel/types": "^7.20.7" } }, + "@types/bip38": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/bip38/-/bip38-3.1.2.tgz", + "integrity": "sha512-KF5aiS7DUJs2llJJeg1O1Io129PETszfUfDQotJ4VPBXzytpIUmb7n2MHWEdFYRHs2LYoaRivP/aJbTlF56J+Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/bn.js": { "version": "4.11.6", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", @@ -27655,6 +27684,15 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, + "@types/wif": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.5.tgz", + "integrity": "sha512-addYBlYjDxLfJxDUoyTzICnu0u4snCdGJpICIIFk65zGcdjah3twTJq1Fdy+OdeZSRiof2raFtMqSqF9KeqthQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/yargs": { "version": "16.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.9.tgz", @@ -29873,9 +29911,9 @@ "dev": true }, "detox": { - "version": "20.17.0", - "resolved": "https://registry.npmjs.org/detox/-/detox-20.17.0.tgz", - "integrity": "sha512-IasYgexfkrCoZuJTaqqKHQ2yflK+tnqifzdLwrp4hdTWlXUlG9j/YcM1Dn3ThSs3b6VNMtbSe6xoPkKD0oNiIQ==", + "version": "20.17.1", + "resolved": "https://registry.npmjs.org/detox/-/detox-20.17.1.tgz", + "integrity": "sha512-10pey6CR9D5GSloRkH60ObBGZ8VS11H7iuBNY7qq6jO2swiqqckHhPLRXfH9+WGR7l3vDnfU+G/gQs7JxQkJwA==", "requires": { "ajv": "^8.6.3", "bunyan": "^1.8.12", @@ -37593,9 +37631,9 @@ } }, "react-native-reanimated": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.6.2.tgz", - "integrity": "sha512-IIMREMOrxhtK35drfpzh2UhxNqAOHnuvGgtMofj7yHcMj16tmWZR2zFvMUf6z2MfmXv+aVgFQ6TRZ6yKYf7LNA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.7.0.tgz", + "integrity": "sha512-KM+MKa3CJWqsF4GlOLLKBxTR2NEcrg5/HP9J2b6Dfgvll1sjZPywCOEEIh967SboEU8N9LjYZuoVm2UoXGxp2Q==", "requires": { "@babel/plugin-transform-object-assign": "^7.16.7", "@babel/preset-typescript": "^7.16.7", @@ -37709,9 +37747,9 @@ } }, "react-native-webview": { - "version": "13.7.1", - "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.7.1.tgz", - "integrity": "sha512-tnfTgjIYY3KnBfbN9hRCJf2y/6JZBev3aq2ZacLml0AZn4ufTe4MyCiE1NAZ/l5WHV/1eaqN0srxn45ATL0+Ow==", + "version": "13.8.1", + "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.1.tgz", + "integrity": "sha512-7Jqm1WzWJrOWraBAXQfKtr/Uo5Jw/IJHzC40jYLwgV/eVGmLJ9BpGKw6QVw7wpRkjmTZ2Typ4B1aHJLJJQFslA==", "requires": { "escape-string-regexp": "2.0.0", "invariant": "2.2.4" diff --git a/package.json b/package.json index 6adc5d269..4741fb31f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bluewallet", - "version": "6.5.2", + "version": "6.5.3", "license": "MIT", "repository": { "type": "git", @@ -13,12 +13,14 @@ "@react-native/eslint-config": "^0.72.2", "@react-native/metro-config": "^0.73.0", "@tsconfig/react-native": "^3.0.2", + "@types/bip38": "^3.1.2", "@types/bs58check": "^2.1.0", "@types/create-hash": "^1.2.2", "@types/jest": "^29.4.0", "@types/react": "^18.2.16", "@types/react-native": "^0.72.0", "@types/react-test-renderer": "^18.0.0", + "@types/wif": "^2.0.5", "@typescript-eslint/eslint-plugin": "^6.2.0", "@typescript-eslint/parser": "^6.2.0", "eslint": "^8.45.0", @@ -95,7 +97,7 @@ }, "dependencies": { "@babel/preset-env": "^7.20.0", - "@bugsnag/react-native": "7.22.4", + "@bugsnag/react-native": "7.22.5", "@bugsnag/source-maps": "2.3.1", "@keystonehq/bc-ur-registry": "0.6.4", "@ngraveio/bc-ur": "1.1.6", @@ -173,7 +175,7 @@ "react-native-quick-actions": "0.3.13", "react-native-randombytes": "3.6.1", "react-native-rate": "1.2.12", - "react-native-reanimated": "3.6.2", + "react-native-reanimated": "3.7.0", "react-native-safe-area-context": "4.9.0", "react-native-screens": "3.29.0", "react-native-secure-key-store": "https://github.com/BlueWallet/react-native-secure-key-store#2076b48", @@ -182,7 +184,7 @@ "react-native-tcp-socket": "6.0.6", "react-native-vector-icons": "10.0.3", "react-native-watch-connectivity": "1.1.0", - "react-native-webview": "13.7.1", + "react-native-webview": "13.8.1", "react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38", "readable-stream": "3.6.2", "realm": "12.6.0", diff --git a/screen/PlausibleDeniability.tsx b/screen/PlausibleDeniability.tsx index 80813cbf0..5d3b7b41f 100644 --- a/screen/PlausibleDeniability.tsx +++ b/screen/PlausibleDeniability.tsx @@ -9,7 +9,6 @@ import { BlueStorageContext } from '../blue_modules/storage-context'; import presentAlert from '../components/Alert'; import Button from '../components/Button'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../blue_modules/hapticFeedback'; -import SafeArea from '../components/SafeArea'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; const prompt = require('../helpers/prompt'); @@ -75,14 +74,12 @@ const PlausibleDeniability: React.FC = () => { } }; - return state.isLoading ? ( - - - - ) : ( - - - + return ( + + {state.isLoading ? ( + + ) : ( + {loc.plausibledeniability.help} {loc.plausibledeniability.help2} @@ -92,9 +89,9 @@ const PlausibleDeniability: React.FC = () => { title={loc.plausibledeniability.create_fake_storage} onPress={handleOnCreateFakeStorageButtonPressed} /> - - - + + )} + ); }; diff --git a/screen/lnd/ldkOpenChannel.tsx b/screen/lnd/ldkOpenChannel.tsx index 4230a25d3..a0e25de9d 100644 --- a/screen/lnd/ldkOpenChannel.tsx +++ b/screen/lnd/ldkOpenChannel.tsx @@ -77,16 +77,12 @@ const LdkOpenChannel = (props: any) => { }, [psbt]); useEffect(() => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore Biometric.isBiometricUseCapableAndEnabled().then(setIsBiometricUseCapableAndEnabled); }, []); const finalizeOpenChannel = async () => { setIsLoading(true); if (isBiometricUseCapableAndEnabled) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore if (!(await Biometric.unlockWithBiometrics())) { setIsLoading(false); return; diff --git a/screen/send/broadcast.js b/screen/send/broadcast.js index d7581268a..c641d17dd 100644 --- a/screen/send/broadcast.js +++ b/screen/send/broadcast.js @@ -23,8 +23,7 @@ import Button from '../../components/Button'; import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback'; import SafeArea from '../../components/SafeArea'; import presentAlert from '../../components/Alert'; - -const scanqr = require('../../helpers/scan-qr'); +import { scanQrHelper } from '../../helpers/scan-qr'; const BROADCAST_RESULT = Object.freeze({ none: 'Input transaction hex', @@ -78,7 +77,7 @@ const Broadcast = () => { }; const handleQRScan = async () => { - const scannedData = await scanqr(navigate, name); + const scannedData = await scanQrHelper(navigate, name); if (!scannedData) return; if (scannedData.indexOf('+') === -1 && scannedData.indexOf('=') === -1 && scannedData.indexOf('=') === -1) { diff --git a/screen/settings/Licensing.tsx b/screen/settings/Licensing.tsx index 87bf3f369..bde2929ab 100644 --- a/screen/settings/Licensing.tsx +++ b/screen/settings/Licensing.tsx @@ -2,40 +2,37 @@ import React from 'react'; import { ScrollView } from 'react-native'; import navigationStyle from '../../components/navigationStyle'; import { BlueCard, BlueText, BlueSpacing20 } from '../../BlueComponents'; -import SafeArea from '../../components/SafeArea'; import loc from '../../loc'; const Licensing = () => { return ( - - - - MIT License - - Copyright (c) 2018-2024 BlueWallet developers - - - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - + + + MIT License + + Copyright (c) 2018-2024 BlueWallet developers + + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, + merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + - - The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - - + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - - - + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + ); }; diff --git a/screen/settings/encryptStorage.js b/screen/settings/encryptStorage.js index acb366f51..8754f9949 100644 --- a/screen/settings/encryptStorage.js +++ b/screen/settings/encryptStorage.js @@ -53,8 +53,8 @@ const EncryptStorage = () => { popToTop(); } catch (e) { if (password) { - presentAlert({ message: loc._.bad_password }); triggerHapticFeedback(HapticFeedbackTypes.NotificationError); + presentAlert({ message: loc._.bad_password }); } setIsLoading(false); @@ -83,6 +83,7 @@ const EncryptStorage = () => { saveToDisk(); } else { setIsLoading(false); + triggerHapticFeedback(HapticFeedbackTypes.NotificationError); presentAlert({ message: loc.settings.passwords_do_not_match }); } } else { @@ -124,7 +125,7 @@ const EncryptStorage = () => { }; return isLoading ? ( - + ) : ( diff --git a/screen/wallets/list.js b/screen/wallets/list.js index 69d975c78..dd0515253 100644 --- a/screen/wallets/list.js +++ b/screen/wallets/list.js @@ -36,8 +36,15 @@ const WalletsListSections = { CAROUSEL: 'CAROUSEL', TRANSACTIONS: 'TRANSACTIONS' const WalletsList = () => { const walletsCarousel = useRef(); const currentWalletIndex = useRef(0); - const { wallets, getTransactions, getBalance, refreshAllWalletTransactions, setSelectedWalletID, isElectrumDisabled } = - useContext(BlueStorageContext); + const { + wallets, + getTransactions, + getBalance, + refreshAllWalletTransactions, + setSelectedWalletID, + isElectrumDisabled, + setReloadTransactionsMenuActionFunction, + } = useContext(BlueStorageContext); const { width } = useWindowDimensions(); const { colors, scanImage } = useTheme(); const { navigate, setOptions } = useNavigation(); @@ -67,6 +74,10 @@ const WalletsList = () => { useCallback(() => { verifyBalance(); setSelectedWalletID(undefined); + setReloadTransactionsMenuActionFunction(onRefresh); + return () => { + setReloadTransactionsMenuActionFunction(() => {}); + }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []), ); @@ -352,6 +363,12 @@ const WalletsList = () => { refreshTransactions(true, false); }; + const refreshProps = isDesktop + ? {} + : { + ...(isElectrumDisabled ? {} : { refreshing: isLoading, onRefresh }), + }; + return ( @@ -359,8 +376,7 @@ const WalletsList = () => { removeClippedSubviews contentInsetAdjustmentBehavior="automatic" automaticallyAdjustContentInsets - refreshing={isLoading} - {...(isElectrumDisabled ? {} : { refreshing: isLoading, onRefresh })} + {...refreshProps} renderItem={renderSectionItem} keyExtractor={sectionListKeyExtractor} renderSectionHeader={renderSectionHeader} diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index ae6af8bcb..76ff4d8b5 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -45,7 +45,14 @@ const buttonFontSize = : PixelRatio.roundToNearestPixel(Dimensions.get('window').width / 26); const WalletTransactions = ({ navigation }) => { - const { wallets, saveToDisk, setSelectedWalletID, walletTransactionUpdateStatus, isElectrumDisabled } = useContext(BlueStorageContext); + const { + wallets, + saveToDisk, + setSelectedWalletID, + walletTransactionUpdateStatus, + isElectrumDisabled, + setReloadTransactionsMenuActionFunction, + } = useContext(BlueStorageContext); const [isLoading, setIsLoading] = useState(false); const { walletID } = useRoute().params; const { name } = useRoute(); @@ -502,6 +509,22 @@ const WalletTransactions = ({ navigation }) => { index, }); + useFocusEffect( + useCallback(() => { + setReloadTransactionsMenuActionFunction(refreshTransactions); + return () => { + setReloadTransactionsMenuActionFunction(undefined); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []), + ); + + const refreshProps = isDesktop + ? {} + : { + ...(isElectrumDisabled ? {} : { refreshing: isLoading, refreshTransactions }), + }; + return ( { {isLightning() && {loc.wallets.list_empty_txs2_lightning}} } - {...(isElectrumDisabled ? {} : { refreshing: isLoading, onRefresh: refreshTransactions })} + {...refreshProps} data={dataSource} extraData={[timeElapsed, dataSource, wallets]} keyExtractor={_keyExtractor} diff --git a/screen/wallets/xpub.js b/screen/wallets/xpub.js deleted file mode 100644 index 2e150c1ab..000000000 --- a/screen/wallets/xpub.js +++ /dev/null @@ -1,122 +0,0 @@ -import React, { useCallback, useContext, useEffect, useState } from 'react'; -import { InteractionManager, ActivityIndicator, View, StyleSheet } from 'react-native'; -import { useFocusEffect, useRoute, useNavigation } from '@react-navigation/native'; -import Share from 'react-native-share'; - -import navigationStyle from '../../components/navigationStyle'; -import { BlueSpacing20, BlueText, BlueCopyTextToClipboard } from '../../BlueComponents'; -import Privacy from '../../blue_modules/Privacy'; -import Biometric from '../../class/biometrics'; -import loc from '../../loc'; -import { BlueStorageContext } from '../../blue_modules/storage-context'; -import QRCodeComponent from '../../components/QRCodeComponent'; -import HandoffComponent from '../../components/handoff'; -import { useTheme } from '../../components/themes'; -import Button from '../../components/Button'; -import SafeArea from '../../components/SafeArea'; - -const styles = StyleSheet.create({ - root: { - flex: 1, - paddingTop: 20, - }, - container: { - alignItems: 'center', - flex: 1, - justifyContent: 'center', - }, - share: { - alignSelf: 'center', - width: '40%', - }, -}); - -const WalletXpub = () => { - const { wallets } = useContext(BlueStorageContext); - const { walletID, xpub } = useRoute().params; - const wallet = wallets.find(w => w.getID() === walletID); - const [isLoading, setIsLoading] = useState(true); - const [xPubText, setXPubText] = useState(); - const { goBack, setParams } = useNavigation(); - const { colors } = useTheme(); - const [qrCodeSize, setQRCodeSize] = useState(90); - const stylesHook = StyleSheet.create({ root: { backgroundColor: colors.elevated } }); - - useFocusEffect( - useCallback(() => { - Privacy.enableBlur(); - const task = InteractionManager.runAfterInteractions(async () => { - if (wallet) { - const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled(); - - if (isBiometricsEnabled) { - if (!(await Biometric.unlockWithBiometrics())) { - return goBack(); - } - } - setParams({ xpub: wallet.getXpub() }); - setIsLoading(false); - } else if (xpub) { - setIsLoading(false); - } - }); - return () => { - task.cancel(); - Privacy.disableBlur(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [goBack, walletID]), - ); - - useEffect(() => { - setXPubText(xpub); - }, [xpub]); - - const onLayout = e => { - const { height, width } = e.nativeEvent.layout; - setQRCodeSize(height > width ? width - 40 : e.nativeEvent.layout.width / 1.8); - }; - - const handleShareButtonPressed = () => { - Share.open({ message: xpub }).catch(error => console.log(error)); - }; - - return isLoading ? ( - - - - ) : ( - - <> - - {wallet && ( - <> - - {wallet.typeReadable} - - - - )} - - - - - - - -