diff --git a/navigation/PaymentCodeStackParamList.ts b/navigation/PaymentCodeStackParamList.ts index e7d5281a8..e3bf6d5bb 100644 --- a/navigation/PaymentCodeStackParamList.ts +++ b/navigation/PaymentCodeStackParamList.ts @@ -9,7 +9,7 @@ export type PaymentCodeStackParamList = { amount: number; amountSats: number; unit: BitcoinUnit; - noRbf: boolean; + isTransactionReplaceable: boolean; launchedBy: string; isEditable: boolean; uri: string /* payjoin uri */; diff --git a/navigation/SendDetailsStack.tsx b/navigation/SendDetailsStack.tsx index 6557caecf..ec5fbc0da 100644 --- a/navigation/SendDetailsStack.tsx +++ b/navigation/SendDetailsStack.tsx @@ -17,6 +17,7 @@ import { } from './LazyLoadSendDetailsStack'; import { SendDetailsStackParamList } from './SendDetailsStackParamList'; import HeaderRightButton from '../components/HeaderRightButton'; +import { BitcoinUnit } from '../models/bitcoinUnits'; const Stack = createNativeStackNavigator(); @@ -37,7 +38,7 @@ const SendDetailsStack = () => { statusBarStyle: 'light', closeButtonPosition: CloseButtonPosition.Left, })(theme)} - initialParams={{ isEditable: true }} // Correctly typed now + initialParams={{ isEditable: true, feeUnit: BitcoinUnit.BTC, amountUnit: BitcoinUnit.BTC }} // Correctly typed now /> void; }; PaymentCodeList: { walletID: string; diff --git a/screen/send/SendDetails.tsx b/screen/send/SendDetails.tsx index 74cd43c79..529a2a0ac 100644 --- a/screen/send/SendDetails.tsx +++ b/screen/send/SendDetails.tsx @@ -81,6 +81,13 @@ const SendDetails = () => { const setParams = navigation.setParams; const route = useRoute(); const name = route.name; + const feeUnit = route.params?.feeUnit ?? BitcoinUnit.BTC; + const amountUnit = route.params?.amountUnit ?? BitcoinUnit.BTC; + const frozenBalance = route.params?.frozenBalance ?? 0; + const transactionMemo = route.params?.transactionMemo; + const utxos = route.params?.utxos; + const payjoinUrl = route.params?.payjoinUrl; + const isTransactionReplaceable = route.params?.isTransactionReplaceable; const routeParams = route.params; const scrollView = useRef>(null); const scrollIndex = useRef(0); @@ -92,26 +99,18 @@ const SendDetails = () => { const [isLoading, setIsLoading] = useState(false); const [wallet, setWallet] = useState(null); const feeModalRef = useRef(null); - const [walletSelectionOrCoinsSelectedHidden, setWalletSelectionOrCoinsSelectedHidden] = useState(false); - const [isAmountToolbarVisibleForAndroid, setIsAmountToolbarVisibleForAndroid] = useState(false); - const [isTransactionReplaceable, setIsTransactionReplaceable] = useState(false); + const { isVisible } = useKeyboard(); const [addresses, setAddresses] = useState([]); const [units, setUnits] = useState([]); - const [transactionMemo, setTransactionMemo] = useState(''); const [networkTransactionFees, setNetworkTransactionFees] = useState(new NetworkTransactionFee(3, 2, 1)); const [networkTransactionFeesIsLoading, setNetworkTransactionFeesIsLoading] = useState(false); const [customFee, setCustomFee] = useState(null); const [feePrecalc, setFeePrecalc] = useState({ current: null, slowFee: null, mediumFee: null, fastestFee: null }); - const [feeUnit, setFeeUnit] = useState(); - const [amountUnit, setAmountUnit] = useState(); - const [utxo, setUtxo] = useState(null); - const [frozenBalance, setFrozenBlance] = useState(0); - const [payjoinUrl, setPayjoinUrl] = useState(null); const [changeAddress, setChangeAddress] = useState(null); const [dumb, setDumb] = useState(false); const { isEditable } = routeParams; // if utxo is limited we use it to calculate available balance - const balance: number = utxo ? utxo.reduce((prev, curr) => prev + curr.value, 0) : (wallet?.getBalance() ?? 0); + const balance: number = utxos ? utxos.reduce((prev, curr) => prev + curr.value, 0) : (wallet?.getBalance() ?? 0); const allBalance = formatBalanceWithoutSuffix(balance, BitcoinUnit.BTC, true); // if cutomFee is not set, we need to choose highest possible fee for wallet balance @@ -138,17 +137,6 @@ const SendDetails = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [colors, wallet, isTransactionReplaceable, balance, addresses, isEditable, isLoading]); - useKeyboard({ - onKeyboardDidShow: () => { - setWalletSelectionOrCoinsSelectedHidden(true); - setIsAmountToolbarVisibleForAndroid(true); - }, - onKeyboardDidHide: () => { - setWalletSelectionOrCoinsSelectedHidden(false); - setIsAmountToolbarVisibleForAndroid(false); - }, - }); - useEffect(() => { // decode route params const currentAddress = addresses[scrollIndex.current]; @@ -176,10 +164,9 @@ const SendDetails = () => { }); if (memo?.trim().length > 0) { - setTransactionMemo(memo); + setParams({ transactionMemo: memo }); } - setAmountUnit(BitcoinUnit.BTC); - setPayjoinUrl(pjUrl); + setParams({ payjoinUrl: pjUrl, amountUnit: BitcoinUnit.BTC }); } catch (error) { console.log(error); presentAlert({ title: loc.errors.error, message: loc.send.details_error_decode }); @@ -196,9 +183,6 @@ const SendDetails = () => { return [...value, { address: routeParams.address, key: String(Math.random()), amount, amountSats }]; } }); - if (routeParams.memo && routeParams.memo?.trim().length > 0) { - setTransactionMemo(routeParams.memo); - } setUnits(u => { u[scrollIndex.current] = unit; return [...u]; @@ -238,8 +222,7 @@ const SendDetails = () => { } const newWallet = (routeParams.walletID && wallets.find(w => w.getID() === routeParams.walletID)) || suitable[0]; setWallet(newWallet); - setFeeUnit(newWallet.getPreferredBalanceUnit()); - setAmountUnit(newWallet.preferredBalanceUnit); // default for whole screen + setParams({ feeUnit: newWallet.getPreferredBalanceUnit(), amountUnit: newWallet.getPreferredBalanceUnit() }); // we are ready! setIsLoading(false); @@ -276,9 +259,11 @@ const SendDetails = () => { setSelectedWalletID(wallet.getID()); // reset other values - setUtxo(null); setChangeAddress(null); - setIsTransactionReplaceable(wallet.type === HDSegwitBech32Wallet.type && !routeParams.noRbf ? true : undefined); + setParams({ + utxos: null, + isTransactionReplaceable: wallet.type === HDSegwitBech32Wallet.type && !routeParams.isTransactionReplaceable ? true : undefined, + }); // update wallet UTXO wallet .fetchUtxo() @@ -294,9 +279,9 @@ const SendDetails = () => { if (!wallet) return; // wait for it const fees = networkTransactionFees; const requestedSatPerByte = Number(feeRate); - const lutxo = utxo || wallet.getUtxo(); + const lutxo = utxos || wallet.getUtxo(); let frozen = 0; - if (!utxo) { + if (!utxos) { // if utxo is not limited search for frozen outputs and calc it's balance frozen = wallet .getUtxo(true) @@ -369,8 +354,8 @@ const SendDetails = () => { } setFeePrecalc(newFeePrecalc); - setFrozenBlance(frozen); - }, [wallet, networkTransactionFees, utxo, addresses, feeRate, dumb]); // eslint-disable-line react-hooks/exhaustive-deps + setParams({ frozenBalance: frozen }); + }, [wallet, networkTransactionFees, utxos, addresses, feeRate, dumb]); // eslint-disable-line react-hooks/exhaustive-deps // we need to re-calculate fees if user opens-closes coin control useFocusEffect( @@ -470,9 +455,7 @@ const SendDetails = () => { u[scrollIndex.current] = BitcoinUnit.BTC; // also resetting current unit to BTC return [...u]; }); - setTransactionMemo(options.label || ''); // there used to be `options.message` here as well. bug? - setAmountUnit(BitcoinUnit.BTC); - setPayjoinUrl(options.pj || ''); + setParams({ transactionMemo: options.label || '', amountUnit: BitcoinUnit.BTC, payjoinUrl: options.pj || '' }); // there used to be `options.message` here as well. bug? // RN Bug: contentOffset gets reset to 0 when state changes. Remove code once this bug is resolved. setTimeout(() => scrollView.current?.scrollToIndex({ index: currentIndex, animated: false }), 50); } @@ -565,7 +548,7 @@ const SendDetails = () => { const change = await getChangeAddressAsync(); assert(change, 'Could not get change address'); const requestedSatPerByte = Number(feeRate); - const lutxo: CreateTransactionUtxo[] = utxo || (wallet?.getUtxo() ?? []); + const lutxo: CreateTransactionUtxo[] = utxos || (wallet?.getUtxo() ?? []); console.log({ requestedSatPerByte, lutxo: lutxo.length }); const targets: CreateTransactionTarget[] = []; @@ -669,6 +652,10 @@ const SendDetails = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [routeParams.walletID]); + const setTransactionMemo = (memo: string) => { + setParams({ transactionMemo: memo }); + }; + /** * same as `importTransaction`, but opens camera instead. * @@ -898,7 +885,6 @@ const SendDetails = () => { if (!wallet) return; navigation.navigate('CoinControl', { walletID: wallet?.getID(), - onUTXOChoose: (u: CreateTransactionUtxo[]) => setUtxo(u), }); }; @@ -1050,7 +1036,7 @@ const SendDetails = () => { }; const onReplaceableFeeSwitchValueChanged = (value: boolean) => { - setIsTransactionReplaceable(value); + setParams({ isTransactionReplaceable: value }); }; const handleRecipientsScroll = (e: NativeSyntheticEvent) => { @@ -1141,16 +1127,16 @@ const SendDetails = () => { }; const renderWalletSelectionOrCoinsSelected = () => { - if (walletSelectionOrCoinsSelectedHidden) return null; - if (utxo !== null) { + if (isVisible) return null; + if (utxos !== null) { return ( { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); - setUtxo(null); + setParams({ utxos: null }); }} /> @@ -1262,9 +1248,11 @@ const SendDetails = () => { addrs[index] = item; return [...addrs]; }); - setTransactionMemo(memo || transactionMemo); + if (memo) { + setParams({ transactionMemo: memo }); + } setIsLoading(false); - setPayjoinUrl(pjUrl); + setParams({ payjoinUrl: pjUrl }); }} onBarScanned={processAddressData} address={item.address} @@ -1354,7 +1342,7 @@ const SendDetails = () => { {Platform.select({ ios: 0} onUseAllPressed={onUseAllPressed} balance={String(allBalance)} />, - android: isAmountToolbarVisibleForAndroid && ( + android: isVisible && ( 0} onUseAllPressed={onUseAllPressed} balance={String(allBalance)} /> ), })} diff --git a/screen/send/coinControl.js b/screen/send/coinControl.js index 47d6df68a..9811dc019 100644 --- a/screen/send/coinControl.js +++ b/screen/send/coinControl.js @@ -260,7 +260,7 @@ const CoinControl = () => { const navigation = useExtendedNavigation(); const { width } = useWindowDimensions(); const bottomModalRef = useRef(null); - const { walletID, onUTXOChoose } = useRoute().params; + const { walletID } = useRoute().params; const { wallets, saveToDisk, sleep } = useStorage(); const wallet = wallets.find(w => w.getID() === walletID); // sort by height ascending, txid , vout ascending @@ -329,8 +329,13 @@ const CoinControl = () => { const handleUseCoin = async u => { setOutput(null); - navigation.pop(); - onUTXOChoose(u); + navigation.navigate('SendDetailsRoot', { + screen: 'SendDetails', + params: { + utxos: u, + }, + merge: true, + }); }; const handleMassFreeze = () => { @@ -476,7 +481,7 @@ const styles = StyleSheet.create({ padding: { padding: 16, }, - modalMinHeight: Platform.OS === 'android' ? { minHeight: 490 } : {}, + modalMinHeight: Platform.OS === 'android' ? { minHeight: 530 } : {}, empty: { flex: 1, justifyContent: 'center',