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}
-
-
- >
- )}
-
-
-
-
-
-
-
-
-
- >
-
- );
-};
-
-WalletXpub.navigationOptions = navigationStyle(
- {
- closeButton: true,
- headerBackVisible: false,
- },
- opts => ({ ...opts, headerTitle: loc.wallets.xpub_title }),
-);
-
-export default WalletXpub;
diff --git a/screen/wallets/xpub.styles.ts b/screen/wallets/xpub.styles.ts
new file mode 100644
index 000000000..143535624
--- /dev/null
+++ b/screen/wallets/xpub.styles.ts
@@ -0,0 +1,42 @@
+import { StyleSheet } from 'react-native';
+import { useTheme } from '../../components/themes';
+import { useMemo } from 'react';
+
+export const styles = StyleSheet.create({
+ root: {
+ flex: 1,
+ paddingTop: 20,
+ },
+ container: {
+ alignItems: 'center',
+ flex: 1,
+ justifyContent: 'center',
+ },
+ share: {
+ alignSelf: 'center',
+ width: '40%',
+ },
+});
+
+export const useDynamicStyles = () => {
+ const theme = useTheme();
+
+ const stylesHook = useMemo(
+ () =>
+ StyleSheet.create({
+ root: {
+ backgroundColor: theme.colors.elevated,
+ // Add more dynamic styles as needed
+ },
+ container: {
+ // Example of another dynamic style
+ borderColor: theme.colors.inputBorderColor,
+ borderWidth: 1,
+ },
+ // You can add more dynamically themed styles here
+ }),
+ [theme],
+ ); // Recompute styles only when theme changes
+
+ return stylesHook;
+};
diff --git a/screen/wallets/xpub.tsx b/screen/wallets/xpub.tsx
new file mode 100644
index 000000000..b2e803470
--- /dev/null
+++ b/screen/wallets/xpub.tsx
@@ -0,0 +1,124 @@
+import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
+import { InteractionManager, ActivityIndicator, View } from 'react-native';
+import { useFocusEffect, useRoute, useNavigation, RouteProp, NavigationProp } from '@react-navigation/native';
+import Share from 'react-native-share';
+import { styles, useDynamicStyles } from './xpub.styles';
+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 Button from '../../components/Button';
+import SafeArea from '../../components/SafeArea';
+import { AbstractWallet } from '../../class';
+
+type WalletXpubRouteProp = RouteProp<{ params: { walletID: string; xpub: string } }, 'params'>;
+export type RootStackParamList = {
+ WalletXpub: {
+ walletID: string;
+ xpub: string;
+ };
+};
+
+const WalletXpub: React.FC = () => {
+ const { wallets } = useContext(BlueStorageContext);
+ const route = useRoute();
+ const { walletID, xpub } = route.params;
+ const wallet = wallets.find((w: AbstractWallet) => w.getID() === walletID);
+ const [isLoading, setIsLoading] = useState(true);
+ const [xPubText, setXPubText] = useState(undefined);
+ const navigation = useNavigation>();
+ const stylesHook = useDynamicStyles(); // This now includes the theme implicitly
+ const [qrCodeSize, setQRCodeSize] = useState(90);
+ const lastWalletIdRef = useRef();
+
+ useFocusEffect(
+ useCallback(() => {
+ // Skip execution if walletID hasn't changed
+ if (lastWalletIdRef.current === walletID) {
+ return;
+ }
+ Privacy.enableBlur();
+ const task = InteractionManager.runAfterInteractions(async () => {
+ if (wallet) {
+ const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
+
+ if (isBiometricsEnabled) {
+ if (!(await Biometric.unlockWithBiometrics())) {
+ return navigation.goBack();
+ }
+ }
+ const walletXpub = wallet.getXpub();
+ if (xpub !== walletXpub) {
+ navigation.setParams({ xpub: walletXpub });
+ }
+
+ setIsLoading(false);
+ } else if (xpub) {
+ setIsLoading(false);
+ }
+ });
+ lastWalletIdRef.current = walletID;
+ return () => {
+ task.cancel();
+ Privacy.disableBlur();
+ };
+ }, [wallet, xpub, walletID, navigation]),
+ );
+
+ useEffect(() => {
+ setXPubText(xpub);
+ }, [xpub]);
+
+ const onLayout = (e: { nativeEvent: { layout: { width: any; height?: any } } }) => {
+ const { height, width } = e.nativeEvent.layout;
+ setQRCodeSize(height > width ? width - 40 : e.nativeEvent.layout.width / 1.8);
+ };
+
+ const handleShareButtonPressed = useCallback(() => {
+ Share.open({ message: xpub }).catch(console.log);
+ }, [xpub]);
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+ <>
+
+ {wallet && (
+ <>
+
+ {wallet.typeReadable}
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
+ >
+ )}
+
+ );
+};
+
+// @ts-ignore: Deal with later
+WalletXpub.navigationOptions = navigationStyle(
+ {
+ closeButton: true,
+ headerBackVisible: false,
+ },
+ opts => ({ ...opts, headerTitle: loc.wallets.xpub_title }),
+);
+
+export default WalletXpub;
diff --git a/scripts/build-release-apk.sh b/scripts/build-release-apk.sh
index 8df66d69d..6cdcaada4 100755
--- a/scripts/build-release-apk.sh
+++ b/scripts/build-release-apk.sh
@@ -1,23 +1,28 @@
#!/bin/bash
-
# assumes 2 env variables: KEYSTORE_FILE_HEX & KEYSTORE_PASSWORD
-#
+
# PS. to turn file to hex and back:
# $ xxd -plain test.txt > test.hex
# $ xxd -plain -revert test.hex test2.txt
-
echo $KEYSTORE_FILE_HEX > bluewallet-release-key.keystore.hex
xxd -plain -revert bluewallet-release-key.keystore.hex > ./android/bluewallet-release-key.keystore
rm bluewallet-release-key.keystore.hex
cd android
-TIMESTAMP=$(date +%s)
-sed -i'.original' "s/versionCode 1/versionCode $TIMESTAMP/g" app/build.gradle
+# Use the BUILD_NUMBER environment variable set in the GitHub Actions workflow
+sed -i'.original' "s/versionCode 1/versionCode $BUILD_NUMBER/g" app/build.gradle
+
+# Extract versionName from build.gradle
+VERSION_NAME=$(grep versionName app/build.gradle | awk '{print $2}' | tr -d '"')
+
./gradlew assembleRelease
-mv ./app/build/outputs/apk/release/app-release-unsigned.apk ./app/build/outputs/apk/release/app-release.apk
+
+# Rename the APK file to include the dynamic version and build number with parentheses
+mv ./app/build/outputs/apk/release/app-release-unsigned.apk "./app/build/outputs/apk/release/BlueWallet-${VERSION_NAME}($BUILD_NUMBER).apk"
+
echo wheres waldo?
find $ANDROID_HOME | grep apksigner | grep -v jar
-$ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks ./bluewallet-release-key.keystore --ks-pass=pass:$KEYSTORE_PASSWORD ./app/build/outputs/apk/release/app-release.apk
+$ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks ./bluewallet-release-key.keystore --ks-pass=pass:$KEYSTORE_PASSWORD "./app/build/outputs/apk/release/BlueWallet-${VERSION_NAME}($BUILD_NUMBER).apk"
diff --git a/typings/react-native-passcode-auth.d.ts b/typings/react-native-passcode-auth.d.ts
new file mode 100644
index 000000000..b2af90818
--- /dev/null
+++ b/typings/react-native-passcode-auth.d.ts
@@ -0,0 +1,4 @@
+declare module 'react-native-passcode-auth' {
+ declare function isSupported(): Promise;
+ declare function authenticate(): Promise;
+}