Merge branch 'master' into realmtmp

This commit is contained in:
Marcos Rodriguez Velez 2024-04-09 14:39:24 -04:00
commit 80a3318780
No known key found for this signature in database
GPG key ID: 6030B2F48CCE86D7
24 changed files with 239 additions and 146 deletions

2
App.js
View file

@ -27,7 +27,7 @@ import WatchConnectivity from './WatchConnectivity';
import DeviceQuickActions from './class/quick-actions';
import Notifications from './blue_modules/notifications';
import Biometric from './class/biometrics';
import WidgetCommunication from './blue_modules/WidgetCommunication';
import WidgetCommunication from './components/WidgetCommunication';
import ActionSheet from './screen/ActionSheet';
import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback';
import MenuElements from './components/MenuElements';

View file

@ -4,11 +4,10 @@ import * as bitcoin from 'bitcoinjs-lib';
import { Alert } from 'react-native';
import DefaultPreference from 'react-native-default-preference';
import Realm from 'realm';
import RNFS from 'react-native-fs';
import { LegacyWallet, SegwitBech32Wallet, SegwitP2SHWallet, TaprootWallet } from '../class';
import presentAlert from '../components/Alert';
import loc from '../loc';
import WidgetCommunication from './WidgetCommunication';
import { reloadAllTimelines } from '../components/WidgetCommunication';
const ElectrumClient = require('electrum-client');
const net = require('net');
@ -213,7 +212,7 @@ export async function connectMain(): Promise<void> {
await DefaultPreference.set(ELECTRUM_SSL_PORT, usingPeer.ssl ?? '');
}
WidgetCommunication.reloadAllTimelines();
reloadAllTimelines();
} catch (e) {
// Must be running on Android
console.log(e);
@ -340,7 +339,7 @@ const presentNetworkErrorAlert = async (usingPeer?: Peer) => {
await DefaultPreference.clear(ELECTRUM_HOST);
await DefaultPreference.clear(ELECTRUM_SSL_PORT);
await DefaultPreference.clear(ELECTRUM_TCP_PORT);
WidgetCommunication.reloadAllTimelines();
reloadAllTimelines();
} catch (e) {
// Must be running on Android
console.log(e);

View file

@ -1,79 +0,0 @@
import { useContext, useEffect } from 'react';
import { BlueStorageContext } from './storage-context';
import DefaultPreference from 'react-native-default-preference';
import RNWidgetCenter from 'react-native-widget-center';
import AsyncStorage from '@react-native-async-storage/async-storage';
function WidgetCommunication() {
WidgetCommunication.WidgetCommunicationAllWalletsSatoshiBalance = 'WidgetCommunicationAllWalletsSatoshiBalance';
WidgetCommunication.WidgetCommunicationAllWalletsLatestTransactionTime = 'WidgetCommunicationAllWalletsLatestTransactionTime';
WidgetCommunication.WidgetCommunicationDisplayBalanceAllowed = 'WidgetCommunicationDisplayBalanceAllowed';
WidgetCommunication.LatestTransactionIsUnconfirmed = 'WidgetCommunicationLatestTransactionIsUnconfirmed';
const { wallets, walletsInitialized, isStorageEncrypted } = useContext(BlueStorageContext);
WidgetCommunication.isBalanceDisplayAllowed = async () => {
try {
const displayBalance = JSON.parse(await AsyncStorage.getItem(WidgetCommunication.WidgetCommunicationDisplayBalanceAllowed));
if (displayBalance !== null) {
return displayBalance;
} else {
return true;
}
} catch (e) {
return true;
}
};
WidgetCommunication.setBalanceDisplayAllowed = async value => {
await AsyncStorage.setItem(WidgetCommunication.WidgetCommunicationDisplayBalanceAllowed, JSON.stringify(value));
setValues();
};
WidgetCommunication.reloadAllTimelines = () => {
RNWidgetCenter.reloadAllTimelines();
};
const allWalletsBalanceAndTransactionTime = async () => {
if ((await isStorageEncrypted()) || !(await WidgetCommunication.isBalanceDisplayAllowed())) {
return { allWalletsBalance: 0, latestTransactionTime: 0 };
} else {
let balance = 0;
let latestTransactionTime = 0;
for (const wallet of wallets) {
if (wallet.hideBalance) {
continue;
}
balance += wallet.getBalance();
if (wallet.getLatestTransactionTimeEpoch() > latestTransactionTime) {
if (wallet.getTransactions()[0].confirmations === 0) {
latestTransactionTime = WidgetCommunication.LatestTransactionIsUnconfirmed;
} else {
latestTransactionTime = wallet.getLatestTransactionTimeEpoch();
}
}
}
return { allWalletsBalance: balance, latestTransactionTime };
}
};
const setValues = async () => {
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
const { allWalletsBalance, latestTransactionTime } = await allWalletsBalanceAndTransactionTime();
await DefaultPreference.set(WidgetCommunication.WidgetCommunicationAllWalletsSatoshiBalance, JSON.stringify(allWalletsBalance));
await DefaultPreference.set(
WidgetCommunication.WidgetCommunicationAllWalletsLatestTransactionTime,
JSON.stringify(latestTransactionTime),
);
RNWidgetCenter.reloadAllTimelines();
};
useEffect(() => {
if (walletsInitialized) {
setValues();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallets, walletsInitialized]);
return null;
}
export default WidgetCommunication;

View file

@ -3,7 +3,7 @@ import DefaultPreference from 'react-native-default-preference';
import * as RNLocalize from 'react-native-localize';
import BigNumber from 'bignumber.js';
import { FiatUnit, FiatUnitType, getFiatRate } from '../models/fiatUnit';
import WidgetCommunication from './WidgetCommunication';
import { reloadAllTimelines } from '../components/WidgetCommunication';
const PREFERRED_CURRENCY_STORAGE_KEY = 'preferredCurrency';
const PREFERRED_CURRENCY_LOCALE_STORAGE_KEY = 'preferredCurrencyLocale';
@ -33,7 +33,7 @@ async function setPreferredCurrency(item: FiatUnitType): Promise<void> {
await DefaultPreference.set(PREFERRED_CURRENCY_STORAGE_KEY, item.endPointKey);
await DefaultPreference.set(PREFERRED_CURRENCY_LOCALE_STORAGE_KEY, item.locale.replace('-', '_'));
// @ts-ignore: Convert to TSX later
WidgetCommunication.reloadAllTimelines();
reloadAllTimelines();
}
async function getPreferredCurrency(): Promise<FiatUnitType> {

View file

@ -41,7 +41,7 @@ export class DynamicQRCode extends Component<DynamicQRCodeProps, DynamicQRCodeSt
fragments: string[] = [];
componentDidMount() {
const { value, capacity = 200, hideControls = true } = this.props;
const { value, capacity = 175, hideControls = true } = this.props;
try {
this.fragments = encodeUR(value, capacity);
this.setState(

View file

@ -12,9 +12,20 @@ interface SaveFileButtonProps {
style?: StyleProp<ViewStyle>;
afterOnPress?: () => void;
beforeOnPress?: () => Promise<void>; // Changed this line
onMenuWillHide?: () => void;
onMenuWillShow?: () => void;
}
const SaveFileButton: React.FC<SaveFileButtonProps> = ({ fileName, fileContent, children, style, beforeOnPress, afterOnPress }) => {
const SaveFileButton: React.FC<SaveFileButtonProps> = ({
fileName,
fileContent,
children,
style,
beforeOnPress,
afterOnPress,
onMenuWillHide,
onMenuWillShow,
}) => {
const actions = [
{ id: 'save', text: loc._.save, icon: actionIcons.Save },
{ id: 'share', text: loc.receive.details_share, icon: actionIcons.Share },
@ -39,7 +50,15 @@ const SaveFileButton: React.FC<SaveFileButtonProps> = ({ fileName, fileContent,
return (
// @ts-ignore: Tooltip must be refactored to use TSX}
<ToolTipMenu isButton isMenuPrimaryAction actions={actions} onPressMenuItem={handlePressMenuItem} buttonStyle={style}>
<ToolTipMenu
onMenuWillHide={onMenuWillHide}
onMenuWillShow={onMenuWillShow}
isButton
isMenuPrimaryAction
actions={actions}
onPressMenuItem={handlePressMenuItem}
buttonStyle={style}
>
{children}
</ToolTipMenu>
);

View file

@ -34,7 +34,13 @@ export const SecondButton = forwardRef<TouchableOpacity, SecondButtonProps>((pro
);
return props.onPress ? (
<TouchableOpacity accessibilityRole="button" style={[styles.button, { backgroundColor }]} {...props} ref={ref}>
<TouchableOpacity
disabled={props.disabled}
accessibilityRole="button"
style={[styles.button, { backgroundColor }]}
{...props}
ref={ref}
>
{buttonView}
</TouchableOpacity>
) : (

View file

@ -42,12 +42,16 @@ const BaseToolTipMenu = (props, ref) => {
const renderPreview = props.renderPreview ?? undefined;
const disabled = props.disabled ?? false;
const onPress = props.onPress ?? undefined;
const onMenuWillShow = props.onMenuWillShow ?? undefined;
const onMenuWillHide = props.onMenuWillHide ?? undefined;
const buttonStyle = props.buttonStyle;
return isButton ? (
<TouchableOpacity onPress={onPress} disabled={disabled} accessibilityRole="button" style={buttonStyle}>
<ContextMenuButton
ref={ref}
onMenuWillShow={onMenuWillShow}
onMenuWillHide={onMenuWillHide}
useActionSheetFallback={false}
onPressMenuItem={({ nativeEvent }) => {
props.onPressMenuItem(nativeEvent.actionKey);

View file

@ -1,6 +1,6 @@
import { forwardRef } from 'react';
const BaseToolTipMenu = props => {
const BaseToolTipMenu = (props, _ref) => {
return props.children;
};

View file

@ -227,10 +227,10 @@ export const WalletCarouselItem = ({ item, _, onPress, handleLongPress, isSelect
<Text
numberOfLines={1}
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
adjustsFontSizeToFit
ellipsizeMode='middle'
style={[iStyles.balance, { color: colors.inverseForegroundColor }]}
>
{balance}
{`${balance} `}
</Text>
)}
<Text style={iStyles.br} />

View file

@ -0,0 +1,80 @@
import React, { useContext, useEffect } from 'react';
import DefaultPreference from 'react-native-default-preference';
// @ts-ignore: fix later
import RNWidgetCenter from 'react-native-widget-center';
import { BlueStorageContext } from '../blue_modules/storage-context';
import { TWallet } from '../class/wallets/types';
enum WidgetCommunicationKeys {
AllWalletsSatoshiBalance = 'WidgetCommunicationAllWalletsSatoshiBalance',
AllWalletsLatestTransactionTime = 'WidgetCommunicationAllWalletsLatestTransactionTime',
DisplayBalanceAllowed = 'WidgetCommunicationDisplayBalanceAllowed',
LatestTransactionIsUnconfirmed = 'WidgetCommunicationLatestTransactionIsUnconfirmed',
}
export const reloadAllTimelines = (): void => {
RNWidgetCenter.reloadAllTimelines();
};
export const isBalanceDisplayAllowed = async (): Promise<boolean> => {
try {
const displayBalance = await DefaultPreference.get(WidgetCommunicationKeys.DisplayBalanceAllowed);
return displayBalance === '1';
} catch {
return false;
}
};
export const setBalanceDisplayAllowed = async (value: boolean): Promise<void> => {
if (value) {
await DefaultPreference.set(WidgetCommunicationKeys.DisplayBalanceAllowed, '1');
} else {
await DefaultPreference.clear(WidgetCommunicationKeys.DisplayBalanceAllowed);
}
reloadAllTimelines();
};
const WidgetCommunication: React.FC = () => {
const { wallets, walletsInitialized } = useContext(BlueStorageContext);
useEffect(() => {
const allWalletsBalanceAndTransactionTime = async (): Promise<{
allWalletsBalance: number;
latestTransactionTime: number | string;
}> => {
if (!walletsInitialized || !(await isBalanceDisplayAllowed())) {
return { allWalletsBalance: 0, latestTransactionTime: 0 };
} else {
let balance = 0;
let latestTransactionTime: number | string = 0;
wallets.forEach((wallet: TWallet) => {
if (wallet.hideBalance) return;
balance += wallet.getBalance();
const walletLatestTime = wallet.getLatestTransactionTimeEpoch();
if (typeof latestTransactionTime === 'number' && walletLatestTime > latestTransactionTime) {
latestTransactionTime =
wallet.getTransactions()[0]?.confirmations === 0 ? WidgetCommunicationKeys.LatestTransactionIsUnconfirmed : walletLatestTime;
}
});
return { allWalletsBalance: balance, latestTransactionTime };
}
};
const setValues = async (): Promise<void> => {
await DefaultPreference.setName('group.io.bluewallet.bluewallet');
const { allWalletsBalance, latestTransactionTime } = await allWalletsBalanceAndTransactionTime();
await DefaultPreference.set(WidgetCommunicationKeys.AllWalletsSatoshiBalance, String(allWalletsBalance));
await DefaultPreference.set(WidgetCommunicationKeys.AllWalletsLatestTransactionTime, String(latestTransactionTime));
reloadAllTimelines();
};
if (walletsInitialized) {
setValues();
}
}, [wallets, walletsInitialized]);
return null;
};
export default WidgetCommunication;

View file

@ -0,0 +1,15 @@
import React from 'react';
export const isBalanceDisplayAllowed = async (): Promise<boolean> => {
return true;
};
export const setBalanceDisplayAllowed = async (value: boolean): Promise<void> => {};
export const reloadAllTimelines = (): void => {};
const WidgetCommunication: React.FC = () => {
return null; // This component does not render anything.
};
export default WidgetCommunication;

View file

@ -8,9 +8,10 @@ export const presentWalletExportReminder = (): Promise<void> => {
loc.pleasebackup.ask,
[
{ text: loc.pleasebackup.ask_yes, onPress: () => resolve(), style: 'default' },
{ text: loc.pleasebackup.ask_no, onPress: () => reject(new Error('User has denied saving the wallet backup.')), style: 'cancel' },
{ text: loc.pleasebackup.ask_no, onPress: () => reject(new Error('User has denied saving the wallet backup.')) },
{ text: loc._.cancel, style: 'cancel' },
],
{ cancelable: false },
{ cancelable: true },
);
});
};

View file

@ -74,11 +74,13 @@ export const useExtendedNavigation = (): NavigationProp<ParamListBase> => {
wallet.setUserHasSavedExport(true);
await saveToDisk(); // Assuming saveToDisk() returns a Promise.
proceedWithNavigation();
} catch {
originalNavigation.navigate('WalletExportRoot', {
screen: 'WalletExport',
params: { walletID },
});
} catch (error) {
if (error) {
originalNavigation.navigate('WalletExportRoot', {
screen: 'WalletExport',
params: { walletID },
});
}
}
return; // Prevent proceeding with the original navigation if the reminder is shown

View file

@ -30,22 +30,15 @@ NSUserDefaults *group = [[NSUserDefaults alloc] initWithSuiteName:@"group.io.blu
config.appType = @"macOS";
// Start Bugsnag with the configuration
[Bugsnag startWithConfiguration:config];
[self copyDeviceUID];
#else
[Bugsnag start];
[self copyDeviceUID];
#endif
}
[self copyDeviceUID];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"deviceUID"
options:NSKeyValueObservingOptionNew
context:NULL];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"deviceUIDCopy"
options:NSKeyValueObservingOptionNew
context:NULL];
[self addSplashScreenView];
self.moduleName = @"BlueWallet";
@ -95,6 +88,14 @@ NSUserDefaults *group = [[NSUserDefaults alloc] initWithSuiteName:@"group.io.blu
}
- (void)copyDeviceUID {
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"deviceUID"
options:NSKeyValueObservingOptionNew
context:NULL];
[[NSUserDefaults standardUserDefaults] addObserver:self
forKeyPath:@"deviceUIDCopy"
options:NSKeyValueObservingOptionNew
context:NULL];
NSString *deviceUID = [[NSUserDefaults standardUserDefaults] stringForKey:@"deviceUID"];
if (deviceUID && deviceUID.length > 0) {
[NSUserDefaults.standardUserDefaults setValue:deviceUID forKey:@"deviceUIDCopy"];

View file

@ -20,9 +20,9 @@ PODS:
- hermes-engine/Pre-built (= 0.72.12)
- hermes-engine/Pre-built (0.72.12)
- libevent (2.1.12)
- lottie-ios (4.4.2)
- lottie-react-native (6.7.0):
- lottie-ios (~> 4.4.1)
- lottie-ios (4.4.1)
- lottie-react-native (6.7.2):
- lottie-ios (= 4.4.1)
- React-Core
- PasscodeAuth (1.0.0):
- React
@ -792,8 +792,8 @@ SPEC CHECKSUMS:
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
hermes-engine: e89344b9e9e54351c3c5cac075e0275148fb37ba
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
lottie-ios: 4445b0bdb583c7a5325529f62246d311ee85fcd0
lottie-react-native: e3205322282d72e23efb3bff3287d0bd16fb1b01
lottie-ios: e047b1d2e6239b787cc5e9755b988869cf190494
lottie-react-native: 17547b2f3c7034e2ae8672833fdb63262164d18a
PasscodeAuth: 3e88093ff46c31a952d8b36c488240de980517be
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCTRequired: b6cea797b684c6d8d82ba0107cef58cbb679afdb

View file

@ -104,7 +104,7 @@ struct WalletInformationWidget: Widget {
struct WalletInformationWidget_Previews: PreviewProvider {
static var previews: some View {
WalletInformationWidgetEntryView(entry: WalletInformationWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10,000", rate: Double(0)), allWalletsBalance: WalletData(balance: 10000, latestTransactionTime: LatestTransaction(isUnconfirmed: false, epochValue: 1568804029000))))
WalletInformationWidgetEntryView(entry: WalletInformationWidgetEntry(date: Date(), marketData: MarketData(nextBlock: "26", sats: "9 134", price: "$10,000", rate: Double(0)), allWalletsBalance: WalletData(balance: 0, latestTransactionTime: LatestTransaction(isUnconfirmed: nil, epochValue: nil))))
.previewContext(WidgetPreviewContext(family: .systemSmall))
}
}

14
package-lock.json generated
View file

@ -49,7 +49,7 @@
"events": "3.3.0",
"frisbee": "3.1.0",
"junderw-crc32c": "1.2.0",
"lottie-react-native": "6.7.0",
"lottie-react-native": "6.7.2",
"metro-react-native-babel-preset": "0.77.0",
"path-browserify": "1.0.1",
"payjoin-client": "1.0.1",
@ -16909,9 +16909,9 @@
}
},
"node_modules/lottie-react-native": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.7.0.tgz",
"integrity": "sha512-doiF/36LaKkzo0XkgUIK8egxALNY6jGjCI4szpRuwop15LTW3DFtIA2L3pusNdaH7oM797aSH5UylIJw2k+Hgw==",
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.7.2.tgz",
"integrity": "sha512-MZVx6N1EeO/EaSx8T44mJ0aHc5Mqee+xIfWwszni0oz8U2wlHdaWGjES44dHxaxgAp/0dRaFt3PkpZ6egTzcBg==",
"peerDependencies": {
"@dotlottie/react-player": "^1.6.1",
"@lottiefiles/react-lottie-player": "^3.5.3",
@ -35090,9 +35090,9 @@
}
},
"lottie-react-native": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.7.0.tgz",
"integrity": "sha512-doiF/36LaKkzo0XkgUIK8egxALNY6jGjCI4szpRuwop15LTW3DFtIA2L3pusNdaH7oM797aSH5UylIJw2k+Hgw=="
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/lottie-react-native/-/lottie-react-native-6.7.2.tgz",
"integrity": "sha512-MZVx6N1EeO/EaSx8T44mJ0aHc5Mqee+xIfWwszni0oz8U2wlHdaWGjES44dHxaxgAp/0dRaFt3PkpZ6egTzcBg=="
},
"lru-cache": {
"version": "5.1.1",

View file

@ -135,7 +135,7 @@
"events": "3.3.0",
"frisbee": "3.1.0",
"junderw-crc32c": "1.2.0",
"lottie-react-native": "6.7.0",
"lottie-react-native": "6.7.2",
"metro-react-native-babel-preset": "0.77.0",
"path-browserify": "1.0.1",
"payjoin-client": "1.0.1",

View file

@ -8,7 +8,7 @@ import loc from '../../loc';
import DeviceQuickActions from '../../class/quick-actions';
import BlueClipboard from '../../blue_modules/clipboard';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import WidgetCommunication from '../../blue_modules/WidgetCommunication';
import { isBalanceDisplayAllowed, setBalanceDisplayAllowed } from '../../components/WidgetCommunication';
import { useTheme } from '../../components/themes';
import ListItem from '../../components/ListItem';
import A from '../../blue_modules/analytics';
@ -38,7 +38,7 @@ const SettingsPrivacy = () => {
setIsReadClipboardAllowed(await BlueClipboard().isReadClipboardAllowed());
setStorageIsEncrypted(await isStorageEncrypted());
setIsQuickActionsEnabled(await DeviceQuickActions.getEnabled());
setIsDisplayWidgetBalanceAllowed(await WidgetCommunication.isBalanceDisplayAllowed());
setIsDisplayWidgetBalanceAllowed(await isBalanceDisplayAllowed());
} catch (e) {
console.log(e);
}
@ -84,7 +84,7 @@ const SettingsPrivacy = () => {
const onWidgetsTotalBalanceValueChange = async value => {
setIsLoading(sections.WIDGETS);
try {
await WidgetCommunication.setBalanceDisplayAllowed(value);
await setBalanceDisplayAllowed(value);
setIsDisplayWidgetBalanceAllowed(value);
} catch (e) {
console.log(e);

View file

@ -29,7 +29,7 @@ import {
BlueDismissKeyboardInputAccessory,
} from '../../BlueComponents';
import { BlueCurrentTheme } from '../../components/themes';
import WidgetCommunication from '../../blue_modules/WidgetCommunication';
import { reloadAllTimelines } from '../../components/WidgetCommunication';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import presentAlert from '../../components/Alert';
import { requestCameraAuthorization } from '../../helpers/scan-qr';
@ -170,7 +170,7 @@ export default class ElectrumSettings extends Component {
await DefaultPreference.clear(BlueElectrum.ELECTRUM_HOST);
await DefaultPreference.clear(BlueElectrum.ELECTRUM_SSL_PORT);
await DefaultPreference.clear(BlueElectrum.ELECTRUM_TCP_PORT);
WidgetCommunication.reloadAllTimelines();
reloadAllTimelines();
} catch (e) {
// Must be running on Android
console.log(e);
@ -199,7 +199,7 @@ export default class ElectrumSettings extends Component {
await DefaultPreference.set(BlueElectrum.ELECTRUM_HOST, host);
await DefaultPreference.set(BlueElectrum.ELECTRUM_TCP_PORT, port);
await DefaultPreference.set(BlueElectrum.ELECTRUM_SSL_PORT, sslPort);
WidgetCommunication.reloadAllTimelines();
reloadAllTimelines();
} catch (e) {
// Must be running on Android
console.log(e);

View file

@ -97,7 +97,6 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
},
delete: {
color: '#d0021b',
fontSize: 15,
fontWeight: '500',
textAlign: 'center',
@ -147,6 +146,10 @@ const WalletDetails = () => {
}
}, [wallet]);
const [lightningWalletInfo, setLightningWalletInfo] = useState({});
const [isToolTipMenuVisible, setIsToolTipMenuVisible] = useState(false);
const onMenuWillShow = () => setIsToolTipMenuVisible(true);
const onMenuWillHide = () => setIsToolTipMenuVisible(false);
useEffect(() => {
if (isAdvancedModeEnabledRender && wallet.allowMasterFingerprint()) {
@ -177,6 +180,9 @@ const WalletDetails = () => {
saveText: {
color: colors.buttonTextColor,
},
delete: {
color: isToolTipMenuVisible ? colors.buttonDisabledTextColor : '#d0021b',
},
});
useEffect(() => {
if (wallet.type === LightningLdkWallet.type) {
@ -216,7 +222,7 @@ const WalletDetails = () => {
<TouchableOpacity
accessibilityRole="button"
testID="Save"
disabled={isLoading}
disabled={isLoading || isToolTipMenuVisible}
style={[styles.save, stylesHook.save]}
onPress={save}
>
@ -225,7 +231,7 @@ const WalletDetails = () => {
),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoading, colors, walletName, useWithHardwareWallet, hideTransactionsInWalletsList, isBIP47Enabled]);
}, [isLoading, colors, walletName, useWithHardwareWallet, hideTransactionsInWalletsList, isBIP47Enabled, isToolTipMenuVisible]);
useEffect(() => {
if (wallets.some(w => w.getID() === walletID)) {
@ -594,7 +600,11 @@ const WalletDetails = () => {
</Text>
<View style={styles.hardware}>
<BlueText onPress={() => setBackdoorBip47Pressed(prevState => prevState + 1)}>{loc.wallets.details_display}</BlueText>
<Switch value={hideTransactionsInWalletsList} onValueChange={setHideTransactionsInWalletsList} />
<Switch
disabled={isToolTipMenuVisible}
value={hideTransactionsInWalletsList}
onValueChange={setHideTransactionsInWalletsList}
/>
</View>
</>
<>
@ -647,17 +657,27 @@ const WalletDetails = () => {
</View>
</BlueCard>
{(wallet instanceof AbstractHDElectrumWallet || (wallet.type === WatchOnlyWallet.type && wallet.isHd())) && (
<ListItem onPress={navigateToAddresses} title={loc.wallets.details_show_addresses} chevron />
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToAddresses} title={loc.wallets.details_show_addresses} chevron />
)}
{wallet.allowBIP47() && isBIP47Enabled && <ListItem onPress={navigateToPaymentCodes} title="Show payment codes" chevron />}
<BlueCard style={styles.address}>
<View>
<BlueSpacing20 />
<Button onPress={navigateToWalletExport} testID="WalletExport" title={loc.wallets.details_export_backup} />
<Button
disabled={isToolTipMenuVisible}
onPress={navigateToWalletExport}
testID="WalletExport"
title={loc.wallets.details_export_backup}
/>
{walletTransactionsLength > 0 && (
<>
<BlueSpacing20 />
<SaveFileButton fileName={fileName} fileContent={exportHistoryContent()}>
<SaveFileButton
onMenuWillHide={onMenuWillHide}
onMenuWillShow={onMenuWillShow}
fileName={fileName}
fileContent={exportHistoryContent()}
>
<SecondButton title={loc.wallets.details_export_history} />
</SaveFileButton>
</>
@ -666,6 +686,7 @@ const WalletDetails = () => {
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToMultisigCoordinationSetup}
testID="MultisigCoordinationSetup"
title={loc.multisig.export_coordination_setup.replace(/^\w/, c => c.toUpperCase())}
@ -677,6 +698,7 @@ const WalletDetails = () => {
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToViewEditCosigners}
testID="ViewEditCosigners"
title={loc.multisig.view_edit_cosigners}
@ -687,25 +709,48 @@ const WalletDetails = () => {
{wallet.allowXpub() && (
<>
<BlueSpacing20 />
<SecondButton onPress={navigateToXPub} testID="XPub" title={loc.wallets.details_show_xpub} />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToXPub}
testID="XPub"
title={loc.wallets.details_show_xpub}
/>
</>
)}
{wallet.allowSignVerifyMessage() && (
<>
<BlueSpacing20 />
<SecondButton onPress={navigateToSignVerify} testID="SignVerify" title={loc.addresses.sign_title} />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToSignVerify}
testID="SignVerify"
title={loc.addresses.sign_title}
/>
</>
)}
{wallet.type === LightningLdkWallet.type && (
<>
<BlueSpacing20 />
<SecondButton onPress={navigateToLdkViewLogs} testID="LdkLogs" title={loc.lnd.view_logs} />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToLdkViewLogs}
testID="LdkLogs"
title={loc.lnd.view_logs}
/>
</>
)}
<BlueSpacing20 />
<BlueSpacing20 />
<TouchableOpacity accessibilityRole="button" onPress={handleDeleteButtonTapped} testID="DeleteButton">
<Text textBreakStrategy="simple" style={styles.delete}>{`${loc.wallets.details_delete}${' '}`}</Text>
<TouchableOpacity
disabled={isToolTipMenuVisible}
accessibilityRole="button"
onPress={handleDeleteButtonTapped}
testID="DeleteButton"
>
<Text
textBreakStrategy="simple"
style={[styles.delete, stylesHook.delete]}
>{`${loc.wallets.details_delete}${' '}`}</Text>
</TouchableOpacity>
<BlueSpacing20 />
<BlueSpacing20 />

View file

@ -1,4 +1,4 @@
import React, { useEffect, useRef, useContext, useState } from 'react';
import React, { useEffect, useRef, useContext, useState, useLayoutEffect } from 'react';
import { StyleSheet, useColorScheme, Platform } from 'react-native';
import DraggableFlatList, { ScaleDecorator } from 'react-native-draggable-flatlist';
import navigationStyle from '../../components/navigationStyle';
@ -54,7 +54,7 @@ const ReorderWallets = () => {
setWalletData(filteredWallets);
}, [wallets, searchQuery]);
useEffect(() => {
useLayoutEffect(() => {
// Set navigation options dynamically
setOptions({
headerSearchBarOptions: {

View file

@ -187,7 +187,7 @@ jest.mock('react-native-share', () => {
};
});
jest.mock('../blue_modules/WidgetCommunication', () => {
jest.mock('../components/WidgetCommunication', () => {
return {
reloadAllTimelines: jest.fn(),
};