REF: Move to params for better predictability

This commit is contained in:
Marcos Rodriguez Velez 2024-10-23 18:36:28 -04:00
parent cebdea6d25
commit 60fb4ef9bf
6 changed files with 64 additions and 57 deletions

View File

@ -5,6 +5,9 @@ import { scanQrHelper } from '../helpers/scan-qr';
import loc from '../loc';
import presentAlert from './Alert';
import ToolTipMenu from './TooltipMenu';
import { showFilePickerAndReadFile, showImagePickerAndReadImage } from '../blue_modules/fs';
import Clipboard from '@react-native-clipboard/clipboard';
import { useTheme } from './themes';
interface AddressInputProps {
isLoading?: boolean;

View File

@ -17,6 +17,7 @@ import {
} from './LazyLoadSendDetailsStack';
import { SendDetailsStackParamList } from './SendDetailsStackParamList';
import HeaderRightButton from '../components/HeaderRightButton';
import { BitcoinUnit } from '../models/bitcoinUnits';
const Stack = createNativeStackNavigator<SendDetailsStackParamList>();
@ -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
/>
<Stack.Screen
name="Confirm"

View File

@ -3,7 +3,12 @@ import { CreateTransactionTarget, CreateTransactionUtxo, TWallet } from '../clas
import { BitcoinUnit, Chain } from '../models/bitcoinUnits';
export type SendDetailsParams = {
memo?: string;
transactionMemo?: string;
isTransactionReplaceable?: boolean;
payjoinUrl?: string;
feeUnit?: BitcoinUnit;
frozenBalance?: number;
amountUnit?: BitcoinUnit;
address?: string;
amount?: number;
amountSats?: number;
@ -11,6 +16,7 @@ export type SendDetailsParams = {
noRbf?: boolean;
walletID: string;
launchedBy?: string;
utxos?: CreateTransactionUtxo[] | null;
isEditable?: boolean;
uri?: string;
addRecipientParams?: {
@ -74,7 +80,6 @@ export type SendDetailsStackParamList = {
};
CoinControl: {
walletID: string;
onUTXOChoose: (u: CreateTransactionUtxo[]) => void;
};
PaymentCodeList: {
walletID: string;

View File

@ -340,7 +340,11 @@ const Confirm: React.FC = () => {
{state.isLoading ? (
<ActivityIndicator />
) : (
<Button disabled={isElectrumDisabled || state.isButtonDisabled} onPress={handleSendTransaction} title={loc.send.confirm_sendNow} />
<Button
disabled={isElectrumDisabled || state.isButtonDisabled}
onPress={handleSendTransaction}
title={loc.send.confirm_sendNow}
/>
)}
</BlueCard>
</View>

View File

@ -81,6 +81,13 @@ const SendDetails = () => {
const setParams = navigation.setParams;
const route = useRoute<RouteProps>();
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<FlatList<any>>(null);
const scrollIndex = useRef(0);
@ -92,26 +99,18 @@ const SendDetails = () => {
const [isLoading, setIsLoading] = useState(false);
const [wallet, setWallet] = useState<TWallet | null>(null);
const feeModalRef = useRef<BottomModalHandle>(null);
const [walletSelectionOrCoinsSelectedHidden, setWalletSelectionOrCoinsSelectedHidden] = useState(false);
const [isAmountToolbarVisibleForAndroid, setIsAmountToolbarVisibleForAndroid] = useState(false);
const [isTransactionReplaceable, setIsTransactionReplaceable] = useState<boolean | undefined>(false);
const { isVisible } = useKeyboard();
const [addresses, setAddresses] = useState<IPaymentDestinations[]>([]);
const [units, setUnits] = useState<BitcoinUnit[]>([]);
const [transactionMemo, setTransactionMemo] = useState<string>('');
const [networkTransactionFees, setNetworkTransactionFees] = useState(new NetworkTransactionFee(3, 2, 1));
const [networkTransactionFeesIsLoading, setNetworkTransactionFeesIsLoading] = useState(false);
const [customFee, setCustomFee] = useState<string | null>(null);
const [feePrecalc, setFeePrecalc] = useState<IFee>({ current: null, slowFee: null, mediumFee: null, fastestFee: null });
const [feeUnit, setFeeUnit] = useState<BitcoinUnit>();
const [amountUnit, setAmountUnit] = useState<BitcoinUnit>();
const [utxo, setUtxo] = useState<CreateTransactionUtxo[] | null>(null);
const [frozenBalance, setFrozenBlance] = useState<number>(0);
const [payjoinUrl, setPayjoinUrl] = useState<string | null>(null);
const [changeAddress, setChangeAddress] = useState<string | null>(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.noRbf ? 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,8 @@ 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 }); // there used to be `options.message` here as well. bug?
setParams({ payjoinUrl: options.pj || '' });
// 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 +549,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 +653,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 +886,6 @@ const SendDetails = () => {
if (!wallet) return;
navigation.navigate('CoinControl', {
walletID: wallet?.getID(),
onUTXOChoose: (u: CreateTransactionUtxo[]) => setUtxo(u),
});
};
@ -1050,7 +1037,7 @@ const SendDetails = () => {
};
const onReplaceableFeeSwitchValueChanged = (value: boolean) => {
setIsTransactionReplaceable(value);
setParams({ isTransactionReplaceable: value });
};
const handleRecipientsScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {
@ -1141,16 +1128,16 @@ const SendDetails = () => {
};
const renderWalletSelectionOrCoinsSelected = () => {
if (walletSelectionOrCoinsSelectedHidden) return null;
if (utxo !== null) {
if (isVisible) return null;
if (utxos !== null) {
return (
<View style={styles.select}>
<CoinsSelected
number={utxo.length}
number={utxos?.length || 0}
onContainerPress={handleCoinControl}
onClose={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
setUtxo(null);
setParams({ utxos: null });
}}
/>
</View>
@ -1262,9 +1249,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 +1343,7 @@ const SendDetails = () => {
<DismissKeyboardInputAccessory />
{Platform.select({
ios: <InputAccessoryAllFunds canUseAll={balance > 0} onUseAllPressed={onUseAllPressed} balance={String(allBalance)} />,
android: isAmountToolbarVisibleForAndroid && (
android: isVisible && (
<InputAccessoryAllFunds canUseAll={balance > 0} onUseAllPressed={onUseAllPressed} balance={String(allBalance)} />
),
})}

View File

@ -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',