mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 18:00:17 +01:00
349 lines
11 KiB
TypeScript
349 lines
11 KiB
TypeScript
import React, { useState, useEffect, useRef, useContext, useCallback, useMemo } from 'react';
|
|
import { Image, Text, TouchableOpacity, View, I18nManager, StyleSheet } from 'react-native';
|
|
import Clipboard from '@react-native-clipboard/clipboard';
|
|
import LinearGradient from 'react-native-linear-gradient';
|
|
import { AbstractWallet, HDSegwitBech32Wallet, LightningCustodianWallet, LightningLdkWallet, MultisigHDWallet } from '../class';
|
|
import { BitcoinUnit } from '../models/bitcoinUnits';
|
|
import WalletGradient from '../class/wallet-gradient';
|
|
import Biometric from '../class/biometrics';
|
|
import loc, { formatBalance } from '../loc';
|
|
import { BlueStorageContext } from '../blue_modules/storage-context';
|
|
import ToolTipMenu from './TooltipMenu';
|
|
import { BluePrivateBalance } from '../BlueComponents';
|
|
import { FiatUnit } from '../models/fiatUnit';
|
|
|
|
interface TransactionsNavigationHeaderProps {
|
|
wallet: AbstractWallet;
|
|
onWalletUnitChange?: (wallet: any) => void;
|
|
navigation: {
|
|
navigate: (route: string, params?: any) => void;
|
|
goBack: () => void;
|
|
};
|
|
onManageFundsPressed?: (id: string) => void; // Add a type definition for this prop
|
|
actionKeys: {
|
|
CopyToClipboard: 'copyToClipboard';
|
|
WalletBalanceVisibility: 'walletBalanceVisibility';
|
|
Refill: 'refill';
|
|
RefillWithExternalWallet: 'qrcode';
|
|
};
|
|
}
|
|
|
|
const TransactionsNavigationHeader: React.FC<TransactionsNavigationHeaderProps> = ({
|
|
// @ts-ignore: Ugh
|
|
wallet: initialWallet,
|
|
// @ts-ignore: Ugh
|
|
onWalletUnitChange,
|
|
// @ts-ignore: Ugh
|
|
navigation,
|
|
// @ts-ignore: Ugh
|
|
onManageFundsPressed,
|
|
}) => {
|
|
const [wallet, setWallet] = useState(initialWallet);
|
|
const [allowOnchainAddress, setAllowOnchainAddress] = useState(false);
|
|
|
|
const { preferredFiatCurrency, saveToDisk } = useContext(BlueStorageContext);
|
|
const menuRef = useRef(null);
|
|
|
|
const verifyIfWalletAllowsOnchainAddress = useCallback(() => {
|
|
if (wallet.type === LightningCustodianWallet.type) {
|
|
wallet
|
|
.allowOnchainAddress()
|
|
.then((value: boolean) => setAllowOnchainAddress(value))
|
|
.catch((e: Error) => {
|
|
console.log('This Lndhub wallet does not have an onchain address API.');
|
|
setAllowOnchainAddress(false);
|
|
});
|
|
}
|
|
}, [wallet]);
|
|
|
|
useEffect(() => {
|
|
setWallet(initialWallet);
|
|
}, [initialWallet]);
|
|
|
|
useEffect(() => {
|
|
verifyIfWalletAllowsOnchainAddress();
|
|
}, [wallet, verifyIfWalletAllowsOnchainAddress]);
|
|
|
|
const handleCopyPress = () => {
|
|
const value = formatBalance(wallet.getBalance(), wallet.getPreferredBalanceUnit());
|
|
if (value) {
|
|
Clipboard.setString(value);
|
|
}
|
|
};
|
|
|
|
const updateWalletVisibility = (w: AbstractWallet, newHideBalance: boolean) => {
|
|
w.hideBalance = newHideBalance;
|
|
return w;
|
|
};
|
|
|
|
const handleBalanceVisibility = async () => {
|
|
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
|
|
|
|
if (isBiometricsEnabled && wallet.hideBalance) {
|
|
if (!(await Biometric.unlockWithBiometrics())) {
|
|
return navigation.goBack();
|
|
}
|
|
}
|
|
|
|
const updatedWallet = updateWalletVisibility(wallet, !wallet.hideBalance);
|
|
setWallet(updatedWallet);
|
|
saveToDisk();
|
|
};
|
|
|
|
const updateWalletWithNewUnit = (w: AbstractWallet, newPreferredUnit: BitcoinUnit) => {
|
|
w.preferredBalanceUnit = newPreferredUnit;
|
|
return w;
|
|
};
|
|
|
|
const changeWalletBalanceUnit = () => {
|
|
// @ts-ignore: Ugh
|
|
menuRef.current?.dismissMenu();
|
|
let newWalletPreferredUnit = wallet.getPreferredBalanceUnit();
|
|
|
|
if (newWalletPreferredUnit === BitcoinUnit.BTC) {
|
|
newWalletPreferredUnit = BitcoinUnit.SATS;
|
|
} else if (newWalletPreferredUnit === BitcoinUnit.SATS) {
|
|
newWalletPreferredUnit = BitcoinUnit.LOCAL_CURRENCY;
|
|
} else {
|
|
newWalletPreferredUnit = BitcoinUnit.BTC;
|
|
}
|
|
|
|
const updatedWallet = updateWalletWithNewUnit(wallet, newWalletPreferredUnit);
|
|
setWallet(updatedWallet);
|
|
onWalletUnitChange?.(updatedWallet);
|
|
};
|
|
|
|
const handleManageFundsPressed = () => {
|
|
onManageFundsPressed?.(actionKeys.Refill);
|
|
};
|
|
|
|
const handleOnPaymentCodeButtonPressed = () => {
|
|
navigation.navigate('PaymentCodeRoot', {
|
|
screen: 'PaymentCode',
|
|
params: { paymentCode: (wallet as HDSegwitBech32Wallet).getBIP47PaymentCode() },
|
|
});
|
|
};
|
|
|
|
const onPressMenuItem = (id: string) => {
|
|
if (id === 'walletBalanceVisibility') {
|
|
handleBalanceVisibility();
|
|
} else if (id === 'copyToClipboard') {
|
|
handleCopyPress();
|
|
}
|
|
};
|
|
|
|
const balance = useMemo(() => {
|
|
const hideBalance = wallet.hideBalance;
|
|
const balanceUnit = wallet.getPreferredBalanceUnit();
|
|
const balanceFormatted = formatBalance(wallet.getBalance(), balanceUnit, true);
|
|
return !hideBalance && balanceFormatted?.toString();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [wallet.hideBalance, wallet.getPreferredBalanceUnit()]);
|
|
|
|
return (
|
|
<LinearGradient
|
|
colors={WalletGradient.gradientsFor(wallet.type)}
|
|
style={styles.lineaderGradient}
|
|
// @ts-ignore: Ugh
|
|
{...WalletGradient.linearGradientProps(wallet.type)}
|
|
>
|
|
<Image
|
|
source={(() => {
|
|
switch (wallet.type) {
|
|
case LightningLdkWallet.type:
|
|
case LightningCustodianWallet.type:
|
|
return I18nManager.isRTL ? require('../img/lnd-shape-rtl.png') : require('../img/lnd-shape.png');
|
|
case MultisigHDWallet.type:
|
|
return I18nManager.isRTL ? require('../img/vault-shape-rtl.png') : require('../img/vault-shape.png');
|
|
default:
|
|
return I18nManager.isRTL ? require('../img/btc-shape-rtl.png') : require('../img/btc-shape.png');
|
|
}
|
|
})()}
|
|
style={styles.chainIcon}
|
|
/>
|
|
|
|
<Text testID="WalletLabel" numberOfLines={1} style={styles.walletLabel}>
|
|
{wallet.getLabel()}
|
|
</Text>
|
|
<ToolTipMenu
|
|
onPress={changeWalletBalanceUnit}
|
|
ref={menuRef}
|
|
title={`${loc.wallets.balance} (${
|
|
wallet.getPreferredBalanceUnit() === BitcoinUnit.LOCAL_CURRENCY
|
|
? preferredFiatCurrency?.endPointKey ?? FiatUnit.USD
|
|
: wallet.getPreferredBalanceUnit()
|
|
})`}
|
|
onPressMenuItem={onPressMenuItem}
|
|
actions={
|
|
wallet.hideBalance
|
|
? [
|
|
{
|
|
id: 'walletBalanceVisibility',
|
|
text: loc.transactions.details_balance_show,
|
|
icon: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'eye',
|
|
},
|
|
},
|
|
]
|
|
: [
|
|
{
|
|
id: 'walletBalanceVisibility',
|
|
text: loc.transactions.details_balance_hide,
|
|
icon: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'eye.slash',
|
|
},
|
|
},
|
|
{
|
|
id: 'copyToClipboard',
|
|
text: loc.transactions.details_copy,
|
|
icon: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'doc.on.doc',
|
|
},
|
|
},
|
|
]
|
|
}
|
|
>
|
|
<View style={styles.walletBalance}>
|
|
{wallet.hideBalance ? (
|
|
<BluePrivateBalance />
|
|
) : (
|
|
<Text
|
|
testID="WalletBalance"
|
|
// @ts-ignore: Ugh
|
|
key={balance} // force component recreation on balance change. To fix right-to-left languages, like Farsi
|
|
numberOfLines={1}
|
|
adjustsFontSizeToFit
|
|
style={styles.walletBalance}
|
|
>
|
|
{balance}
|
|
</Text>
|
|
)}
|
|
</View>
|
|
</ToolTipMenu>
|
|
{wallet.type === LightningCustodianWallet.type && allowOnchainAddress && (
|
|
<ToolTipMenu
|
|
isMenuPrimaryAction
|
|
isButton
|
|
onPressMenuItem={handleManageFundsPressed}
|
|
actions={[
|
|
{
|
|
id: actionKeys.Refill,
|
|
text: loc.lnd.refill,
|
|
icon: actionIcons.Refill,
|
|
},
|
|
{
|
|
id: actionKeys.RefillWithExternalWallet,
|
|
text: loc.lnd.refill_external,
|
|
icon: actionIcons.RefillWithExternalWallet,
|
|
},
|
|
]}
|
|
buttonStyle={styles.manageFundsButton}
|
|
>
|
|
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
|
</ToolTipMenu>
|
|
)}
|
|
|
|
{wallet.allowBIP47() && wallet.isBIP47Enabled() && (
|
|
<TouchableOpacity accessibilityRole="button" onPress={handleOnPaymentCodeButtonPressed}>
|
|
<View style={styles.manageFundsButton}>
|
|
<Text style={styles.manageFundsButtonText}>{loc.bip47.payment_code}</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
)}
|
|
{wallet.type === LightningLdkWallet.type && (
|
|
<TouchableOpacity accessibilityRole="button" accessibilityLabel={loc.lnd.title} onPress={handleManageFundsPressed}>
|
|
<View style={styles.manageFundsButton}>
|
|
<Text style={styles.manageFundsButtonText}>{loc.lnd.title}</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
)}
|
|
{wallet.type === MultisigHDWallet.type && (
|
|
<TouchableOpacity accessibilityRole="button" onPress={handleManageFundsPressed}>
|
|
<View style={styles.manageFundsButton}>
|
|
<Text style={styles.manageFundsButtonText}>{loc.multisig.manage_keys}</Text>
|
|
</View>
|
|
</TouchableOpacity>
|
|
)}
|
|
</LinearGradient>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
lineaderGradient: {
|
|
padding: 15,
|
|
minHeight: 140,
|
|
justifyContent: 'center',
|
|
},
|
|
chainIcon: {
|
|
width: 99,
|
|
height: 94,
|
|
position: 'absolute',
|
|
bottom: 0,
|
|
right: 0,
|
|
},
|
|
walletLabel: {
|
|
backgroundColor: 'transparent',
|
|
fontSize: 19,
|
|
color: '#fff',
|
|
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
|
},
|
|
walletBalance: {
|
|
backgroundColor: 'transparent',
|
|
fontWeight: 'bold',
|
|
fontSize: 36,
|
|
color: '#fff',
|
|
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
|
},
|
|
manageFundsButton: {
|
|
marginTop: 14,
|
|
marginBottom: 10,
|
|
backgroundColor: 'rgba(255,255,255,0.2)',
|
|
borderRadius: 9,
|
|
minHeight: 39,
|
|
alignSelf: 'flex-start',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
manageFundsButtonText: {
|
|
fontWeight: '500',
|
|
fontSize: 14,
|
|
color: '#FFFFFF',
|
|
padding: 12,
|
|
},
|
|
});
|
|
|
|
export const actionKeys = {
|
|
CopyToClipboard: 'copyToClipboard',
|
|
WalletBalanceVisibility: 'walletBalanceVisibility',
|
|
Refill: 'refill',
|
|
RefillWithExternalWallet: 'qrcode',
|
|
};
|
|
|
|
export const actionIcons = {
|
|
Eye: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'eye',
|
|
},
|
|
EyeSlash: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'eye.slash',
|
|
},
|
|
Clipboard: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'doc.on.doc',
|
|
},
|
|
Refill: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'goforward.plus',
|
|
},
|
|
RefillWithExternalWallet: {
|
|
iconType: 'SYSTEM',
|
|
iconValue: 'qrcode',
|
|
},
|
|
};
|
|
|
|
export default TransactionsNavigationHeader;
|