FIX: Disable screen protect until it supports nav 7. Fix speed issue exposed by disabling it

This commit is contained in:
Marcos Rodriguez Velez 2025-02-25 22:24:31 -04:00
parent 685332ce22
commit 3fcf3c0840
18 changed files with 198 additions and 134 deletions

View file

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useRef, useState, memo } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import Clipboard from '@react-native-clipboard/clipboard';
import { Linking, View, ViewStyle } from 'react-native';
@ -36,7 +36,7 @@ interface TransactionListItemProps {
type NavigationProps = NativeStackNavigationProp<DetailViewStackParamList>;
export const TransactionListItem: React.FC<TransactionListItemProps> = React.memo(
export const TransactionListItem: React.FC<TransactionListItemProps> = memo(
({ item, itemPriceUnit = BitcoinUnit.BTC, walletID, searchQuery, style, renderHighlightedText }) => {
const [subtitleNumberOfLines, setSubtitleNumberOfLines] = useState(1);
const { colors } = useTheme();
@ -366,4 +366,12 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
</ToolTipMenu>
);
},
(prevProps, nextProps) => {
return (
prevProps.item.hash === nextProps.item.hash &&
prevProps.item.received === nextProps.item.received &&
prevProps.itemPriceUnit === nextProps.itemPriceUnit &&
prevProps.walletID === nextProps.walletID
);
},
);

23
helpers/screenProtect.ts Normal file
View file

@ -0,0 +1,23 @@
// import { enableSecureView, disableSecureView, forbidAndroidShare, allowAndroidShare } from 'react-native-prevent-screenshot-ios-android';
// import { Platform } from 'react-native';
// import { isDesktop } from '../blue_modules/environment';
export const enableScreenProtect = () => {
// if (isDesktop) return;
// if (Platform.OS === 'ios') {
// enableSecureView();
// } else if (Platform.OS === 'android') {
// forbidAndroidShare();
// }
};
export const disableScreenProtect = () => {
// if (isDesktop) return;
// if (Platform.OS === 'ios') {
// disableSecureView();
// } else if (Platform.OS === 'android') {
// allowAndroidShare();
// }
};
// CURRENTLY UNUSED AS WE WAIT FOR NAV 7 SUPPORT

View file

@ -1443,7 +1443,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
@ -1506,7 +1506,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = A7W54YZ4WU;
@ -1565,7 +1565,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1608,7 +1608,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -1652,7 +1652,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1708,7 +1708,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -1895,7 +1895,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -1948,7 +1948,7 @@
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";
@ -2000,7 +2000,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = "";
@ -2049,7 +2049,7 @@
"CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1703137999;
CURRENT_PROJECT_VERSION = 1703138999;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = "";

View file

@ -1322,18 +1322,37 @@ PODS:
- React-Core
- react-native-menu (1.2.1):
- React
- react-native-prevent-screenshot-ios-android (1.1.0):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2024.01.01.00)
- RCTRequired
- RCTTypeSafety
- React-Core
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-NativeModulesApple
- React-RCTFabric
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-randombytes (3.6.1):
- React-Core
- react-native-safe-area-context (5.2.0):
- React-Core
- react-native-screen-capture (0.2.3):
- React
- react-native-secure-key-store (2.0.10):
- React-Core
- react-native-tcp-socket (6.2.0):
- CocoaAsyncSocket
- React-Core
- react-native-true-sheet (1.1.1):
- react-native-true-sheet (2.0.0):
- DoubleConversion
- glog
- hermes-engine
@ -1941,9 +1960,9 @@ DEPENDENCIES:
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`)
- "react-native-menu (from `../node_modules/@react-native-menu/menu`)"
- react-native-prevent-screenshot-ios-android (from `../node_modules/react-native-prevent-screenshot-ios-android`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-screen-capture (from `../node_modules/react-native-screen-capture`)
- react-native-secure-key-store (from `../node_modules/react-native-secure-key-store`)
- react-native-tcp-socket (from `../node_modules/react-native-tcp-socket`)
- "react-native-true-sheet (from `../node_modules/@lodev09/react-native-true-sheet`)"
@ -2098,12 +2117,12 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-ios-context-menu"
react-native-menu:
:path: "../node_modules/@react-native-menu/menu"
react-native-prevent-screenshot-ios-android:
:path: "../node_modules/react-native-prevent-screenshot-ios-android"
react-native-randombytes:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-screen-capture:
:path: "../node_modules/react-native-screen-capture"
react-native-secure-key-store:
:path: "../node_modules/react-native-secure-key-store"
react-native-tcp-socket:
@ -2261,12 +2280,12 @@ SPEC CHECKSUMS:
react-native-image-picker: 130fad649d07e4eec8faaed361d3bba570e1e5ff
react-native-ios-context-menu: 986da6dcba70094bcc2a8049f68410fe7d25aff1
react-native-menu: 2cfe0a3b3c610ed331f00d9f0df300db14ba8692
react-native-prevent-screenshot-ios-android: 490b2ae701658753e819ca215201f4aa8cab3d53
react-native-randombytes: 3c8f3e89d12487fd03a2f966c288d495415fc116
react-native-safe-area-context: 3e33e7c43c8b74dba436a5a32651cb8d7064c740
react-native-screen-capture: 7b6121f529681ed2fde36cdedadd0bb39e9a3796
react-native-secure-key-store: eb45b44bdec3f48e9be5cdfca0f49ddf64892ea6
react-native-tcp-socket: 61379457d7e702e83e28c213b6e085ac079e480f
react-native-true-sheet: 58c0848a4326fd2eb7eedd266ec0f39e7c70e5bd
react-native-true-sheet: 15f8d1bfbf2aceca472b9ba585b4116041d20f34
React-nativeconfig: 67fa7a63ea288cb5b1d0dd2deaf240405fec164f
React-NativeModulesApple: 34b7a4d7441a4ee78d18109ff107c1ccf7c074a9
React-perflogger: d1149037ac466ad2141d4ae541ca16cb73b2343b

31
package-lock.json generated
View file

@ -14,7 +14,7 @@
"@bugsnag/react-native": "8.2.0",
"@bugsnag/source-maps": "2.3.3",
"@keystonehq/bc-ur-registry": "0.7.0",
"@lodev09/react-native-true-sheet": "github:BlueWallet/react-native-true-sheet#0fefdd1aca07fcc3c204f6f1511f9fc0a2c59111",
"@lodev09/react-native-true-sheet": "github:BlueWallet/react-native-true-sheet#5945184a2fea9fe5ba8f5cfcdb20e3fc5eed6e37",
"@ngraveio/bc-ur": "1.1.13",
"@noble/secp256k1": "1.6.3",
"@react-native-async-storage/async-storage": "2.1.0",
@ -83,6 +83,7 @@
"react-native-linear-gradient": "2.8.3",
"react-native-localize": "3.4.1",
"react-native-permissions": "5.2.5",
"react-native-prevent-screenshot-ios-android": "github:BlueWallet/react-native-prevent-screenshot-ios-android#133004e",
"react-native-prompt-android": "github:BlueWallet/react-native-prompt-android#ed168d66fed556bc2ed07cf498770f058b78a376",
"react-native-push-notification": "8.1.1",
"react-native-qrcode-svg": "6.3.12",
@ -91,7 +92,6 @@
"react-native-rate": "1.2.12",
"react-native-reanimated": "3.16.7",
"react-native-safe-area-context": "5.2.0",
"react-native-screen-capture": "github:BlueWallet/react-native-screen-capture#18cb79f",
"react-native-screens": "4.9.0",
"react-native-secure-key-store": "github:BlueWallet/react-native-secure-key-store#2076b4849e88aa0a78e08bfbb4ce3923e0925cbc",
"react-native-share": "11.1.0",
@ -4699,9 +4699,9 @@
}
},
"node_modules/@lodev09/react-native-true-sheet": {
"version": "1.1.1",
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-true-sheet.git#0fefdd1aca07fcc3c204f6f1511f9fc0a2c59111",
"integrity": "sha512-44sy92Jofy5dmKYpu9CYAHEHnEUnZPvy5bCSCvlg/2W3HlIUY2IKp81VzrFLf7XvDO7ZREqNsTt4QsaOH+GUnQ==",
"version": "2.0.0",
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-true-sheet.git#5945184a2fea9fe5ba8f5cfcdb20e3fc5eed6e37",
"integrity": "sha512-JoMgC3w8Xgzvb4zHRnBdycBDuhz1O8MuKh9LE3QJjCElcm8x0n3asHzrt+XaLs3XfVrvq/LNyIMQSSYtvvhFKA==",
"license": "MIT",
"workspaces": [
"example",
@ -21973,6 +21973,18 @@
}
}
},
"node_modules/react-native-prevent-screenshot-ios-android": {
"version": "1.1.0",
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-prevent-screenshot-ios-android.git#133004eff4b2e95176ad2a8cc1d6aa61ea43be98",
"license": "MIT",
"engines": {
"node": ">= 16.0.0"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-prompt-android": {
"version": "1.0.0",
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-prompt-android.git#ed168d66fed556bc2ed07cf498770f058b78a376",
@ -22091,15 +22103,6 @@
"react-native": "*"
}
},
"node_modules/react-native-screen-capture": {
"version": "0.2.3",
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-screen-capture.git#18cb79f0cd3edf189c8fac926ee8cdb8a58b1174",
"license": "MIT",
"peerDependencies": {
"react": ">=17.0.2",
"react-native": ">=0.67.0-rc.0 <1.0.x"
}
},
"node_modules/react-native-screens": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.9.0.tgz",

View file

@ -94,6 +94,7 @@
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#038a9c9",
"@react-native/gradle-plugin": "0.76.7",
"@react-native/metro-config": "0.76.7",
"@react-navigation/devtools": "7.0.15",
"@react-navigation/drawer": "7.1.1",
"@react-navigation/native": "7.0.14",
"@react-navigation/native-stack": "7.2.0",
@ -150,6 +151,7 @@
"react-native-linear-gradient": "2.8.3",
"react-native-localize": "3.4.1",
"react-native-permissions": "5.2.5",
"react-native-prevent-screenshot-ios-android": "github:BlueWallet/react-native-prevent-screenshot-ios-android#133004e",
"react-native-prompt-android": "github:BlueWallet/react-native-prompt-android#ed168d66fed556bc2ed07cf498770f058b78a376",
"react-native-push-notification": "8.1.1",
"react-native-qrcode-svg": "6.3.12",
@ -157,9 +159,7 @@
"react-native-randombytes": "3.6.1",
"react-native-rate": "1.2.12",
"react-native-reanimated": "3.16.7",
"@react-navigation/devtools": "7.0.15",
"react-native-safe-area-context": "5.2.0",
"react-native-screen-capture": "github:BlueWallet/react-native-screen-capture#18cb79f",
"react-native-screens": "4.9.0",
"react-native-secure-key-store": "github:BlueWallet/react-native-secure-key-store#2076b4849e88aa0a78e08bfbb4ce3923e0925cbc",
"react-native-share": "11.1.0",

View file

@ -9,17 +9,16 @@ import { Icon } from '@rneui/themed';
import RNFS from 'react-native-fs';
import { PERMISSIONS, request, RESULTS } from 'react-native-permissions';
import Share from 'react-native-share';
import { satoshiToBTC } from '../../blue_modules/currency';
import { isDesktop } from '../../blue_modules/environment';
import { BlueSpacing20, BlueText } from '../../BlueComponents';
import presentAlert from '../../components/Alert';
import { DynamicQRCode } from '../../components/DynamicQRCode';
import { useTheme } from '../../components/themes';
import { disallowScreenshot } from 'react-native-screen-capture';
import loc from '../../loc';
import { BitcoinUnit } from '../../models/bitcoinUnits';
import { useSettings } from '../../hooks/context/useSettings';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
const SendCreate = () => {
const { fee, recipients, memo = '', satoshiPerByte, psbt, showAnimatedQr, tx } = useRoute().params;
@ -49,9 +48,11 @@ const SendCreate = () => {
useEffect(() => {
console.log('send/create - useEffect');
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
if (isPrivacyBlurEnabled) {
enableScreenProtect();
}
return () => {
if (!isDesktop) disallowScreenshot(false);
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]);

View file

@ -7,12 +7,11 @@ import { DynamicQRCode } from '../../components/DynamicQRCode';
import SaveFileButton from '../../components/SaveFileButton';
import { SquareButton } from '../../components/SquareButton';
import { useTheme } from '../../components/themes';
import { disallowScreenshot } from 'react-native-screen-capture';
import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage';
import { ExportMultisigCoordinationSetupStackRootParamList } from '../../navigation/ExportMultisigCoordinationSetupStack';
import { useSettings } from '../../hooks/context/useSettings';
import { isDesktop } from '../../blue_modules/environment';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
const enum ActionType {
SET_LOADING = 'SET_LOADING',
@ -102,7 +101,6 @@ const ExportMultisigCoordinationSetup: React.FC = () => {
dispatch({ type: ActionType.SET_LOADING, isLoading: true });
const task = InteractionManager.runAfterInteractions(() => {
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
if (wallet) {
setTimeout(async () => {
try {
@ -128,12 +126,22 @@ const ExportMultisigCoordinationSetup: React.FC = () => {
return () => {
task.cancel();
if (!isDesktop) disallowScreenshot(false);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletID]),
);
useFocusEffect(
useCallback(() => {
if (isPrivacyBlurEnabled) {
enableScreenProtect();
}
return () => {
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]),
);
useFocusEffect(
useCallback(() => {
if (closeButtonState) {

View file

@ -16,10 +16,9 @@ import { useStorage } from '../../hooks/context/useStorage';
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { THDWalletForWatchOnly, TWallet } from '../../class/wallets/types';
import { keepAwake, disallowScreenshot } from 'react-native-screen-capture';
import { useSettings } from '../../hooks/context/useSettings';
import { isDesktop } from '../../blue_modules/environment';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportWalletDiscovery'>;
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'ImportWalletDiscovery'>;
@ -39,7 +38,7 @@ const ImportWalletDiscovery: React.FC = () => {
const { colors } = useTheme();
const route = useRoute<RouteProps>();
const { importText, askPassphrase, searchAccounts } = route.params;
const { isElectrumDisabled } = useSettings();
const { isElectrumDisabled, isPrivacyBlurEnabled } = useSettings();
const task = useRef<TImport | null>(null);
const { addAndSaveWallet } = useStorage();
const [loading, setLoading] = useState<boolean>(true);
@ -115,7 +114,6 @@ const ImportWalletDiscovery: React.FC = () => {
}
};
if (!isDesktop) keepAwake(true);
task.current = startImport(importText, askPassphrase, searchAccounts, isElectrumDisabled, onProgress, onWallet, onPassword);
task.current.promise
@ -134,22 +132,24 @@ const ImportWalletDiscovery: React.FC = () => {
.finally(() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setLoading(false);
if (!isDesktop) keepAwake(false);
});
return () => {
if (!isDesktop) keepAwake(false);
task.current?.stop();
};
}, [askPassphrase, importText, isElectrumDisabled, navigation, saveWallet, searchAccounts]);
useEffect(() => {
if (isPrivacyBlurEnabled) {
enableScreenProtect();
}
return () => {
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]);
const handleCustomDerivation = () => {
task.current?.stop();
if (!isDesktop) {
keepAwake(false);
disallowScreenshot(false);
}
navigation.navigate('ImportCustomDerivationPath', { importText, password });
};

View file

@ -1,17 +1,16 @@
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
import { RouteProp, useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import React, { useCallback, useEffect } from 'react';
import { BackHandler, I18nManager, ScrollView, StyleSheet, Text, View } from 'react-native';
import { disallowScreenshot } from 'react-native-screen-capture';
import Button from '../../components/Button';
import { useTheme } from '../../components/themes';
import { useSettings } from '../../hooks/context/useSettings';
import { useStorage } from '../../hooks/context/useStorage';
import loc from '../../loc';
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
import { isDesktop } from '../../blue_modules/environment';
import SeedWords from '../../components/SeedWords';
import { disableScreenProtect, enableScreenProtect } from '../../helpers/screenProtect';
type RouteProps = RouteProp<AddWalletStackParamList, 'PleaseBackup'>;
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'PleaseBackup'>;
@ -34,21 +33,27 @@ const PleaseBackup: React.FC = () => {
});
const handleBackButton = useCallback(() => {
// @ts-ignore: Ignore
navigation.getParent()?.goBack();
return true;
}, [navigation]);
useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
if (!isDesktop) disallowScreenshot(false);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useFocusEffect(
useCallback(() => {
if (isPrivacyBlurEnabled) enableScreenProtect();
return () => {
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]),
);
return (
<ScrollView
style={styles.root}

View file

@ -33,7 +33,7 @@ import { useTheme } from '../../components/themes';
import prompt from '../../helpers/prompt';
import { unlockWithBiometrics, useBiometrics } from '../../hooks/useBiometrics';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { disallowScreenshot } from 'react-native-screen-capture';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
import loc from '../../loc';
import ActionSheet from '../ActionSheet';
import { useStorage } from '../../hooks/context/useStorage';
@ -181,7 +181,7 @@ const ViewEditMultisigCosigners: React.FC = () => {
// useFocusEffect is called on willAppear (example: when camera dismisses). we want to avoid this.
if (hasLoaded.current) return;
setIsLoading(true);
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
if (isPrivacyBlurEnabled) enableScreenProtect();
const task = InteractionManager.runAfterInteractions(async () => {
if (!w.current) {
@ -197,7 +197,7 @@ const ViewEditMultisigCosigners: React.FC = () => {
setIsLoading(false);
});
return () => {
if (!isDesktop) disallowScreenshot(false);
disableScreenProtect();
task.cancel();
};
// eslint-disable-next-line react-hooks/exhaustive-deps

View file

@ -1,10 +1,9 @@
import React, { useCallback, useEffect, useLayoutEffect, useRef, useReducer, useMemo } from 'react';
import { useFocusEffect, useRoute, RouteProp } from '@react-navigation/native';
import { useRoute, RouteProp, useFocusEffect } from '@react-navigation/native';
import { ActivityIndicator, FlatList, StyleSheet, View, Platform, UIManager } from 'react-native';
import { WatchOnlyWallet } from '../../class';
import { AddressItem } from '../../components/addresses/AddressItem';
import { useTheme } from '../../components/themes';
import { disallowScreenshot } from 'react-native-screen-capture';
import { useStorage } from '../../hooks/context/useStorage';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
@ -12,7 +11,8 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import SegmentedControl from '../../components/SegmentControl';
import loc from '../../loc';
import { BitcoinUnit } from '../../models/bitcoinUnits';
import { isDesktop } from '../../blue_modules/environment';
import { useSettings } from '../../hooks/context/useSettings';
import { disableScreenProtect, enableScreenProtect } from '../../helpers/screenProtect';
export const TABS = {
EXTERNAL: 'receive',
@ -131,6 +131,7 @@ const WalletAddresses: React.FC = () => {
const allowSignVerifyMessage = (wallet && 'allowSignVerifyMessage' in wallet && wallet.allowSignVerifyMessage()) ?? false;
const { colors } = useTheme();
const { isPrivacyBlurEnabled } = useSettings();
const { setOptions } = useExtendedNavigation<NavigationProps>();
const stylesHook = StyleSheet.create({
@ -139,6 +140,15 @@ const WalletAddresses: React.FC = () => {
},
});
useFocusEffect(
useCallback(() => {
if (isPrivacyBlurEnabled) enableScreenProtect();
return () => {
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]),
);
const getAddresses = useMemo(() => {
if (!walletInstance) return [];
const newAddresses: Address[] = [];
@ -177,15 +187,6 @@ const WalletAddresses: React.FC = () => {
});
}, [setOptions]);
useFocusEffect(
useCallback(() => {
if (!isDesktop) disallowScreenshot(true);
return () => {
if (!isDesktop) disallowScreenshot(false);
};
}, []),
);
const data =
search.length > 0 ? filteredAddresses.filter(item => item.address.toLowerCase().includes(search.toLowerCase())) : filteredAddresses;

View file

@ -1,10 +1,9 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import Clipboard from '@react-native-clipboard/clipboard';
import { RouteProp, useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
import { RouteProp, useNavigation, useRoute } from '@react-navigation/native';
import { Icon } from '@rneui/themed';
import { ActivityIndicator, InteractionManager, LayoutChangeEvent, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
import { disallowScreenshot } from 'react-native-screen-capture';
import { LayoutChangeEvent, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
import { validateMnemonic } from '../../blue_modules/bip39';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
import { BlueText } from '../../BlueComponents';
@ -15,7 +14,6 @@ import SeedWords from '../../components/SeedWords';
import { useTheme } from '../../components/themes';
import { HandOffActivityType } from '../../components/types';
import { useSettings } from '../../hooks/context/useSettings';
import { isDesktop } from '../../blue_modules/environment';
import { useStorage } from '../../hooks/context/useStorage';
import useAppState from '../../hooks/useAppState';
import loc from '../../loc';
@ -57,9 +55,8 @@ const DoNotDisclose: React.FC = () => {
};
const WalletExport: React.FC = () => {
const { wallets, saveToDisk } = useStorage();
const { wallets } = useStorage();
const { walletID } = useRoute<RouteProps>().params;
const [isLoading, setIsLoading] = useState(true);
const navigation = useNavigation();
const { isPrivacyBlurEnabled } = useSettings();
const { colors } = useTheme();
@ -85,28 +82,20 @@ const WalletExport: React.FC = () => {
}, [wallet]);
useEffect(() => {
if (!isLoading && previousAppState === 'active' && currentAppState !== 'active') {
if (previousAppState === 'active' && currentAppState !== 'active') {
const timer = setTimeout(() => navigation.goBack(), 500);
return () => clearTimeout(timer);
}
}, [currentAppState, previousAppState, navigation, isLoading]);
}, [currentAppState, previousAppState, navigation]);
useFocusEffect(
useCallback(() => {
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
const task = InteractionManager.runAfterInteractions(async () => {
if (!wallet.getUserHasSavedExport()) {
wallet.setUserHasSavedExport(true);
saveToDisk();
}
setIsLoading(false);
});
return () => {
if (!isDesktop) disallowScreenshot(false);
task.cancel();
};
}, [isPrivacyBlurEnabled, wallet, saveToDisk]),
);
useEffect(() => {
if (isPrivacyBlurEnabled) {
enableScreenProtect();
}
return () => {
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]);
const onLayout = useCallback((e: LayoutChangeEvent) => {
const { height, width } = e.nativeEvent.layout;
@ -128,22 +117,13 @@ const WalletExport: React.FC = () => {
contentContainerStyle={styles.scrollViewContent}
onLayout={onLayout}
testID="WalletExportScroll"
centerContent={isLoading}
>
{children}
</ScrollView>
),
[isLoading, onLayout, stylesHook.root],
[onLayout, stylesHook.root],
);
if (isLoading) {
return (
<Scroll>
<ActivityIndicator />
</Scroll>
);
}
// for SLIP39
if (secrets.length !== 1) {
return (
@ -177,7 +157,6 @@ const WalletExport: React.FC = () => {
contentContainerStyle={styles.scrollViewContent}
onLayout={onLayout}
testID="WalletExportScroll"
centerContent={isLoading}
>
{wallet.type !== WatchOnlyWallet.type && <DoNotDisclose />}

View file

@ -297,10 +297,10 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
const renderItem = useCallback(
// eslint-disable-next-line react/no-unused-prop-types
({ item }: { item: Transaction }) => {
return <TransactionListItem item={item} itemPriceUnit={wallet?.preferredBalanceUnit} walletID={walletID} />;
},
[wallet, walletID],
({ item }: { item: Transaction }) => (
<TransactionListItem key={item.hash} item={item} itemPriceUnit={wallet?.preferredBalanceUnit} walletID={walletID} />
),
[wallet?.preferredBalanceUnit, walletID],
);
const choosePhoto = () => {
@ -317,7 +317,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
});
};
const _keyExtractor = (_item: any, index: number) => index.toString();
const _keyExtractor = useCallback((_item: any, index: number) => index.toString(), []);
const pasteFromClipboard = async () => {
onBarCodeRead({ data: await getClipboardContent() });
@ -398,6 +398,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
});
return () => {
task.cancel();
console.debug('Next screen is focused, clearing reloadTransactionsMenuActionFunction');
setReloadTransactionsMenuActionFunction(() => {});
};
}, [setReloadTransactionsMenuActionFunction, refreshTransactions]),
@ -525,7 +526,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
<FlatList<Transaction>
getItemLayout={getItemLayout}
updateCellsBatchingPeriod={30}
updateCellsBatchingPeriod={50}
onEndReachedThreshold={0.3}
onEndReached={loadMoreTransactions}
ListFooterComponent={renderListFooterComponent}
@ -537,7 +538,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
removeClippedSubviews
contentContainerStyle={{ backgroundColor: colors.background }}
contentInset={{ top: 0, left: 0, bottom: 90, right: 0 }}
maxToRenderPerBatch={15}
maxToRenderPerBatch={10}
onScroll={handleScroll}
scrollEventThrottle={16}
stickyHeaderHiddenOnScroll
@ -555,6 +556,10 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }) => {
<RefreshControl refreshing={isLoading} onRefresh={() => refreshTransactions(true)} tintColor={colors.msSuccessCheck} />
) : undefined
}
windowSize={15}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
}}
/>
<FContainer ref={walletActionButtonsRef}>
{wallet?.allowReceive() && (

View file

@ -168,6 +168,7 @@ const WalletsList: React.FC = () => {
});
return () => {
task.cancel();
console.debug('Next screen is focused, clearing reloadTransactionsMenuActionFunction');
setReloadTransactionsMenuActionFunction(() => {});
};
}, [onRefresh, setReloadTransactionsMenuActionFunction, verifyBalance, setSelectedWalletID]),
@ -259,7 +260,7 @@ const WalletsList: React.FC = () => {
const renderTransactionListsRow = useCallback(
(item: ExtendedTransaction) => (
<View style={styles.transaction}>
<TransactionListItem item={item} itemPriceUnit={item.walletPreferredBalanceUnit} walletID={item.walletID} />
<TransactionListItem key={item.hash} item={item} itemPriceUnit={item.walletPreferredBalanceUnit} walletID={item.walletID} />
</View>
),
[],
@ -357,9 +358,9 @@ const WalletsList: React.FC = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [scanImage, wallets.length]);
const sectionListKeyExtractor = (item: any, index: any) => {
const sectionListKeyExtractor = useCallback((item: any, index: any) => {
return `${item}${index}}`;
};
}, []);
const onScanButtonPressed = useCallback(() => {
navigation.navigate('ScanQRCode', {
@ -420,6 +421,15 @@ const WalletsList: React.FC = () => {
{ key: WalletsListSections.TRANSACTIONS, data: dataSource },
];
const getItemLayout = useCallback(
(data: any, index: number) => ({
length: 80, // Approximate height of each item
offset: 80 * index,
index,
}),
[],
);
return (
<View style={styles.root}>
<View style={[styles.walletsListWrapper, stylesHook.walletsListWrapper]}>
@ -438,6 +448,7 @@ const WalletsList: React.FC = () => {
windowSize={21}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={50}
getItemLayout={getItemLayout}
/>
{renderScanButton()}
</View>

View file

@ -26,14 +26,12 @@ import QRCodeComponent from '../../components/QRCodeComponent';
import { useTheme } from '../../components/themes';
import confirm from '../../helpers/confirm';
import prompt from '../../helpers/prompt';
import { disallowScreenshot } from 'react-native-screen-capture';
import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import ToolTipMenu from '../../components/TooltipMenu';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
import { useSettings } from '../../hooks/context/useSettings';
import { isDesktop } from '../../blue_modules/environment';
import { useKeyboard } from '../../hooks/useKeyboard';
import {
DoneAndDismissKeyboardInputAccessory,
@ -45,6 +43,7 @@ import MultipleStepsListItem, {
MultipleStepsListItemDashType,
} from '../../components/MultipleStepsListItem';
import { AddressInputScanButton } from '../../components/AddressInputScanButton';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
const staticCache = {};
@ -72,9 +71,11 @@ const WalletsAddMultisigStep2 = () => {
useFocusEffect(
useCallback(() => {
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
if (isPrivacyBlurEnabled) {
enableScreenProtect();
}
return () => {
if (!isDesktop) disallowScreenshot(false);
disableScreenProtect();
};
}, [isPrivacyBlurEnabled]),
);

View file

@ -7,11 +7,10 @@ import CopyTextToClipboard from '../../components/CopyTextToClipboard';
import QRCodeComponent from '../../components/QRCodeComponent';
import SafeArea from '../../components/SafeArea';
import { useTheme } from '../../components/themes';
import { disallowScreenshot } from 'react-native-screen-capture';
import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage';
import { useSettings } from '../../hooks/context/useSettings';
import { isDesktop } from '../../blue_modules/environment';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
const PleaseBackupLNDHub = () => {
const { wallets } = useStorage();
@ -44,10 +43,12 @@ const PleaseBackupLNDHub = () => {
});
useEffect(() => {
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
if (isPrivacyBlurEnabled) {
enableScreenProtect();
}
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
return () => {
if (!isDesktop) disallowScreenshot(false);
disableScreenProtect();
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
};
}, [handleBackButton, isPrivacyBlurEnabled]);

View file

@ -8,13 +8,12 @@ import CopyTextToClipboard from '../../components/CopyTextToClipboard';
import HandOffComponent from '../../components/HandOffComponent';
import QRCodeComponent from '../../components/QRCodeComponent';
import SafeArea from '../../components/SafeArea';
import { disallowScreenshot } from 'react-native-screen-capture';
import { enableScreenProtect, disableScreenProtect } from '../../helpers/screenProtect';
import loc from '../../loc';
import { styles, useDynamicStyles } from './xpub.styles';
import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
import { useSettings } from '../../hooks/context/useSettings';
import { isDesktop } from '../../blue_modules/environment';
type WalletXpubRouteProp = RouteProp<{ params: { walletID: string; xpub: string } }, 'params'>;
export type RootStackParamList = {
@ -39,7 +38,7 @@ const WalletXpub: React.FC = () => {
useFocusEffect(
useCallback(() => {
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
if (isPrivacyBlurEnabled) enableScreenProtect();
// Skip execution if walletID hasn't changed
if (lastWalletIdRef.current === walletID) {
return;
@ -58,7 +57,7 @@ const WalletXpub: React.FC = () => {
});
lastWalletIdRef.current = walletID;
return () => {
if (!isDesktop) disallowScreenshot(false);
disableScreenProtect();
task.cancel();
};
}, [isPrivacyBlurEnabled, walletID, wallet, xpub, navigation]),