mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 18:00:17 +01:00
Merge pull request #6872 from BlueWallet/menu
REF: Use tooltip menu for SendDetails on Android
This commit is contained in:
commit
812319154b
@ -36,7 +36,7 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
|
||||
actionKey: action.id.toString(),
|
||||
actionTitle: action.text,
|
||||
icon: action.icon?.iconValue ? ({ iconType: 'SYSTEM', iconValue: action.icon.iconValue } as IconConfig) : undefined,
|
||||
state: action.menuStateOn ? ('on' as MenuState) : ('off' as MenuState),
|
||||
state: action.menuState ?? undefined,
|
||||
attributes: action.disabled ? ['disabled'] : [],
|
||||
};
|
||||
}, []);
|
||||
@ -46,8 +46,7 @@ const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
|
||||
return {
|
||||
id: action.id.toString(),
|
||||
title: action.text,
|
||||
image: action.menuStateOn && Platform.OS === 'android' ? 'checkbox_on_background' : action.icon?.iconValue || undefined,
|
||||
state: action.menuStateOn ? ('on' as MenuState) : undefined,
|
||||
state: action.menuState === undefined ? undefined : ((action.menuState ? 'on' : 'off') as MenuState),
|
||||
attributes: { disabled: action.disabled },
|
||||
};
|
||||
}, []);
|
||||
|
@ -7,7 +7,7 @@ export interface Action {
|
||||
iconValue: string;
|
||||
};
|
||||
menuTitle?: string;
|
||||
menuStateOn?: boolean;
|
||||
menuState?: 'mixed' | boolean | undefined;
|
||||
disabled?: boolean;
|
||||
displayInline?: boolean;
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
"close": "Close",
|
||||
"change_input_currency": "Change input currency",
|
||||
"refresh": "Refresh",
|
||||
"more": "More",
|
||||
"pick_image": "Choose image from library",
|
||||
"pick_file": "Choose a file",
|
||||
"enter_amount": "Enter amount",
|
||||
|
76
package-lock.json
generated
76
package-lock.json
generated
@ -20,7 +20,7 @@
|
||||
"@react-native-async-storage/async-storage": "1.24.0",
|
||||
"@react-native-clipboard/clipboard": "1.14.1",
|
||||
"@react-native-community/push-notification-ios": "1.11.0",
|
||||
"@react-native-menu/menu": "1.1.2",
|
||||
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#958fac3d40811f38b53042ada9168175e321b99f",
|
||||
"@react-native/metro-config": "0.74.87",
|
||||
"@react-navigation/drawer": "6.7.2",
|
||||
"@react-navigation/native": "6.1.18",
|
||||
@ -3550,6 +3550,8 @@
|
||||
},
|
||||
"node_modules/@react-native-menu/menu": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "git+ssh://git@github.com/BlueWallet/menu.git#958fac3d40811f38b53042ada9168175e321b99f",
|
||||
"integrity": "sha512-0j8qsd04s36qSLQIFZ0mfpgzikZU0A0lriq4OFaUvCFfDTDgc5iVKnVr0MzxkFa66qX4NuCbhiQ82Fsdar5RHA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
@ -3784,8 +3786,6 @@
|
||||
},
|
||||
"node_modules/@react-native/eslint-config/node_modules/eslint-config-prettier": {
|
||||
"version": "8.10.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
|
||||
"integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@ -3928,8 +3928,6 @@
|
||||
},
|
||||
"node_modules/@react-native/eslint-config/node_modules/eslint-plugin-prettier": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
|
||||
"integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3948,6 +3946,61 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/eslint-config/node_modules/eslint-plugin-react": {
|
||||
"version": "7.35.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.8",
|
||||
"array.prototype.findlast": "^1.2.5",
|
||||
"array.prototype.flatmap": "^1.3.2",
|
||||
"array.prototype.tosorted": "^1.1.4",
|
||||
"doctrine": "^2.1.0",
|
||||
"es-iterator-helpers": "^1.0.19",
|
||||
"estraverse": "^5.3.0",
|
||||
"hasown": "^2.0.2",
|
||||
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
|
||||
"minimatch": "^3.1.2",
|
||||
"object.entries": "^1.1.8",
|
||||
"object.fromentries": "^2.0.8",
|
||||
"object.values": "^1.2.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"resolve": "^2.0.0-next.5",
|
||||
"semver": "^6.3.1",
|
||||
"string.prototype.matchall": "^4.0.11",
|
||||
"string.prototype.repeat": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/eslint-config/node_modules/eslint-plugin-react/node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/eslint-config/node_modules/resolve": {
|
||||
"version": "2.0.0-next.5",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/eslint-plugin": {
|
||||
"version": "0.74.87",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/eslint-plugin/-/eslint-plugin-0.74.87.tgz",
|
||||
@ -14874,6 +14927,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.repeat": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"node_modules/string.prototype.trim": {
|
||||
"version": "1.2.9",
|
||||
"dev": true,
|
||||
@ -15342,6 +15404,8 @@
|
||||
},
|
||||
"node_modules/tsutils": {
|
||||
"version": "3.21.0",
|
||||
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
|
||||
"integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -15356,6 +15420,8 @@
|
||||
},
|
||||
"node_modules/tsutils/node_modules/tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
|
@ -114,7 +114,7 @@
|
||||
"@react-native-async-storage/async-storage": "1.24.0",
|
||||
"@react-native-clipboard/clipboard": "1.14.1",
|
||||
"@react-native-community/push-notification-ios": "1.11.0",
|
||||
"@react-native-menu/menu": "1.1.2",
|
||||
"@react-native-menu/menu": "https://github.com/BlueWallet/menu.git#958fac3d40811f38b53042ada9168175e321b99f",
|
||||
"@react-navigation/drawer": "6.7.2",
|
||||
"@react-navigation/native": "6.1.18",
|
||||
"@react-navigation/native-stack": "6.11.0",
|
||||
|
@ -19,7 +19,6 @@ import {
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import DocumentPicker from 'react-native-document-picker';
|
||||
@ -36,11 +35,10 @@ import { AbstractHDElectrumWallet } from '../../class/wallets/abstract-hd-electr
|
||||
import AddressInput from '../../components/AddressInput';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import AmountInput from '../../components/AmountInput';
|
||||
import BottomModal, { BottomModalHandle } from '../../components/BottomModal';
|
||||
import { BottomModalHandle } from '../../components/BottomModal';
|
||||
import Button from '../../components/Button';
|
||||
import CoinsSelected from '../../components/CoinsSelected';
|
||||
import InputAccessoryAllFunds from '../../components/InputAccessoryAllFunds';
|
||||
import ListItem from '../../components/ListItem';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import ToolTipMenu from '../../components/TooltipMenu';
|
||||
import { requestCameraAuthorization, scanQrHelper } from '../../helpers/scan-qr';
|
||||
@ -92,10 +90,9 @@ const SendDetails = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [wallet, setWallet] = useState<TWallet | null>(null);
|
||||
const feeModalRef = useRef<BottomModalHandle>(null);
|
||||
const optionsModalRef = useRef<BottomModalHandle>(null);
|
||||
const [walletSelectionOrCoinsSelectedHidden, setWalletSelectionOrCoinsSelectedHidden] = useState(false);
|
||||
const [isAmountToolbarVisibleForAndroid, setIsAmountToolbarVisibleForAndroid] = useState(false);
|
||||
const [isTransactionReplaceable, setIsTransactionReplaceable] = useState<boolean>(false);
|
||||
const [isTransactionReplaceable, setIsTransactionReplaceable] = useState<boolean | undefined>(false);
|
||||
const [addresses, setAddresses] = useState<IPaymentDestinations[]>([]);
|
||||
const [units, setUnits] = useState<BitcoinUnit[]>([]);
|
||||
const [transactionMemo, setTransactionMemo] = useState<string>('');
|
||||
@ -288,8 +285,7 @@ const SendDetails = () => {
|
||||
// reset other values
|
||||
setUtxo(null);
|
||||
setChangeAddress(null);
|
||||
setIsTransactionReplaceable(wallet.type === HDSegwitBech32Wallet.type && !routeParams.noRbf);
|
||||
|
||||
setIsTransactionReplaceable(wallet.type === HDSegwitBech32Wallet.type && !routeParams.noRbf ? true : undefined);
|
||||
// update wallet UTXO
|
||||
wallet
|
||||
.fetchUtxo()
|
||||
@ -390,7 +386,6 @@ const SendDetails = () => {
|
||||
setDumb(v => !v);
|
||||
return () => {
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
};
|
||||
}, []),
|
||||
);
|
||||
@ -614,7 +609,7 @@ const SendDetails = () => {
|
||||
if (tx && routeParams.launchedBy && psbt) {
|
||||
console.warn('navigating back to ', routeParams.launchedBy);
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
// @ts-ignore idk how to fix FIXME?
|
||||
|
||||
navigation.navigate(routeParams.launchedBy, { psbt });
|
||||
@ -622,7 +617,7 @@ const SendDetails = () => {
|
||||
|
||||
if (wallet?.type === WatchOnlyWallet.type) {
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
// watch-only wallets with enabled HW wallet support have different flow. we have to show PSBT to user as QR code
|
||||
// so he can scan it and sign it. then we have to scan it back from user (via camera and QR code), and ask
|
||||
// user whether he wants to broadcast it
|
||||
@ -638,7 +633,7 @@ const SendDetails = () => {
|
||||
|
||||
if (wallet?.type === MultisigHDWallet.type) {
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
navigation.navigate('PsbtMultisig', {
|
||||
memo: transactionMemo,
|
||||
psbtBase64: psbt.toBase64(),
|
||||
@ -664,7 +659,6 @@ const SendDetails = () => {
|
||||
recipients = outputs;
|
||||
}
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
navigation.navigate('Confirm', {
|
||||
fee: new BigNumber(fee).dividedBy(100000000).toNumber(),
|
||||
@ -700,7 +694,7 @@ const SendDetails = () => {
|
||||
|
||||
requestCameraAuthorization().then(() => {
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
navigation.navigate('ScanQRCodeRoot', {
|
||||
screen: 'ScanQRCode',
|
||||
params: {
|
||||
@ -722,7 +716,7 @@ const SendDetails = () => {
|
||||
// we dont support it in this flow
|
||||
} else {
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
// psbt base64?
|
||||
|
||||
// we construct PSBT object and pass to next screen
|
||||
@ -747,7 +741,6 @@ const SendDetails = () => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const importTransaction = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
if (wallet?.type !== WatchOnlyWallet.type) {
|
||||
return presentAlert({ title: loc.errors.error, message: 'Importing transaction in non-watchonly wallet (this should never happen)' });
|
||||
}
|
||||
@ -822,7 +815,6 @@ const SendDetails = () => {
|
||||
};
|
||||
|
||||
const _importTransactionMultisig = async (base64arg: string | false) => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
try {
|
||||
const base64 = base64arg || (await fs.openSignedTransaction());
|
||||
if (!base64) return;
|
||||
@ -868,8 +860,7 @@ const SendDetails = () => {
|
||||
};
|
||||
|
||||
const importTransactionMultisigScanQr = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
requestCameraAuthorization().then(() => {
|
||||
await requestCameraAuthorization().then(() => {
|
||||
navigation.navigate('ScanQRCodeRoot', {
|
||||
screen: 'ScanQRCode',
|
||||
params: {
|
||||
@ -882,8 +873,7 @@ const SendDetails = () => {
|
||||
|
||||
const handleAddRecipient = async () => {
|
||||
console.debug('handleAddRecipient');
|
||||
await optionsModalRef.current?.dismiss();
|
||||
setAddresses(addrs => [...addrs, { address: '', key: String(Math.random()) } as IPaymentDestinations]);
|
||||
await setAddresses(addrs => [...addrs, { address: '', key: String(Math.random()) } as IPaymentDestinations]);
|
||||
|
||||
await sleep(200); // wait for animation
|
||||
scrollView.current?.scrollToEnd();
|
||||
@ -892,7 +882,6 @@ const SendDetails = () => {
|
||||
};
|
||||
|
||||
const handleRemoveRecipient = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
const last = scrollIndex.current === addresses.length - 1;
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
||||
setAddresses(addrs => {
|
||||
@ -907,7 +896,6 @@ const SendDetails = () => {
|
||||
};
|
||||
|
||||
const handleCoinControl = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
if (!wallet) return;
|
||||
navigation.navigate('CoinControl', {
|
||||
walletID: wallet?.getID(),
|
||||
@ -916,13 +904,11 @@ const SendDetails = () => {
|
||||
};
|
||||
|
||||
const handleInsertContact = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
if (!wallet) return;
|
||||
navigation.navigate('PaymentCodeList', { walletID: wallet.getID() });
|
||||
};
|
||||
|
||||
const handlePsbtSign = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
setIsLoading(true);
|
||||
await new Promise(resolve => setTimeout(resolve, 100)); // sleep for animations
|
||||
|
||||
@ -1006,8 +992,8 @@ const SendDetails = () => {
|
||||
|
||||
actions.push([{ id: SendDetails.actionKeys.SendMax, text: loc.send.details_adv_full, disabled: balance === 0 || isSendMaxUsed }]);
|
||||
}
|
||||
if (wallet?.type === HDSegwitBech32Wallet.type) {
|
||||
actions.push([{ id: SendDetails.actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuStateOn: isTransactionReplaceable }]);
|
||||
if (wallet?.type === HDSegwitBech32Wallet.type && isTransactionReplaceable !== undefined) {
|
||||
actions.push([{ id: SendDetails.actionKeys.AllowRBF, text: loc.send.details_adv_fee_bump, menuState: !!isTransactionReplaceable }]);
|
||||
}
|
||||
const transactionActions = [];
|
||||
if (wallet?.type === WatchOnlyWallet.type && wallet.isHd()) {
|
||||
@ -1060,38 +1046,22 @@ const SendDetails = () => {
|
||||
|
||||
return actions;
|
||||
};
|
||||
|
||||
const setHeaderRightOptions = () => {
|
||||
navigation.setOptions({
|
||||
headerRight: Platform.select({
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
ios: () => (
|
||||
<ToolTipMenu
|
||||
disabled={isLoading}
|
||||
isButton
|
||||
isMenuPrimaryAction
|
||||
onPressMenuItem={headerRightOnPress}
|
||||
// @ts-ignore idk how to fix
|
||||
actions={headerRightActions()}
|
||||
>
|
||||
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} style={styles.advancedOptions} />
|
||||
</ToolTipMenu>
|
||||
),
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
default: () => (
|
||||
<TouchableOpacity
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={loc._.more}
|
||||
disabled={isLoading}
|
||||
style={styles.advancedOptions}
|
||||
onPress={() => {
|
||||
optionsModalRef.current?.present();
|
||||
}}
|
||||
testID="advancedOptionsMenuButton"
|
||||
>
|
||||
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} />
|
||||
</TouchableOpacity>
|
||||
),
|
||||
}),
|
||||
// eslint-disable-next-line react/no-unstable-nested-components
|
||||
headerRight: () => (
|
||||
<ToolTipMenu
|
||||
disabled={isLoading}
|
||||
isButton
|
||||
isMenuPrimaryAction
|
||||
onPressMenuItem={headerRightOnPress}
|
||||
actions={headerRightActions()}
|
||||
testID="advancedOptionsMenuButton"
|
||||
>
|
||||
<Icon size={22} name="more-horiz" type="material" color={colors.foregroundColor} style={styles.advancedOptions} />
|
||||
</ToolTipMenu>
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
@ -1119,8 +1089,7 @@ const SendDetails = () => {
|
||||
scrollIndex.current = index;
|
||||
};
|
||||
|
||||
const onUseAllPressed = async () => {
|
||||
await optionsModalRef.current?.dismiss();
|
||||
const onUseAllPressed = () => {
|
||||
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
|
||||
const message = frozenBalance > 0 ? loc.send.details_adv_full_sure_frozen : loc.send.details_adv_full_sure;
|
||||
Alert.alert(
|
||||
@ -1145,9 +1114,7 @@ const SendDetails = () => {
|
||||
},
|
||||
{
|
||||
text: loc._.cancel,
|
||||
onPress: () => {
|
||||
optionsModalRef.current?.present();
|
||||
},
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
],
|
||||
@ -1194,60 +1161,6 @@ const SendDetails = () => {
|
||||
return totalWithFee;
|
||||
};
|
||||
|
||||
const renderOptionsModal = () => {
|
||||
const isSendMaxUsed = addresses.some(element => element.amount === BitcoinUnit.MAX);
|
||||
|
||||
return (
|
||||
<BottomModal ref={optionsModalRef} backgroundColor={colors.modal} contentContainerStyle={styles.optionsContent}>
|
||||
{wallet?.allowBIP47() && wallet.isBIP47Enabled() && (
|
||||
<ListItem testID="InsertContactButton" title={loc.send.details_insert_contact} onPress={handleInsertContact} />
|
||||
)}
|
||||
{isEditable && (
|
||||
<ListItem
|
||||
testID="sendMaxButton"
|
||||
disabled={balance === 0 || isSendMaxUsed}
|
||||
title={loc.send.details_adv_full}
|
||||
onPress={onUseAllPressed}
|
||||
/>
|
||||
)}
|
||||
{wallet?.type === HDSegwitBech32Wallet.type && isEditable && (
|
||||
<ListItem
|
||||
title={loc.send.details_adv_fee_bump}
|
||||
Component={TouchableWithoutFeedback}
|
||||
switch={{ value: isTransactionReplaceable, onValueChange: onReplaceableFeeSwitchValueChanged }}
|
||||
/>
|
||||
)}
|
||||
{wallet?.type === WatchOnlyWallet.type && wallet.isHd() && (
|
||||
<ListItem title={loc.send.details_adv_import} onPress={importTransaction} />
|
||||
)}
|
||||
{wallet?.type === WatchOnlyWallet.type && wallet.isHd() && (
|
||||
<ListItem testID="ImportQrTransactionButton" title={loc.send.details_adv_import_qr} onPress={importQrTransaction} />
|
||||
)}
|
||||
{wallet?.type === MultisigHDWallet.type && isEditable && (
|
||||
<ListItem title={loc.send.details_adv_import} onPress={importTransactionMultisig} />
|
||||
)}
|
||||
{wallet?.type === MultisigHDWallet.type && wallet.howManySignaturesCanWeMake() > 0 && isEditable && (
|
||||
<ListItem title={loc.multisig.co_sign_transaction} onPress={importTransactionMultisigScanQr} />
|
||||
)}
|
||||
{isEditable && (
|
||||
<>
|
||||
<ListItem testID="AddRecipient" title={loc.send.details_add_rec_add} onPress={handleAddRecipient} />
|
||||
<ListItem
|
||||
testID="RemoveRecipient"
|
||||
title={loc.send.details_add_rec_rem}
|
||||
disabled={addresses.length < 2}
|
||||
onPress={handleRemoveRecipient}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<ListItem testID="CoinControl" title={loc.cc.header} onPress={handleCoinControl} />
|
||||
{(wallet as MultisigHDWallet)?.allowCosignPsbt() && isEditable && (
|
||||
<ListItem testID="PsbtSign" title={loc.send.psbt_sign} onPress={handlePsbtSign} />
|
||||
)}
|
||||
</BottomModal>
|
||||
);
|
||||
};
|
||||
|
||||
const renderCreateButton = () => {
|
||||
const totalWithFee = calculateTotalAmount();
|
||||
const isDisabled = totalWithFee === 0 || totalWithFee > balance || balance === 0 || isLoading || addresses.length === 0;
|
||||
@ -1288,7 +1201,7 @@ const SendDetails = () => {
|
||||
style={styles.selectTouch}
|
||||
onPress={() => {
|
||||
feeModalRef.current?.dismiss();
|
||||
optionsModalRef.current?.dismiss();
|
||||
|
||||
navigation.navigate('SelectWallet', { chainType: Chain.ONCHAIN });
|
||||
}}
|
||||
>
|
||||
@ -1475,7 +1388,6 @@ const SendDetails = () => {
|
||||
setCustomFee={setCustomFee}
|
||||
setFeePrecalc={setFeePrecalc}
|
||||
/>
|
||||
{renderOptionsModal()}
|
||||
</KeyboardAvoidingView>
|
||||
</View>
|
||||
<BlueDismissKeyboardInputAccessory />
|
||||
@ -1538,11 +1450,6 @@ const styles = StyleSheet.create({
|
||||
bottom: 0,
|
||||
right: 8,
|
||||
},
|
||||
|
||||
optionsContent: {
|
||||
padding: 22,
|
||||
},
|
||||
|
||||
createButton: {
|
||||
marginVertical: 16,
|
||||
marginHorizontal: 16,
|
||||
|
@ -208,23 +208,23 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
|
||||
// lest add another two outputs
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('AddRecipient')).tap();
|
||||
await element(by.text('Add Recipient')).tap();
|
||||
await yo('Transaction1'); // adding a recipient autoscrolls it to the last one
|
||||
await element(by.id('AddressInput').withAncestor(by.id('Transaction1'))).replaceText('bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl');
|
||||
await element(by.id('BitcoinAmountInput').withAncestor(by.id('Transaction1'))).replaceText('0.0002\n');
|
||||
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('AddRecipient')).tap();
|
||||
await element(by.text('Add Recipient')).tap();
|
||||
await yo('Transaction2'); // adding a recipient autoscrolls it to the last one
|
||||
|
||||
// remove last output, check if second output is shown
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('RemoveRecipient')).tap();
|
||||
await element(by.text('Remove Recipient')).tap();
|
||||
await yo('Transaction1');
|
||||
|
||||
// adding it again
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('AddRecipient')).tap();
|
||||
await element(by.text('Add Recipient')).tap();
|
||||
await yo('Transaction2'); // adding a recipient autoscrolls it to the last one
|
||||
await element(by.id('AddressInput').withAncestor(by.id('Transaction2'))).replaceText('bc1qh6tf004ty7z7un2v5ntu4mkf630545gvhs45u7');
|
||||
await element(by.id('BitcoinAmountInput').withAncestor(by.id('Transaction2'))).replaceText('0.0003\n');
|
||||
@ -233,7 +233,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await element(by.id('Transaction2')).swipe('right', 'fast', NaN, 0.2);
|
||||
await sleep(5000);
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('RemoveRecipient')).tap();
|
||||
await element(by.text('Remove Recipient')).tap();
|
||||
|
||||
// creating and verifying. tx should have 3 outputs
|
||||
if (process.env.TRAVIS) await sleep(5000);
|
||||
@ -282,7 +282,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await element(by.id('AddressInput')).replaceText('bc1qnapskphjnwzw2w3dk4anpxntunc77v6qrua0f7');
|
||||
await element(by.id('BitcoinAmountInput')).typeText('0.0001\n');
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('sendMaxButton')).tap();
|
||||
await element(by.text('Use Full Balance')).tap();
|
||||
await element(by.text('OK')).tap();
|
||||
|
||||
if (process.env.TRAVIS) await sleep(5000);
|
||||
@ -301,7 +301,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('AddRecipient')).tap();
|
||||
await element(by.text('Add Recipient')).tap();
|
||||
await yo('Transaction1');
|
||||
await element(by.id('AddressInput').withAncestor(by.id('Transaction1'))).replaceText('bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl');
|
||||
await element(by.id('BitcoinAmountInput').withAncestor(by.id('Transaction1'))).typeText('0.0001\n');
|
||||
@ -342,7 +342,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await element(by.id('SendButton')).tap();
|
||||
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('PsbtSign')).tap();
|
||||
await element(by.text('Sign a transaction')).tap();
|
||||
|
||||
// tapping 5 times invisible button is a backdoor:
|
||||
for (let c = 0; c <= 5; c++) {
|
||||
@ -491,7 +491,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await element(by.text('Imported HD SegWit (BIP84 Bech32 Native)')).tap();
|
||||
await element(by.id('SendButton')).tap();
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('CoinControl')).tap();
|
||||
await element(by.text('Coin Control')).tap();
|
||||
await waitFor(element(by.id('Loading'))) // wait for outputs to be loaded
|
||||
.not.toExist()
|
||||
.withTimeout(300 * 1000);
|
||||
@ -510,7 +510,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await element(by.id('UseCoin')).tap();
|
||||
await element(by.id('AddressInput')).replaceText('bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl');
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('sendMaxButton')).tap();
|
||||
await element(by.text('Use Full Balance')).tap();
|
||||
await element(by.text('OK')).tap();
|
||||
// setting fee rate:
|
||||
await element(by.id('chooseFee')).tap();
|
||||
@ -539,7 +539,7 @@ describe('BlueWallet UI Tests - import BIP84 wallet', () => {
|
||||
await element(by.id('SendButton')).tap();
|
||||
await element(by.id('AddressInput')).replaceText('bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl');
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('sendMaxButton')).tap();
|
||||
await element(by.text('Use Full Balance')).tap();
|
||||
await element(by.text('OK')).tap();
|
||||
// setting fee rate:
|
||||
await element(by.id('chooseFee')).tap();
|
||||
|
@ -56,7 +56,7 @@ describe('BlueWallet UI Tests - import Watch-only wallet (zpub)', () => {
|
||||
await element(by.text('OK')).tap();
|
||||
|
||||
await element(by.id('advancedOptionsMenuButton')).tap();
|
||||
await element(by.id('ImportQrTransactionButton')).tap(); // opens camera
|
||||
await element(by.text('Import Transaction (QR)')).tap(); // opens camera
|
||||
|
||||
// produced by real Keystone device using MNEMONICS_KEYSTONE
|
||||
const unsignedPsbt =
|
||||
|
Loading…
Reference in New Issue
Block a user