REF: Move some Wallet Details options to menu

This commit is contained in:
Marcos Rodriguez Velez 2024-12-16 15:34:34 -04:00
parent 79f05ec12a
commit ba5e566b90
4 changed files with 193 additions and 193 deletions

View file

@ -269,6 +269,7 @@ const WalletsAdd: React.FC = () => {
return selectedWalletType === ButtonSelected.ONCHAIN ? [walletAction, entropyActions] : [walletAction];
}, [entropy, entropyButtonText, selectedIndex, selectedWalletType]);
const handleOnLightningButtonPressed = useCallback(() => {
confirmResetEntropy(ButtonSelected.OFFCHAIN);
}, [confirmResetEntropy]);

View file

@ -30,7 +30,6 @@ import { LightningCustodianWallet } from '../../class/wallets/lightning-custodia
import presentAlert from '../../components/Alert';
import Button from '../../components/Button';
import ListItem from '../../components/ListItem';
import SaveFileButton from '../../components/SaveFileButton';
import { SecondButton } from '../../components/SecondButton';
import { useTheme } from '../../components/themes';
import prompt from '../../helpers/prompt';
@ -44,6 +43,9 @@ import { useFocusEffect, useRoute, RouteProp } from '@react-navigation/native';
import { LightningTransaction, Transaction, TWallet } from '../../class/wallets/types';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
import { unsubscribe } from '../../blue_modules/notifications';
import HeaderMenuButton from '../../components/HeaderMenuButton';
import { Action } from '../../components/types';
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
type RouteProps = RouteProp<DetailViewStackParamList, 'WalletDetails'>;
const WalletDetails: React.FC = () => {
@ -85,67 +87,8 @@ const WalletDetails: React.FC = () => {
return null;
}
}, [wallet]);
const [isToolTipMenuVisible, setIsToolTipMenuVisible] = useState<boolean>(false);
const [isMasterFingerPrintVisible, setIsMasterFingerPrintVisible] = useState<boolean>(false);
const onMenuWillShow = () => setIsToolTipMenuVisible(true);
const onMenuWillHide = () => setIsToolTipMenuVisible(false);
useEffect(() => {
setIsContactsVisible(wallet.allowBIP47 && wallet.allowBIP47() && isBIP47Enabled);
}, [isBIP47Enabled, wallet]);
useFocusEffect(
useCallback(() => {
const task = InteractionManager.runAfterInteractions(() => {
if (isMasterFingerPrintVisible && wallet.allowMasterFingerprint && wallet.allowMasterFingerprint()) {
// @ts-expect-error: Need to fix later
if (wallet.getMasterFingerprintHex) {
// @ts-expect-error: Need to fix later
setMasterFingerprint(wallet.getMasterFingerprintHex());
}
} else {
setMasterFingerprint(undefined);
}
});
return () => task.cancel();
}, [isMasterFingerPrintVisible, wallet]),
);
const stylesHook = StyleSheet.create({
textLabel1: {
color: colors.feeText,
},
textLabel2: {
color: colors.feeText,
},
textValue: {
color: colors.outputValue,
},
input: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
delete: {
color: isToolTipMenuVisible ? colors.buttonDisabledTextColor : '#d0021b',
},
});
useEffect(() => {
setOptions({
headerBackTitleVisible: true,
});
}, [setOptions]);
useEffect(() => {
if (wallets.some(w => w.getID() === walletID)) {
setSelectedWalletID(walletID);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletID]);
const navigateToOverviewAndDeleteWallet = useCallback(async () => {
setIsLoading(true);
@ -192,6 +135,170 @@ const WalletDetails: React.FC = () => {
} catch (_) {}
}, [navigateToOverviewAndDeleteWallet, wallet]);
const handleDeleteButtonTapped = useCallback(() => {
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
Alert.alert(
loc.wallets.details_delete_wallet,
loc.wallets.details_are_you_sure,
[
{
text: loc.wallets.details_yes_delete,
onPress: async () => {
const isBiometricsEnabled = await isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await unlockWithBiometrics())) {
return;
}
}
if (wallet.getBalance && wallet.getBalance() > 0 && wallet.allowSend && wallet.allowSend()) {
presentWalletHasBalanceAlert();
} else {
navigateToOverviewAndDeleteWallet();
}
},
style: 'destructive',
},
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
],
{ cancelable: false },
);
}, [isBiometricUseCapableAndEnabled, navigateToOverviewAndDeleteWallet, presentWalletHasBalanceAlert, wallet]);
const exportHistoryContent = useCallback(() => {
const headers = [loc.transactions.date, loc.transactions.txid, `${loc.send.create_amount} (${BitcoinUnit.BTC})`, loc.send.create_memo];
if (wallet.chain === Chain.OFFCHAIN) {
headers.push(loc.lnd.payment);
}
const rows = [headers.join(',')];
const transactions = wallet.getTransactions();
transactions.forEach((transaction: Transaction & LightningTransaction) => {
const value = formatBalanceWithoutSuffix(transaction.value || 0, BitcoinUnit.BTC, true);
let hash: string = transaction.hash || '';
let memo = (transaction.hash && txMetadata[transaction.hash]?.memo?.trim()) || '';
let status = '';
if (wallet.chain === Chain.OFFCHAIN) {
hash = transaction.payment_hash ? transaction.payment_hash.toString() : '';
memo = transaction.memo || '';
status = transaction.ispaid ? loc._.success : loc.lnd.expired;
if (typeof hash !== 'string' && (hash as any)?.type === 'Buffer' && (hash as any)?.data) {
hash = Buffer.from((hash as any).data).toString('hex');
}
}
const date = transaction.received ? new Date(transaction.received).toString() : '';
const data = [date, hash, value, memo];
if (wallet.chain === Chain.OFFCHAIN) {
data.push(status);
}
rows.push(data.join(','));
});
return rows.join('\n');
}, [wallet, txMetadata]);
const fileName = useMemo(() => {
const label = wallet.getLabel().replace(' ', '-');
return `${label}-history.csv`;
}, [wallet]);
const toolTipOnPressMenuItem = useCallback(
async (id: string) => {
if (id === CommonToolTipActions.Delete.id) {
handleDeleteButtonTapped();
} else if (id === CommonToolTipActions.Share.id) {
await writeFileAndExport(fileName, exportHistoryContent(), true);
} else if (id === CommonToolTipActions.SaveFile.id) {
await writeFileAndExport(fileName, exportHistoryContent(), false);
}
},
[exportHistoryContent, fileName, handleDeleteButtonTapped],
);
const toolTipActions = useMemo(() => {
const actions: Action[] = [
{
id: loc.wallets.details_export_history,
text: loc.wallets.details_export_history,
displayInline: true,
hidden: walletTransactionsLength === 0,
subactions: [CommonToolTipActions.Share, CommonToolTipActions.SaveFile],
},
CommonToolTipActions.Delete,
];
return actions;
}, [walletTransactionsLength]);
const HeaderRight = useMemo(
() => <HeaderMenuButton disabled={isLoading} onPressMenuItem={toolTipOnPressMenuItem} actions={toolTipActions} />,
[toolTipOnPressMenuItem, toolTipActions, isLoading],
);
// Adding the ToolTipMenu to the header
useEffect(() => {
setOptions({
headerRight: () => HeaderRight,
});
}, [HeaderRight, setOptions]);
useEffect(() => {
setIsContactsVisible(wallet.allowBIP47 && wallet.allowBIP47() && isBIP47Enabled);
}, [isBIP47Enabled, wallet]);
useFocusEffect(
useCallback(() => {
const task = InteractionManager.runAfterInteractions(() => {
if (isMasterFingerPrintVisible && wallet.allowMasterFingerprint && wallet.allowMasterFingerprint()) {
// @ts-expect-error: Need to fix later
if (wallet.getMasterFingerprintHex) {
// @ts-expect-error: Need to fix later
setMasterFingerprint(wallet.getMasterFingerprintHex());
}
} else {
setMasterFingerprint(undefined);
}
});
return () => task.cancel();
}, [isMasterFingerPrintVisible, wallet]),
);
const stylesHook = StyleSheet.create({
textLabel1: {
color: colors.feeText,
},
textLabel2: {
color: colors.feeText,
},
textValue: {
color: colors.outputValue,
},
input: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
});
useEffect(() => {
setOptions({
headerBackTitleVisible: true,
});
}, [setOptions]);
useEffect(() => {
if (wallets.some(w => w.getID() === walletID)) {
setSelectedWalletID(walletID);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [walletID]);
const navigateToWalletExport = () => {
navigate('WalletExportRoot', {
screen: 'WalletExport',
@ -243,7 +350,7 @@ const WalletDetails: React.FC = () => {
if (backdoorPressed < 10) return setBackdoorPressed(backdoorPressed + 1);
setBackdoorPressed(0);
if (wallet.type !== HDSegwitBech32Wallet.type) return;
const fileName = 'wallet-externals.json';
const fileNameExternals = 'wallet-externals.json';
const contents = JSON.stringify(
{
_balances_by_external_index: wallet._balances_by_external_index,
@ -265,7 +372,7 @@ const WalletDetails: React.FC = () => {
2,
);
await writeFileAndExport(fileName, contents, false);
await writeFileAndExport(fileNameExternals, contents, false);
};
const purgeTransactions = async () => {
@ -314,78 +421,6 @@ const WalletDetails: React.FC = () => {
return subscribe;
}, [addListener, walletName, walletNameTextInputOnBlur]);
const exportHistoryContent = useCallback(() => {
const headers = [loc.transactions.date, loc.transactions.txid, `${loc.send.create_amount} (${BitcoinUnit.BTC})`, loc.send.create_memo];
if (wallet.chain === Chain.OFFCHAIN) {
headers.push(loc.lnd.payment);
}
const rows = [headers.join(',')];
const transactions = wallet.getTransactions();
transactions.forEach((transaction: Transaction & LightningTransaction) => {
const value = formatBalanceWithoutSuffix(transaction.value || 0, BitcoinUnit.BTC, true);
let hash: string = transaction.hash || '';
let memo = (transaction.hash && txMetadata[transaction.hash]?.memo?.trim()) || '';
let status = '';
if (wallet.chain === Chain.OFFCHAIN) {
hash = transaction.payment_hash ? transaction.payment_hash.toString() : '';
memo = transaction.memo || '';
status = transaction.ispaid ? loc._.success : loc.lnd.expired;
if (typeof hash !== 'string' && (hash as any)?.type === 'Buffer' && (hash as any)?.data) {
hash = Buffer.from((hash as any).data).toString('hex');
}
}
const date = transaction.received ? new Date(transaction.received).toString() : '';
const data = [date, hash, value, memo];
if (wallet.chain === Chain.OFFCHAIN) {
data.push(status);
}
rows.push(data.join(','));
});
return rows.join('\n');
}, [wallet, txMetadata]);
const handleDeleteButtonTapped = () => {
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
Alert.alert(
loc.wallets.details_delete_wallet,
loc.wallets.details_are_you_sure,
[
{
text: loc.wallets.details_yes_delete,
onPress: async () => {
const isBiometricsEnabled = await isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await unlockWithBiometrics())) {
return;
}
}
if (wallet.getBalance && wallet.getBalance() > 0 && wallet.allowSend && wallet.allowSend()) {
presentWalletHasBalanceAlert();
} else {
navigateToOverviewAndDeleteWallet();
}
},
style: 'destructive',
},
{ text: loc.wallets.details_no_cancel, onPress: () => {}, style: 'cancel' },
],
{ cancelable: false },
);
};
const fileName = useMemo(() => {
const label = wallet.getLabel().replace(' ', '-');
return `${label}-history.csv`;
}, [wallet]);
const onViewMasterFingerPrintPress = () => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setIsMasterFingerPrintVisible(true);
@ -490,7 +525,6 @@ const WalletDetails: React.FC = () => {
<View style={styles.hardware}>
<BlueText>{loc.wallets.details_display}</BlueText>
<Switch
disabled={isToolTipMenuVisible}
value={hideTransactionsInWalletsList}
onValueChange={async (value: boolean) => {
if (wallet.setHideTransactionsInWalletsList) {
@ -593,38 +627,17 @@ const WalletDetails: React.FC = () => {
</View>
</BlueCard>
{(wallet instanceof AbstractHDElectrumWallet || (wallet.type === WatchOnlyWallet.type && wallet.isHd && wallet.isHd())) && (
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToAddresses} title={loc.wallets.details_show_addresses} chevron />
<ListItem onPress={navigateToAddresses} title={loc.wallets.details_show_addresses} chevron />
)}
{isContactsVisible ? (
<ListItem disabled={isToolTipMenuVisible} onPress={navigateToContacts} title={loc.bip47.contacts} chevron />
) : null}
{isContactsVisible ? <ListItem onPress={navigateToContacts} title={loc.bip47.contacts} chevron /> : null}
<BlueCard style={styles.address}>
<View>
<BlueSpacing20 />
<Button
disabled={isToolTipMenuVisible}
onPress={navigateToWalletExport}
testID="WalletExport"
title={loc.wallets.details_export_backup}
/>
{walletTransactionsLength > 0 && (
<>
<BlueSpacing20 />
<SaveFileButton
onMenuWillHide={onMenuWillHide}
onMenuWillShow={onMenuWillShow}
fileName={fileName}
fileContent={exportHistoryContent()}
>
<SecondButton title={loc.wallets.details_export_history} />
</SaveFileButton>
</>
)}
<Button onPress={navigateToWalletExport} testID="WalletExport" title={loc.wallets.details_export_backup} />
{wallet.type === MultisigHDWallet.type && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToMultisigCoordinationSetup}
testID="MultisigCoordinationSetup"
title={loc.multisig.export_coordination_setup.replace(/^\w/, (c: string) => c.toUpperCase())}
@ -635,49 +648,24 @@ const WalletDetails: React.FC = () => {
{wallet.type === MultisigHDWallet.type && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToViewEditCosigners}
testID="ViewEditCosigners"
title={loc.multisig.view_edit_cosigners}
/>
<SecondButton onPress={navigateToViewEditCosigners} testID="ViewEditCosigners" title={loc.multisig.view_edit_cosigners} />
</>
)}
{wallet.allowXpub && wallet.allowXpub() && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToXPub}
testID="XPub"
title={loc.wallets.details_show_xpub}
/>
<SecondButton onPress={navigateToXPub} testID="XPub" title={loc.wallets.details_show_xpub} />
</>
)}
{wallet.allowSignVerifyMessage && wallet.allowSignVerifyMessage() && (
<>
<BlueSpacing20 />
<SecondButton
disabled={isToolTipMenuVisible}
onPress={navigateToSignVerify}
testID="SignVerify"
title={loc.addresses.sign_title}
/>
<SecondButton onPress={navigateToSignVerify} testID="SignVerify" title={loc.addresses.sign_title} />
</>
)}
<BlueSpacing20 />
<BlueSpacing20 />
<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>
</BlueCard>
</View>
@ -728,11 +716,6 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'space-between',
},
delete: {
fontSize: 15,
fontWeight: '500',
textAlign: 'center',
},
row: {
flexDirection: 'row',
},

View file

@ -61,7 +61,8 @@ export async function helperDeleteWallet(label, remainingBalanceSat = false) {
await element(by.text(label)).tap();
await element(by.id('WalletDetails')).tap();
await element(by.id('WalletDetailsScroll')).swipe('up', 'fast', 1);
await element(by.id('DeleteButton')).tap();
await element(by.id('HeaderMenuButton')).tap();
await element(by.text('Delete')).tap();
await sup('Yes, delete');
await element(by.text('Yes, delete')).tap();
if (remainingBalanceSat) {

View file

@ -40,6 +40,7 @@ const keys = {
CoSignTransaction: 'co_sign_transaction',
CopyToClipboard: 'copyToClipboard',
Share: 'share',
SaveFile: 'saveFile',
SignVerify: 'signVerify',
ExportPrivateKey: 'exportPrivateKey',
PasteFromClipboard: 'pasteFromClipboard',
@ -50,6 +51,7 @@ const keys = {
SortValue: 'sortValue',
SortLabel: 'sortLabel',
SortStatus: 'sortStatus',
Delete: 'delete',
} as const;
const icons = {
@ -94,6 +96,8 @@ const icons = {
ClearClipboard: { iconValue: 'clipboard' },
SortASC: { iconValue: 'arrow.down.to.line' },
SortDESC: { iconValue: 'arrow.up.to.line' },
SaveFile: { iconValue: 'square.and.arrow.down' },
Delete: { iconValue: 'trash' },
} as const;
export const CommonToolTipActions = {
@ -353,4 +357,15 @@ export const CommonToolTipActions = {
id: keys.SortStatus,
text: loc.cc.sort_status,
},
SaveFile: {
id: keys.SaveFile,
text: loc._.save,
icon: icons.SaveFile,
},
Delete: {
id: keys.Delete,
text: loc.wallets.details_delete,
icon: icons.Delete,
destructive: true,
},
} as const;