2021-08-26 22:38:30 +01:00
|
|
|
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
2020-06-10 23:54:47 -04:00
|
|
|
import {
|
2021-08-26 22:38:30 +01:00
|
|
|
BackHandler,
|
2020-06-10 23:54:47 -04:00
|
|
|
InteractionManager,
|
|
|
|
Keyboard,
|
2020-11-17 11:43:38 +03:00
|
|
|
KeyboardAvoidingView,
|
|
|
|
Platform,
|
2020-06-10 23:54:47 -04:00
|
|
|
ScrollView,
|
2020-11-17 11:43:38 +03:00
|
|
|
StyleSheet,
|
|
|
|
TextInput,
|
|
|
|
View,
|
2020-06-10 23:54:47 -04:00
|
|
|
} from 'react-native';
|
2024-03-24 16:29:58 -04:00
|
|
|
import { useRoute, useFocusEffect } from '@react-navigation/native';
|
2020-11-17 11:43:38 +03:00
|
|
|
import Share from 'react-native-share';
|
2022-01-28 15:32:09 +03:00
|
|
|
import QRCodeComponent from '../../components/QRCodeComponent';
|
2024-03-27 00:37:43 -04:00
|
|
|
import { BlueLoading, BlueButtonLink, BlueText, BlueSpacing20, BlueCard, BlueSpacing40 } from '../../BlueComponents';
|
2020-11-17 11:43:38 +03:00
|
|
|
import BottomModal from '../../components/BottomModal';
|
2019-12-15 01:10:22 -05:00
|
|
|
import { Chain, BitcoinUnit } from '../../models/bitcoinUnits';
|
2024-04-02 21:50:19 -04:00
|
|
|
import HandOffComponent from '../../components/HandOffComponent';
|
2021-02-25 19:13:34 +03:00
|
|
|
import AmountInput from '../../components/AmountInput';
|
2020-04-28 15:48:36 +01:00
|
|
|
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
|
2021-08-26 22:38:30 +01:00
|
|
|
import loc, { formatBalance } from '../../loc';
|
2020-10-24 13:20:59 -04:00
|
|
|
import { BlueStorageContext } from '../../blue_modules/storage-context';
|
|
|
|
import Notifications from '../../blue_modules/notifications';
|
2021-08-26 22:38:30 +01:00
|
|
|
import { TransactionPendingIconBig } from '../../components/TransactionPendingIconBig';
|
|
|
|
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
|
2022-02-23 11:13:20 -05:00
|
|
|
import { SuccessView } from '../send/success';
|
2023-10-23 21:28:44 -04:00
|
|
|
import { useTheme } from '../../components/themes';
|
2023-11-15 04:40:22 -04:00
|
|
|
import Button from '../../components/Button';
|
2023-12-29 07:52:12 -04:00
|
|
|
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
2024-01-28 11:11:08 -04:00
|
|
|
import { fiatToBTC, satoshiToBTC } from '../../blue_modules/currency';
|
2024-03-24 16:29:58 -04:00
|
|
|
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
2024-03-27 00:37:43 -04:00
|
|
|
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
|
2018-01-30 22:42:38 +00:00
|
|
|
|
2020-04-20 00:03:36 -04:00
|
|
|
const ReceiveDetails = () => {
|
2021-04-17 13:43:39 -04:00
|
|
|
const { walletID, address } = useRoute().params;
|
2021-08-26 22:38:30 +01:00
|
|
|
const { wallets, saveToDisk, sleep, isElectrumDisabled, fetchAndSaveWalletTransactions } = useContext(BlueStorageContext);
|
2020-11-03 15:23:34 -05:00
|
|
|
const wallet = wallets.find(w => w.getID() === walletID);
|
2020-04-20 00:03:36 -04:00
|
|
|
const [customLabel, setCustomLabel] = useState();
|
2021-07-03 11:27:44 -04:00
|
|
|
const [customAmount, setCustomAmount] = useState();
|
2020-06-09 15:08:18 +01:00
|
|
|
const [customUnit, setCustomUnit] = useState(BitcoinUnit.BTC);
|
2020-04-20 00:03:36 -04:00
|
|
|
const [bip21encoded, setBip21encoded] = useState();
|
|
|
|
const [isCustom, setIsCustom] = useState(false);
|
|
|
|
const [isCustomModalVisible, setIsCustomModalVisible] = useState(false);
|
2021-08-26 22:38:30 +01:00
|
|
|
const [showPendingBalance, setShowPendingBalance] = useState(false);
|
|
|
|
const [showConfirmedBalance, setShowConfirmedBalance] = useState(false);
|
2020-07-22 23:28:12 -04:00
|
|
|
const [showAddress, setShowAddress] = useState(false);
|
2024-03-24 16:29:58 -04:00
|
|
|
const { goBack, setParams } = useExtendedNavigation();
|
2020-07-15 13:32:59 -04:00
|
|
|
const { colors } = useTheme();
|
2021-08-26 22:38:30 +01:00
|
|
|
const [intervalMs, setIntervalMs] = useState(5000);
|
|
|
|
const [eta, setEta] = useState('');
|
|
|
|
const [initialConfirmed, setInitialConfirmed] = useState(0);
|
|
|
|
const [initialUnconfirmed, setInitialUnconfirmed] = useState(0);
|
|
|
|
const [displayBalance, setDisplayBalance] = useState('');
|
|
|
|
const fetchAddressInterval = useRef();
|
2024-03-20 19:16:12 -04:00
|
|
|
const receiveAddressButton = useRef();
|
2021-08-29 12:28:56 -04:00
|
|
|
const stylesHook = StyleSheet.create({
|
2020-07-15 13:32:59 -04:00
|
|
|
modalContent: {
|
2020-10-24 13:20:59 -04:00
|
|
|
backgroundColor: colors.modal,
|
2020-07-15 13:32:59 -04:00
|
|
|
borderTopColor: colors.foregroundColor,
|
|
|
|
borderWidth: colors.borderWidth,
|
|
|
|
},
|
|
|
|
customAmount: {
|
2020-10-24 13:20:59 -04:00
|
|
|
borderColor: colors.formBorder,
|
|
|
|
borderBottomColor: colors.formBorder,
|
|
|
|
backgroundColor: colors.inputBackgroundColor,
|
2020-07-15 13:32:59 -04:00
|
|
|
},
|
|
|
|
customAmountText: {
|
2020-10-24 13:20:59 -04:00
|
|
|
color: colors.foregroundColor,
|
2020-07-15 13:32:59 -04:00
|
|
|
},
|
|
|
|
root: {
|
2020-10-24 13:20:59 -04:00
|
|
|
backgroundColor: colors.elevated,
|
2020-07-15 13:32:59 -04:00
|
|
|
},
|
2021-08-29 12:28:56 -04:00
|
|
|
rootBackgroundColor: {
|
|
|
|
backgroundColor: colors.elevated,
|
|
|
|
},
|
2020-07-15 13:32:59 -04:00
|
|
|
amount: {
|
2020-10-24 13:20:59 -04:00
|
|
|
color: colors.foregroundColor,
|
2020-07-15 13:32:59 -04:00
|
|
|
},
|
|
|
|
label: {
|
2020-10-24 13:20:59 -04:00
|
|
|
color: colors.foregroundColor,
|
2020-07-15 13:32:59 -04:00
|
|
|
},
|
|
|
|
modalButton: {
|
2020-10-24 13:20:59 -04:00
|
|
|
backgroundColor: colors.modalButton,
|
2020-07-15 13:32:59 -04:00
|
|
|
},
|
|
|
|
});
|
2018-01-30 22:42:38 +00:00
|
|
|
|
2021-08-29 12:28:56 -04:00
|
|
|
useEffect(() => {
|
|
|
|
if (showConfirmedBalance) {
|
2023-12-29 07:52:12 -04:00
|
|
|
triggerHapticFeedback(HapticFeedbackTypes.NotificationSuccess);
|
2021-08-29 12:28:56 -04:00
|
|
|
}
|
|
|
|
}, [showConfirmedBalance]);
|
|
|
|
|
2021-08-26 22:38:30 +01:00
|
|
|
// re-fetching address balance periodically
|
|
|
|
useEffect(() => {
|
2024-03-24 16:49:28 -04:00
|
|
|
console.log('receive/details - useEffect');
|
2021-08-26 22:38:30 +01:00
|
|
|
|
2024-03-24 16:49:28 -04:00
|
|
|
const intervalId = setInterval(async () => {
|
2021-08-26 22:38:30 +01:00
|
|
|
try {
|
|
|
|
const decoded = DeeplinkSchemaMatch.bip21decode(bip21encoded);
|
2024-03-24 16:49:28 -04:00
|
|
|
const addressToUse = address || decoded.address;
|
|
|
|
if (!addressToUse) return;
|
2021-08-26 22:38:30 +01:00
|
|
|
|
2024-03-24 16:49:28 -04:00
|
|
|
console.log('checking address', addressToUse, 'for balance...');
|
|
|
|
const balance = await BlueElectrum.getBalanceByAddress(addressToUse);
|
2021-08-26 22:38:30 +01:00
|
|
|
console.log('...got', balance);
|
|
|
|
|
|
|
|
if (balance.unconfirmed > 0) {
|
|
|
|
if (initialConfirmed === 0 && initialUnconfirmed === 0) {
|
|
|
|
setInitialConfirmed(balance.confirmed);
|
|
|
|
setInitialUnconfirmed(balance.unconfirmed);
|
|
|
|
setIntervalMs(25000);
|
2023-12-29 07:52:12 -04:00
|
|
|
triggerHapticFeedback(HapticFeedbackTypes.ImpactHeavy);
|
2021-08-26 22:38:30 +01:00
|
|
|
}
|
|
|
|
|
2024-03-24 16:49:28 -04:00
|
|
|
const txs = await BlueElectrum.getMempoolTransactionsByAddress(addressToUse);
|
2021-08-26 22:38:30 +01:00
|
|
|
const tx = txs.pop();
|
|
|
|
if (tx) {
|
2024-03-25 00:07:43 +03:00
|
|
|
const rez = await BlueElectrum.multiGetTransactionByTxid([tx.tx_hash], true, 10);
|
2021-08-26 22:38:30 +01:00
|
|
|
if (rez && rez[tx.tx_hash] && rez[tx.tx_hash].vsize) {
|
|
|
|
const satPerVbyte = Math.round(tx.fee / rez[tx.tx_hash].vsize);
|
|
|
|
const fees = await BlueElectrum.estimateFees();
|
|
|
|
if (satPerVbyte >= fees.fast) {
|
2021-08-27 16:14:29 +01:00
|
|
|
setEta(loc.formatString(loc.transactions.eta_10m));
|
2024-03-24 16:49:28 -04:00
|
|
|
} else if (satPerVbyte >= fees.medium) {
|
2021-08-27 16:14:29 +01:00
|
|
|
setEta(loc.formatString(loc.transactions.eta_3h));
|
2024-03-24 16:49:28 -04:00
|
|
|
} else {
|
2021-08-27 16:14:29 +01:00
|
|
|
setEta(loc.formatString(loc.transactions.eta_1d));
|
2021-08-26 22:38:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setDisplayBalance(
|
|
|
|
loc.formatString(loc.transactions.pending_with_amount, {
|
|
|
|
amt1: formatBalance(balance.unconfirmed, BitcoinUnit.LOCAL_CURRENCY, true).toString(),
|
|
|
|
amt2: formatBalance(balance.unconfirmed, BitcoinUnit.BTC, true).toString(),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
setShowPendingBalance(true);
|
|
|
|
setShowAddress(false);
|
|
|
|
} else if (balance.unconfirmed === 0 && initialUnconfirmed !== 0) {
|
|
|
|
// now, handling a case when unconfirmed == 0, but in past it wasnt (i.e. it changed while user was
|
|
|
|
// staring at the screen)
|
|
|
|
const balanceToShow = balance.confirmed - initialConfirmed;
|
|
|
|
|
|
|
|
if (balanceToShow > 0) {
|
2024-03-13 22:13:17 +08:00
|
|
|
// address has actually more coins than initially, so we definitely gained something
|
2021-08-26 22:38:30 +01:00
|
|
|
setShowConfirmedBalance(true);
|
|
|
|
setShowPendingBalance(false);
|
|
|
|
setShowAddress(false);
|
|
|
|
setDisplayBalance(
|
|
|
|
loc.formatString(loc.transactions.received_with_amount, {
|
|
|
|
amt1: formatBalance(balanceToShow, BitcoinUnit.LOCAL_CURRENCY, true).toString(),
|
|
|
|
amt2: formatBalance(balanceToShow, BitcoinUnit.BTC, true).toString(),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
fetchAndSaveWalletTransactions(walletID);
|
|
|
|
} else {
|
|
|
|
// rare case, but probable. transaction evicted from mempool (maybe cancelled by the sender)
|
|
|
|
setShowConfirmedBalance(false);
|
|
|
|
setShowPendingBalance(false);
|
|
|
|
setShowAddress(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.log(error);
|
|
|
|
}
|
|
|
|
}, intervalMs);
|
2024-03-24 16:49:28 -04:00
|
|
|
|
|
|
|
return () => clearInterval(intervalId);
|
2021-08-26 22:38:30 +01:00
|
|
|
}, [bip21encoded, address, initialConfirmed, initialUnconfirmed, intervalMs, fetchAndSaveWalletTransactions, walletID]);
|
|
|
|
|
|
|
|
const renderConfirmedBalance = () => {
|
|
|
|
return (
|
2021-08-29 12:28:56 -04:00
|
|
|
<ScrollView style={stylesHook.rootBackgroundColors} centerContent keyboardShouldPersistTaps="always">
|
2022-01-28 15:32:09 +03:00
|
|
|
<View style={styles.scrollBody}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{isCustom && (
|
|
|
|
<>
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText style={[styles.label, stylesHook.label]} numberOfLines={1}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{customLabel}
|
|
|
|
</BlueText>
|
|
|
|
</>
|
|
|
|
)}
|
2022-02-23 11:13:20 -05:00
|
|
|
<SuccessView />
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText style={[styles.label, stylesHook.label]} numberOfLines={1}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{displayBalance}
|
|
|
|
</BlueText>
|
|
|
|
</View>
|
|
|
|
</ScrollView>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const renderPendingBalance = () => {
|
|
|
|
return (
|
2021-08-29 12:28:56 -04:00
|
|
|
<ScrollView contentContainerStyle={stylesHook.rootBackgroundColor} centerContent keyboardShouldPersistTaps="always">
|
2022-01-28 15:32:09 +03:00
|
|
|
<View style={styles.scrollBody}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{isCustom && (
|
|
|
|
<>
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText style={[styles.label, stylesHook.label]} numberOfLines={1}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{customLabel}
|
|
|
|
</BlueText>
|
|
|
|
</>
|
|
|
|
)}
|
2021-08-29 12:28:56 -04:00
|
|
|
<TransactionPendingIconBig />
|
2021-08-26 22:38:30 +01:00
|
|
|
<BlueSpacing40 />
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText style={[styles.label, stylesHook.label]} numberOfLines={1}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{displayBalance}
|
|
|
|
</BlueText>
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText style={[styles.label, stylesHook.label]} numberOfLines={1}>
|
2021-08-26 22:38:30 +01:00
|
|
|
{eta}
|
|
|
|
</BlueText>
|
|
|
|
</View>
|
|
|
|
</ScrollView>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleBackButton = () => {
|
|
|
|
goBack(null);
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
BackHandler.addEventListener('hardwareBackPress', handleBackButton);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
BackHandler.removeEventListener('hardwareBackPress', handleBackButton);
|
|
|
|
clearInterval(fetchAddressInterval.current);
|
|
|
|
fetchAddressInterval.current = undefined;
|
|
|
|
};
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
}, []);
|
|
|
|
|
2020-07-22 23:28:12 -04:00
|
|
|
const renderReceiveDetails = () => {
|
|
|
|
return (
|
2022-01-28 15:32:09 +03:00
|
|
|
<ScrollView contentContainerStyle={[styles.root, stylesHook.root]} keyboardShouldPersistTaps="always">
|
|
|
|
<View style={styles.scrollBody}>
|
2020-07-22 23:28:12 -04:00
|
|
|
{isCustom && (
|
|
|
|
<>
|
2021-11-08 10:31:25 -05:00
|
|
|
{getDisplayAmount() && (
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText testID="CustomAmountText" style={[styles.amount, stylesHook.amount]} numberOfLines={1}>
|
2021-11-08 10:31:25 -05:00
|
|
|
{getDisplayAmount()}
|
|
|
|
</BlueText>
|
|
|
|
)}
|
|
|
|
{customLabel?.length > 0 && (
|
2022-01-28 15:32:09 +03:00
|
|
|
<BlueText testID="CustomAmountDescriptionText" style={[styles.label, stylesHook.label]} numberOfLines={1}>
|
2021-11-08 10:31:25 -05:00
|
|
|
{customLabel}
|
|
|
|
</BlueText>
|
|
|
|
)}
|
2020-07-22 23:28:12 -04:00
|
|
|
</>
|
|
|
|
)}
|
2021-08-26 21:31:36 -04:00
|
|
|
|
|
|
|
<QRCodeComponent value={bip21encoded} />
|
2024-03-27 00:37:43 -04:00
|
|
|
<CopyTextToClipboard text={isCustom ? bip21encoded : address} ref={receiveAddressButton} />
|
2020-07-22 23:28:12 -04:00
|
|
|
</View>
|
2022-01-28 15:32:09 +03:00
|
|
|
<View style={styles.share}>
|
2021-04-21 08:25:00 -04:00
|
|
|
<BlueCard>
|
|
|
|
<BlueButtonLink
|
2022-01-28 15:32:09 +03:00
|
|
|
style={styles.link}
|
2021-04-21 08:25:00 -04:00
|
|
|
testID="SetCustomAmountButton"
|
|
|
|
title={loc.receive.details_setAmount}
|
|
|
|
onPress={showCustomAmountModal}
|
|
|
|
/>
|
2023-11-15 04:40:22 -04:00
|
|
|
<Button onPress={handleShareButtonPressed} title={loc.receive.details_share} />
|
2021-04-21 12:50:51 +02:00
|
|
|
</BlueCard>
|
2020-07-22 23:28:12 -04:00
|
|
|
</View>
|
|
|
|
{renderCustomAmountModal()}
|
|
|
|
</ScrollView>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const obtainWalletAddress = useCallback(async () => {
|
2020-04-20 00:03:36 -04:00
|
|
|
console.log('receive/details - componentDidMount');
|
|
|
|
wallet.setUserHasSavedExport(true);
|
2020-10-24 13:20:59 -04:00
|
|
|
await saveToDisk();
|
2021-04-17 13:43:39 -04:00
|
|
|
let newAddress;
|
|
|
|
if (address) {
|
|
|
|
setAddressBIP21Encoded(address);
|
2024-03-27 00:08:29 -04:00
|
|
|
await Notifications.tryToObtainPermissions(receiveAddressButton);
|
2021-04-17 13:43:39 -04:00
|
|
|
Notifications.majorTomToGroundControl([address], [], []);
|
2021-07-14 14:40:19 +02:00
|
|
|
} else {
|
2020-04-20 00:03:36 -04:00
|
|
|
if (wallet.chain === Chain.ONCHAIN) {
|
2019-12-24 21:35:47 -06:00
|
|
|
try {
|
2021-08-24 01:00:57 -04:00
|
|
|
if (!isElectrumDisabled) newAddress = await Promise.race([wallet.getAddressAsync(), sleep(1000)]);
|
2019-12-24 21:35:47 -06:00
|
|
|
} catch (_) {}
|
2021-04-19 19:25:20 +03:00
|
|
|
if (newAddress === undefined) {
|
2019-12-24 21:35:47 -06:00
|
|
|
// either sleep expired or getAddressAsync threw an exception
|
|
|
|
console.warn('either sleep expired or getAddressAsync threw an exception');
|
2021-04-17 13:43:39 -04:00
|
|
|
newAddress = wallet._getExternalAddressByIndex(wallet.getNextFreeAddressIndex());
|
2019-12-24 21:35:47 -06:00
|
|
|
} else {
|
2020-10-24 13:20:59 -04:00
|
|
|
saveToDisk(); // caching whatever getAddressAsync() generated internally
|
2019-09-30 18:13:22 -04:00
|
|
|
}
|
2020-04-20 00:03:36 -04:00
|
|
|
} else if (wallet.chain === Chain.OFFCHAIN) {
|
2019-12-24 21:35:47 -06:00
|
|
|
try {
|
2020-10-24 13:20:59 -04:00
|
|
|
await Promise.race([wallet.getAddressAsync(), sleep(1000)]);
|
2021-04-17 13:43:39 -04:00
|
|
|
newAddress = wallet.getAddress();
|
2019-12-24 21:35:47 -06:00
|
|
|
} catch (_) {}
|
2021-04-19 19:25:20 +03:00
|
|
|
if (newAddress === undefined) {
|
2019-12-24 21:35:47 -06:00
|
|
|
// either sleep expired or getAddressAsync threw an exception
|
|
|
|
console.warn('either sleep expired or getAddressAsync threw an exception');
|
2021-04-17 13:43:39 -04:00
|
|
|
newAddress = wallet.getAddress();
|
2019-12-24 21:35:47 -06:00
|
|
|
} else {
|
2020-10-24 13:20:59 -04:00
|
|
|
saveToDisk(); // caching whatever getAddressAsync() generated internally
|
2019-09-11 22:05:01 -04:00
|
|
|
}
|
2019-05-02 16:33:03 -04:00
|
|
|
}
|
2021-04-17 13:43:39 -04:00
|
|
|
setAddressBIP21Encoded(newAddress);
|
2024-03-27 00:08:29 -04:00
|
|
|
await Notifications.tryToObtainPermissions(receiveAddressButton);
|
2021-04-17 13:43:39 -04:00
|
|
|
Notifications.majorTomToGroundControl([newAddress], [], []);
|
2018-07-22 15:49:59 +01:00
|
|
|
}
|
2020-10-24 13:20:59 -04:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
}, []);
|
2020-07-23 14:45:15 -04:00
|
|
|
|
2023-07-25 14:50:04 +01:00
|
|
|
const setAddressBIP21Encoded = addr => {
|
|
|
|
const newBip21encoded = DeeplinkSchemaMatch.bip21encode(addr);
|
|
|
|
setParams({ address: addr });
|
|
|
|
setBip21encoded(newBip21encoded);
|
2020-07-22 23:28:12 -04:00
|
|
|
setShowAddress(true);
|
2020-07-23 14:45:15 -04:00
|
|
|
};
|
2019-12-24 21:35:47 -06:00
|
|
|
|
2020-07-22 23:28:12 -04:00
|
|
|
useFocusEffect(
|
|
|
|
useCallback(() => {
|
|
|
|
const task = InteractionManager.runAfterInteractions(async () => {
|
|
|
|
if (wallet) {
|
2024-03-24 16:29:58 -04:00
|
|
|
obtainWalletAddress();
|
2021-09-24 23:36:08 -04:00
|
|
|
} else if (!wallet && address) {
|
|
|
|
setAddressBIP21Encoded(address);
|
2020-07-22 23:28:12 -04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return () => {
|
|
|
|
task.cancel();
|
|
|
|
};
|
2021-04-17 13:43:39 -04:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
}, [wallet]),
|
2020-07-22 23:28:12 -04:00
|
|
|
);
|
2018-01-30 22:42:38 +00:00
|
|
|
|
2020-04-20 00:03:36 -04:00
|
|
|
const dismissCustomAmountModal = () => {
|
|
|
|
Keyboard.dismiss();
|
|
|
|
setIsCustomModalVisible(false);
|
|
|
|
};
|
2019-02-27 20:29:13 -05:00
|
|
|
|
2020-04-20 00:03:36 -04:00
|
|
|
const showCustomAmountModal = () => {
|
|
|
|
setIsCustomModalVisible(true);
|
|
|
|
};
|
|
|
|
|
|
|
|
const createCustomAmountAddress = () => {
|
|
|
|
setIsCustom(true);
|
|
|
|
setIsCustomModalVisible(false);
|
2020-06-09 15:08:18 +01:00
|
|
|
let amount = customAmount;
|
|
|
|
switch (customUnit) {
|
|
|
|
case BitcoinUnit.BTC:
|
|
|
|
// nop
|
|
|
|
break;
|
|
|
|
case BitcoinUnit.SATS:
|
2024-01-28 11:11:08 -04:00
|
|
|
amount = satoshiToBTC(customAmount);
|
2020-06-09 15:08:18 +01:00
|
|
|
break;
|
|
|
|
case BitcoinUnit.LOCAL_CURRENCY:
|
2021-02-25 19:13:34 +03:00
|
|
|
if (AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]) {
|
2020-06-09 15:08:18 +01:00
|
|
|
// cache hit! we reuse old value that supposedly doesnt have rounding errors
|
2024-01-28 11:11:08 -04:00
|
|
|
amount = satoshiToBTC(AmountInput.conversionCache[amount + BitcoinUnit.LOCAL_CURRENCY]);
|
2020-06-09 15:08:18 +01:00
|
|
|
} else {
|
2024-01-28 11:11:08 -04:00
|
|
|
amount = fiatToBTC(customAmount);
|
2020-06-09 15:08:18 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-11-08 10:31:25 -05:00
|
|
|
setBip21encoded(DeeplinkSchemaMatch.bip21encode(address, { amount, label: customLabel }));
|
2020-07-23 09:28:22 -04:00
|
|
|
setShowAddress(true);
|
2020-04-20 00:03:36 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const renderCustomAmountModal = () => {
|
2019-12-15 01:10:22 -05:00
|
|
|
return (
|
2020-11-17 11:43:38 +03:00
|
|
|
<BottomModal isVisible={isCustomModalVisible} onClose={dismissCustomAmountModal}>
|
2021-02-24 20:56:06 -05:00
|
|
|
<KeyboardAvoidingView enabled={!Platform.isPad} behavior={Platform.OS === 'ios' ? 'position' : null}>
|
2022-01-28 15:32:09 +03:00
|
|
|
<View style={[styles.modalContent, stylesHook.modalContent]}>
|
2021-02-25 19:13:34 +03:00
|
|
|
<AmountInput unit={customUnit} amount={customAmount || ''} onChangeText={setCustomAmount} onAmountUnitChange={setCustomUnit} />
|
2022-01-28 15:32:09 +03:00
|
|
|
<View style={[styles.customAmount, stylesHook.customAmount]}>
|
2019-12-15 01:10:22 -05:00
|
|
|
<TextInput
|
2020-04-20 00:03:36 -04:00
|
|
|
onChangeText={setCustomLabel}
|
2020-06-09 11:55:19 -04:00
|
|
|
placeholderTextColor="#81868e"
|
2020-07-20 16:38:46 +03:00
|
|
|
placeholder={loc.receive.details_label}
|
2020-04-20 00:03:36 -04:00
|
|
|
value={customLabel || ''}
|
2019-12-15 01:10:22 -05:00
|
|
|
numberOfLines={1}
|
2022-01-28 15:32:09 +03:00
|
|
|
style={[styles.customAmountText, stylesHook.customAmountText]}
|
2021-01-22 23:50:52 -05:00
|
|
|
testID="CustomAmountDescription"
|
2019-12-15 01:10:22 -05:00
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
<BlueSpacing20 />
|
|
|
|
<View>
|
2023-11-15 04:40:22 -04:00
|
|
|
<Button
|
2021-01-22 23:50:52 -05:00
|
|
|
testID="CustomAmountSaveButton"
|
2022-01-28 15:32:09 +03:00
|
|
|
style={[styles.modalButton, stylesHook.modalButton]}
|
2021-01-22 23:50:52 -05:00
|
|
|
title={loc.receive.details_create}
|
|
|
|
onPress={createCustomAmountAddress}
|
|
|
|
/>
|
2019-12-15 01:10:22 -05:00
|
|
|
<BlueSpacing20 />
|
|
|
|
</View>
|
|
|
|
<BlueSpacing20 />
|
|
|
|
</View>
|
|
|
|
</KeyboardAvoidingView>
|
2020-11-17 11:43:38 +03:00
|
|
|
</BottomModal>
|
2019-12-15 01:10:22 -05:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-04-20 00:03:36 -04:00
|
|
|
const handleShareButtonPressed = () => {
|
2020-07-06 17:53:08 -04:00
|
|
|
Share.open({ message: bip21encoded }).catch(error => console.log(error));
|
2019-12-15 01:10:22 -05:00
|
|
|
};
|
|
|
|
|
2020-06-09 15:08:18 +01:00
|
|
|
/**
|
|
|
|
* @returns {string} BTC amount, accounting for current `customUnit` and `customUnit`
|
|
|
|
*/
|
|
|
|
const getDisplayAmount = () => {
|
2021-11-07 13:50:09 -05:00
|
|
|
if (Number(customAmount) > 0) {
|
|
|
|
switch (customUnit) {
|
|
|
|
case BitcoinUnit.BTC:
|
|
|
|
return customAmount + ' BTC';
|
|
|
|
case BitcoinUnit.SATS:
|
2024-01-28 11:11:08 -04:00
|
|
|
return satoshiToBTC(customAmount) + ' BTC';
|
2021-11-07 13:50:09 -05:00
|
|
|
case BitcoinUnit.LOCAL_CURRENCY:
|
2024-01-28 11:11:08 -04:00
|
|
|
return fiatToBTC(customAmount) + ' BTC';
|
2021-11-07 13:50:09 -05:00
|
|
|
}
|
|
|
|
return customAmount + ' ' + customUnit;
|
|
|
|
} else {
|
|
|
|
return null;
|
2020-06-09 15:08:18 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-04-20 00:03:36 -04:00
|
|
|
return (
|
2022-01-28 15:32:09 +03:00
|
|
|
<View style={[styles.root, stylesHook.root]}>
|
2021-01-18 22:40:11 -05:00
|
|
|
{address !== undefined && showAddress && (
|
2024-04-02 21:50:19 -04:00
|
|
|
<HandOffComponent title={loc.send.details_address} type={HandOffComponent.activityTypes.ReceiveOnchain} userInfo={{ address }} />
|
2020-04-20 00:03:36 -04:00
|
|
|
)}
|
2021-08-26 22:38:30 +01:00
|
|
|
{showConfirmedBalance ? renderConfirmedBalance() : null}
|
|
|
|
{showPendingBalance ? renderPendingBalance() : null}
|
|
|
|
{showAddress ? renderReceiveDetails() : null}
|
|
|
|
{!showAddress && !showPendingBalance && !showConfirmedBalance ? <BlueLoading /> : null}
|
2020-07-15 13:32:59 -04:00
|
|
|
</View>
|
2020-04-20 00:03:36 -04:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-08-29 12:28:56 -04:00
|
|
|
const styles = StyleSheet.create({
|
2022-01-28 15:32:09 +03:00
|
|
|
modalContent: {
|
|
|
|
padding: 22,
|
|
|
|
justifyContent: 'center',
|
|
|
|
alignItems: 'center',
|
|
|
|
borderTopLeftRadius: 16,
|
|
|
|
borderTopRightRadius: 16,
|
|
|
|
minHeight: 350,
|
|
|
|
height: 350,
|
|
|
|
},
|
|
|
|
customAmount: {
|
|
|
|
flexDirection: 'row',
|
|
|
|
borderWidth: 1.0,
|
|
|
|
borderBottomWidth: 0.5,
|
|
|
|
minHeight: 44,
|
|
|
|
height: 44,
|
|
|
|
marginHorizontal: 20,
|
|
|
|
alignItems: 'center',
|
|
|
|
marginVertical: 8,
|
|
|
|
borderRadius: 4,
|
|
|
|
},
|
|
|
|
root: {
|
|
|
|
flexGrow: 1,
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
},
|
|
|
|
scrollBody: {
|
|
|
|
marginTop: 32,
|
|
|
|
flexGrow: 1,
|
|
|
|
alignItems: 'center',
|
|
|
|
paddingHorizontal: 16,
|
|
|
|
},
|
|
|
|
share: {
|
|
|
|
justifyContent: 'flex-end',
|
|
|
|
paddingVertical: 16,
|
|
|
|
alignItems: 'center',
|
|
|
|
marginBottom: 8,
|
|
|
|
},
|
|
|
|
link: {
|
|
|
|
marginVertical: 16,
|
|
|
|
paddingHorizontal: 32,
|
|
|
|
},
|
|
|
|
amount: {
|
|
|
|
fontWeight: '600',
|
|
|
|
fontSize: 36,
|
|
|
|
textAlign: 'center',
|
|
|
|
},
|
|
|
|
label: {
|
|
|
|
fontWeight: '600',
|
|
|
|
textAlign: 'center',
|
|
|
|
paddingBottom: 24,
|
|
|
|
},
|
|
|
|
modalButton: {
|
|
|
|
paddingVertical: 14,
|
|
|
|
paddingHorizontal: 70,
|
|
|
|
maxWidth: '80%',
|
|
|
|
borderRadius: 50,
|
|
|
|
fontWeight: '700',
|
|
|
|
},
|
|
|
|
customAmountText: {
|
|
|
|
flex: 1,
|
|
|
|
marginHorizontal: 8,
|
|
|
|
minHeight: 33,
|
|
|
|
},
|
2021-08-29 12:28:56 -04:00
|
|
|
});
|
|
|
|
|
2020-04-20 00:03:36 -04:00
|
|
|
export default ReceiveDetails;
|