mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 15:04:50 +01:00
feat: new wallet export screen
This commit is contained in:
parent
5500856abf
commit
32e0ecf3c9
5 changed files with 282 additions and 141 deletions
64
components/SeedWords.tsx
Normal file
64
components/SeedWords.tsx
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { I18nManager, StyleSheet, Text, View } from 'react-native';
|
||||||
|
|
||||||
|
import { useTheme } from './themes';
|
||||||
|
|
||||||
|
const SeedWords = ({ seed }: { seed: string }) => {
|
||||||
|
const words = seed.split(/\s/);
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
const stylesHook = StyleSheet.create({
|
||||||
|
word: {
|
||||||
|
backgroundColor: colors.inputBackgroundColor,
|
||||||
|
},
|
||||||
|
wortText: {
|
||||||
|
color: colors.labelText,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.secret}>
|
||||||
|
{words.map((secret, index) => {
|
||||||
|
const text = `${index + 1}. ${secret} `;
|
||||||
|
return (
|
||||||
|
<View style={[styles.word, stylesHook.word]} key={index}>
|
||||||
|
<Text style={[styles.wortText, stylesHook.wortText]} textBreakStrategy="simple">
|
||||||
|
{text}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Text style={styles.hiddenText} testID="Secret">
|
||||||
|
{seed}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
word: {
|
||||||
|
marginRight: 8,
|
||||||
|
marginBottom: 8,
|
||||||
|
paddingTop: 6,
|
||||||
|
paddingBottom: 6,
|
||||||
|
paddingLeft: 8,
|
||||||
|
paddingRight: 8,
|
||||||
|
borderRadius: 4,
|
||||||
|
},
|
||||||
|
wortText: {
|
||||||
|
fontWeight: 'bold',
|
||||||
|
textAlign: 'left',
|
||||||
|
fontSize: 17,
|
||||||
|
},
|
||||||
|
secret: {
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
|
||||||
|
},
|
||||||
|
hiddenText: {
|
||||||
|
height: 0,
|
||||||
|
width: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default SeedWords;
|
|
@ -481,7 +481,14 @@
|
||||||
"select_wallet": "Select Wallet",
|
"select_wallet": "Select Wallet",
|
||||||
"xpub_copiedToClipboard": "Copied to clipboard.",
|
"xpub_copiedToClipboard": "Copied to clipboard.",
|
||||||
"pull_to_refresh": "Pull to Refresh",
|
"pull_to_refresh": "Pull to Refresh",
|
||||||
"warning_do_not_disclose": "Warning! Do not disclose.",
|
"warning_do_not_disclose": "Never share the information below",
|
||||||
|
"scan_import": "Scan this QR code to import your wallet in another application.",
|
||||||
|
"write_down_header": "Create a manual backup",
|
||||||
|
"write_down": "Write down and securely store these words. Use them to restore your wallet at a later time.",
|
||||||
|
"wallet_type_this": "This wallet type is {type}.",
|
||||||
|
"share_number": "Share {number}",
|
||||||
|
"copy_ln_url": "Copy and securely store this URL to restore your wallet at a later time.",
|
||||||
|
"copy_ln_public": "Copy and securely store this information to restore your wallet at a later time.",
|
||||||
"add_ln_wallet_first": "You must first add a Lightning wallet.",
|
"add_ln_wallet_first": "You must first add a Lightning wallet.",
|
||||||
"identity_pubkey": "Identity Pubkey",
|
"identity_pubkey": "Identity Pubkey",
|
||||||
"xpub_title": "Wallet XPUB",
|
"xpub_title": "Wallet XPUB",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
|
|
||||||
import navigationStyle from '../components/navigationStyle';
|
import navigationStyle from '../components/navigationStyle';
|
||||||
import { useTheme } from '../components/themes';
|
import { useTheme } from '../components/themes';
|
||||||
|
|
|
@ -11,13 +11,15 @@ import loc from '../../loc';
|
||||||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||||
import { isDesktop } from '../../blue_modules/environment';
|
import { isDesktop } from '../../blue_modules/environment';
|
||||||
|
|
||||||
|
import SeedWords from '../../components/SeedWords';
|
||||||
|
|
||||||
type RouteProps = RouteProp<AddWalletStackParamList, 'PleaseBackup'>;
|
type RouteProps = RouteProp<AddWalletStackParamList, 'PleaseBackup'>;
|
||||||
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'PleaseBackup'>;
|
type NavigationProp = NativeStackNavigationProp<AddWalletStackParamList, 'PleaseBackup'>;
|
||||||
|
|
||||||
const PleaseBackup: React.FC = () => {
|
const PleaseBackup: React.FC = () => {
|
||||||
const { wallets } = useStorage();
|
const { wallets } = useStorage();
|
||||||
const { walletID } = useRoute<RouteProps>().params;
|
const { walletID } = useRoute<RouteProps>().params;
|
||||||
const wallet = wallets.find(w => w.getID() === walletID);
|
const wallet = wallets.find(w => w.getID() === walletID)!;
|
||||||
const navigation = useNavigation<NavigationProp>();
|
const navigation = useNavigation<NavigationProp>();
|
||||||
const { isPrivacyBlurEnabled } = useSettings();
|
const { isPrivacyBlurEnabled } = useSettings();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
@ -26,12 +28,6 @@ const PleaseBackup: React.FC = () => {
|
||||||
flex: {
|
flex: {
|
||||||
backgroundColor: colors.elevated,
|
backgroundColor: colors.elevated,
|
||||||
},
|
},
|
||||||
word: {
|
|
||||||
backgroundColor: colors.inputBackgroundColor,
|
|
||||||
},
|
|
||||||
wortText: {
|
|
||||||
color: colors.labelText,
|
|
||||||
},
|
|
||||||
pleaseText: {
|
pleaseText: {
|
||||||
color: colors.foregroundColor,
|
color: colors.foregroundColor,
|
||||||
},
|
},
|
||||||
|
@ -53,26 +49,6 @@ const PleaseBackup: React.FC = () => {
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const renderSecret = () => {
|
|
||||||
const component: JSX.Element[] = [];
|
|
||||||
const entries = wallet?.getSecret().split(/\s/).entries();
|
|
||||||
if (entries) {
|
|
||||||
for (const [index, secret] of entries) {
|
|
||||||
if (secret) {
|
|
||||||
const text = `${index + 1}. ${secret} `;
|
|
||||||
component.push(
|
|
||||||
<View style={[styles.word, stylesHook.word]} key={index}>
|
|
||||||
<Text style={[styles.wortText, stylesHook.wortText]} textBreakStrategy="simple">
|
|
||||||
{text}
|
|
||||||
</Text>
|
|
||||||
</View>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return component;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={styles.root}
|
style={styles.root}
|
||||||
|
@ -85,7 +61,7 @@ const PleaseBackup: React.FC = () => {
|
||||||
<Text style={[styles.pleaseText, stylesHook.pleaseText]}>{loc.pleasebackup.text}</Text>
|
<Text style={[styles.pleaseText, stylesHook.pleaseText]}>{loc.pleasebackup.text}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.list}>
|
<View style={styles.list}>
|
||||||
<View style={styles.secret}>{renderSecret()}</View>
|
<SeedWords seed={wallet.getSecret() ?? ''} />
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.bottom}>
|
<View style={styles.bottom}>
|
||||||
<Button testID="PleasebackupOk" onPress={handleBackButton} title={loc.pleasebackup.ok} />
|
<Button testID="PleasebackupOk" onPress={handleBackButton} title={loc.pleasebackup.ok} />
|
||||||
|
@ -102,26 +78,13 @@ const styles = StyleSheet.create({
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
},
|
},
|
||||||
word: {
|
|
||||||
marginRight: 8,
|
|
||||||
marginBottom: 8,
|
|
||||||
paddingTop: 6,
|
|
||||||
paddingBottom: 6,
|
|
||||||
paddingLeft: 8,
|
|
||||||
paddingRight: 8,
|
|
||||||
borderRadius: 4,
|
|
||||||
},
|
|
||||||
wortText: {
|
|
||||||
fontWeight: 'bold',
|
|
||||||
textAlign: 'left',
|
|
||||||
fontSize: 17,
|
|
||||||
},
|
|
||||||
please: {
|
please: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
flexGrow: 8,
|
flexGrow: 8,
|
||||||
|
marginTop: 14,
|
||||||
paddingHorizontal: 16,
|
paddingHorizontal: 16,
|
||||||
},
|
},
|
||||||
bottom: {
|
bottom: {
|
||||||
|
@ -135,12 +98,6 @@ const styles = StyleSheet.create({
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
|
||||||
},
|
},
|
||||||
secret: {
|
|
||||||
flexWrap: 'wrap',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginTop: 14,
|
|
||||||
flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default PleaseBackup;
|
export default PleaseBackup;
|
||||||
|
|
|
@ -1,60 +1,105 @@
|
||||||
import { useFocusEffect, useNavigation, useRoute, RouteProp } from '@react-navigation/native';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import Clipboard from '@react-native-clipboard/clipboard';
|
||||||
import { ActivityIndicator, InteractionManager, ScrollView, StyleSheet, View, LayoutChangeEvent } from 'react-native';
|
import { RouteProp, useFocusEffect, useNavigation, useRoute } from '@react-navigation/native';
|
||||||
import { BlueCard, BlueSpacing20, BlueText } from '../../BlueComponents';
|
import { Icon } from '@rneui/themed';
|
||||||
import { LegacyWallet, LightningCustodianWallet, SegwitBech32Wallet, SegwitP2SHWallet, WatchOnlyWallet } from '../../class';
|
import { ActivityIndicator, InteractionManager, LayoutChangeEvent, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||||
import CopyTextToClipboard from '../../components/CopyTextToClipboard';
|
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||||
|
|
||||||
|
import { validateMnemonic } from '../../blue_modules/bip39';
|
||||||
|
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||||
|
import { BlueText } from '../../BlueComponents';
|
||||||
|
import { LightningCustodianWallet, WatchOnlyWallet } from '../../class';
|
||||||
import HandOffComponent from '../../components/HandOffComponent';
|
import HandOffComponent from '../../components/HandOffComponent';
|
||||||
import QRCodeComponent from '../../components/QRCodeComponent';
|
import QRCodeComponent from '../../components/QRCodeComponent';
|
||||||
|
import SeedWords from '../../components/SeedWords';
|
||||||
import { useTheme } from '../../components/themes';
|
import { useTheme } from '../../components/themes';
|
||||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
|
||||||
import loc from '../../loc';
|
|
||||||
import { useStorage } from '../../hooks/context/useStorage';
|
|
||||||
import { HandOffActivityType } from '../../components/types';
|
import { HandOffActivityType } from '../../components/types';
|
||||||
import { WalletExportStackParamList } from '../../navigation/WalletExportStack';
|
|
||||||
import useAppState from '../../hooks/useAppState';
|
|
||||||
import { useSettings } from '../../hooks/context/useSettings';
|
import { useSettings } from '../../hooks/context/useSettings';
|
||||||
import { isDesktop } from '../../blue_modules/environment';
|
import { isDesktop } from '../../blue_modules/environment';
|
||||||
|
import { useStorage } from '../../hooks/context/useStorage';
|
||||||
|
import useAppState from '../../hooks/useAppState';
|
||||||
|
import loc from '../../loc';
|
||||||
|
import { WalletExportStackParamList } from '../../navigation/WalletExportStack';
|
||||||
|
|
||||||
type RouteProps = RouteProp<WalletExportStackParamList, 'WalletExport'>;
|
type RouteProps = RouteProp<WalletExportStackParamList, 'WalletExport'>;
|
||||||
|
|
||||||
|
const HORIZONTAL_PADDING = 20;
|
||||||
|
|
||||||
|
const CopyBox: React.FC<{ text: string; onPress: () => void }> = ({ text, onPress }) => {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
const stylesHook = StyleSheet.create({
|
||||||
|
copyRoot: { backgroundColor: colors.lightBorder },
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={onPress} style={[styles.copyRoot, stylesHook.copyRoot]}>
|
||||||
|
<View style={styles.copyLeft}>
|
||||||
|
<BlueText textBreakStrategy="balanced" style={styles.copyText}>
|
||||||
|
{text}
|
||||||
|
</BlueText>
|
||||||
|
</View>
|
||||||
|
<View style={styles.copyRight}>
|
||||||
|
<Icon name="copy" type="font-awesome-5" color={colors.foregroundColor} />
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DoNotDisclose: React.FC = () => {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[styles.warningBox, { backgroundColor: colors.changeText }]}>
|
||||||
|
<Icon type="font-awesome-5" name="exclamation-circle" color="white" />
|
||||||
|
<BlueText style={styles.warning}>{loc.wallets.warning_do_not_disclose}</BlueText>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const WalletExport: React.FC = () => {
|
const WalletExport: React.FC = () => {
|
||||||
const { wallets, saveToDisk } = useStorage();
|
const { wallets, saveToDisk } = useStorage();
|
||||||
const { walletID } = useRoute<RouteProps>().params;
|
const { walletID } = useRoute<RouteProps>().params;
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const { goBack } = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { isPrivacyBlurEnabled } = useSettings();
|
const { isPrivacyBlurEnabled } = useSettings();
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
const wallet = wallets.find(w => w.getID() === walletID);
|
const wallet = wallets.find(w => w.getID() === walletID)!;
|
||||||
const [qrCodeSize, setQRCodeSize] = useState(90);
|
const [qrCodeSize, setQRCodeSize] = useState(90);
|
||||||
const { currentAppState, previousAppState } = useAppState();
|
const { currentAppState, previousAppState } = useAppState();
|
||||||
const stylesHook = StyleSheet.create({
|
const stylesHook = StyleSheet.create({
|
||||||
root: {
|
root: { backgroundColor: colors.elevated },
|
||||||
backgroundColor: colors.elevated,
|
|
||||||
},
|
|
||||||
type: { color: colors.foregroundColor },
|
|
||||||
secret: { color: colors.foregroundColor },
|
|
||||||
warning: { color: colors.failedColor },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const secrets: string[] = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const secret = wallet.getSecret();
|
||||||
|
return typeof secret === 'string' ? [secret] : Array.isArray(secret) ? secret : [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get wallet secret:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}, [wallet]);
|
||||||
|
|
||||||
|
const secretIsMnemonic: boolean = useMemo(() => {
|
||||||
|
return validateMnemonic(wallet.getSecret());
|
||||||
|
}, [wallet]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoading && previousAppState === 'active' && currentAppState !== 'active') {
|
if (!isLoading && previousAppState === 'active' && currentAppState !== 'active') {
|
||||||
const timer = setTimeout(() => goBack(), 500);
|
const timer = setTimeout(() => navigation.goBack(), 500);
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}
|
}
|
||||||
}, [currentAppState, previousAppState, goBack, isLoading]);
|
}, [currentAppState, previousAppState, navigation, isLoading]);
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
if (!isDesktop) disallowScreenshot(isPrivacyBlurEnabled);
|
||||||
const task = InteractionManager.runAfterInteractions(async () => {
|
const task = InteractionManager.runAfterInteractions(async () => {
|
||||||
if (wallet) {
|
if (!wallet.getUserHasSavedExport()) {
|
||||||
if (!wallet.getUserHasSavedExport()) {
|
wallet.setUserHasSavedExport(true);
|
||||||
wallet.setUserHasSavedExport(true);
|
saveToDisk();
|
||||||
saveToDisk();
|
|
||||||
}
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
|
setIsLoading(false);
|
||||||
});
|
});
|
||||||
return () => {
|
return () => {
|
||||||
if (!isDesktop) disallowScreenshot(false);
|
if (!isDesktop) disallowScreenshot(false);
|
||||||
|
@ -63,21 +108,66 @@ const WalletExport: React.FC = () => {
|
||||||
}, [isPrivacyBlurEnabled, wallet, saveToDisk]),
|
}, [isPrivacyBlurEnabled, wallet, saveToDisk]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const secrets: string[] = (() => {
|
const onLayout = useCallback((e: LayoutChangeEvent) => {
|
||||||
try {
|
|
||||||
const secret = wallet?.getSecret();
|
|
||||||
if (!secret) return [];
|
|
||||||
return typeof secret === 'string' ? [secret] : Array.isArray(secret) ? secret : [];
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to get wallet secret:', error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
const onLayout = (e: LayoutChangeEvent) => {
|
|
||||||
const { height, width } = e.nativeEvent.layout;
|
const { height, width } = e.nativeEvent.layout;
|
||||||
setQRCodeSize(height > width ? width - 40 : width / 1.8);
|
setQRCodeSize(height > width ? width - HORIZONTAL_PADDING * 2 : width / 1.8);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
|
const handleCopy = useCallback(() => {
|
||||||
|
Clipboard.setString(wallet.getSecret());
|
||||||
|
triggerHapticFeedback(HapticFeedbackTypes.Selection);
|
||||||
|
}, [wallet]);
|
||||||
|
|
||||||
|
const Scroll = useCallback(
|
||||||
|
// eslint-disable-next-line react/no-unused-prop-types
|
||||||
|
({ children }: { children: React.ReactNode | React.ReactNodeArray }) => (
|
||||||
|
<ScrollView
|
||||||
|
automaticallyAdjustContentInsets
|
||||||
|
contentInsetAdjustmentBehavior="automatic"
|
||||||
|
style={stylesHook.root}
|
||||||
|
contentContainerStyle={styles.scrollViewContent}
|
||||||
|
onLayout={onLayout}
|
||||||
|
testID="WalletExportScroll"
|
||||||
|
centerContent={isLoading}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ScrollView>
|
||||||
|
),
|
||||||
|
[isLoading, onLayout, stylesHook.root],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<Scroll>
|
||||||
|
<ActivityIndicator />
|
||||||
|
</Scroll>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for SLIP39
|
||||||
|
if (secrets.length !== 1) {
|
||||||
|
return (
|
||||||
|
<Scroll>
|
||||||
|
<DoNotDisclose />
|
||||||
|
|
||||||
|
<View>
|
||||||
|
<BlueText style={styles.manualText}>{loc.wallets.write_down_header}</BlueText>
|
||||||
|
<BlueText style={styles.writeText}>{loc.wallets.write_down}</BlueText>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{secrets.map((secret, index) => (
|
||||||
|
<React.Fragment key={secret}>
|
||||||
|
<BlueText style={styles.scanText}>{loc.formatString(loc.wallets.share_number, { number: index + 1 })}</BlueText>
|
||||||
|
<SeedWords seed={secret} />
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<BlueText style={styles.typeText}>{loc.formatString(loc.wallets.wallet_type_this, { type: wallet.typeReadable })}</BlueText>
|
||||||
|
</Scroll>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const secret = secrets[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView
|
<ScrollView
|
||||||
|
@ -89,69 +179,92 @@ const WalletExport: React.FC = () => {
|
||||||
testID="WalletExportScroll"
|
testID="WalletExportScroll"
|
||||||
centerContent={isLoading}
|
centerContent={isLoading}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{wallet.type !== WatchOnlyWallet.type && <DoNotDisclose />}
|
||||||
<ActivityIndicator />
|
|
||||||
) : (
|
|
||||||
wallet && (
|
|
||||||
<>
|
|
||||||
<View>
|
|
||||||
<BlueText style={[styles.type, stylesHook.type]}>{wallet.typeReadable}</BlueText>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{[LegacyWallet.type, SegwitBech32Wallet.type, SegwitP2SHWallet.type].includes(wallet.type) && (
|
<BlueText style={styles.scanText}>{loc.wallets.scan_import}</BlueText>
|
||||||
<BlueCard>
|
|
||||||
<BlueText>{wallet.getAddress()}</BlueText>
|
<QRCodeComponent isMenuAvailable={false} value={secret} size={qrCodeSize} logoSize={70} />
|
||||||
</BlueCard>
|
|
||||||
)}
|
{/* Do not allow to copy mnemonic */}
|
||||||
<BlueSpacing20 />
|
{secretIsMnemonic ? (
|
||||||
{secrets.map(secret => (
|
<>
|
||||||
<React.Fragment key={secret}>
|
<View>
|
||||||
<QRCodeComponent isMenuAvailable={false} value={secret} size={qrCodeSize} logoSize={70} />
|
<BlueText style={styles.manualText}>{loc.wallets.write_down_header}</BlueText>
|
||||||
{wallet.type !== WatchOnlyWallet.type && (
|
<BlueText style={styles.writeText}>{loc.wallets.write_down}</BlueText>
|
||||||
<>
|
</View>
|
||||||
<BlueSpacing20 />
|
<SeedWords seed={secret} />
|
||||||
<BlueText style={stylesHook.warning}>{loc.wallets.warning_do_not_disclose}</BlueText>
|
</>
|
||||||
</>
|
) : (
|
||||||
)}
|
<>
|
||||||
<BlueSpacing20 />
|
<BlueText style={styles.writeText}>
|
||||||
{wallet.type === LightningCustodianWallet.type || wallet.type === WatchOnlyWallet.type ? (
|
{wallet.type === LightningCustodianWallet.type ? loc.wallets.copy_ln_url : loc.wallets.copy_ln_public}
|
||||||
<CopyTextToClipboard text={secret} />
|
</BlueText>
|
||||||
) : (
|
<CopyBox text={secret} onPress={handleCopy} />
|
||||||
<BlueText style={[styles.secret, styles.secretWritingDirection, stylesHook.secret]} testID="Secret">
|
</>
|
||||||
{secret}
|
|
||||||
</BlueText>
|
|
||||||
)}
|
|
||||||
{wallet.type === WatchOnlyWallet.type && (
|
|
||||||
<HandOffComponent title={loc.wallets.xpub_title} type={HandOffActivityType.Xpub} userInfo={{ xpub: secret }} />
|
|
||||||
)}
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{wallet.type === WatchOnlyWallet.type && (
|
||||||
|
<HandOffComponent title={loc.wallets.xpub_title} type={HandOffActivityType.Xpub} userInfo={{ xpub: secret }} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<BlueText style={styles.typeText}>{loc.formatString(loc.wallets.wallet_type_this, { type: wallet.typeReadable })}</BlueText>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
scrollViewContent: {
|
scrollViewContent: {
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
|
gap: 32,
|
||||||
|
paddingHorizontal: HORIZONTAL_PADDING,
|
||||||
|
paddingTop: 10,
|
||||||
|
paddingBottom: 20,
|
||||||
},
|
},
|
||||||
type: {
|
warningBox: {
|
||||||
fontSize: 17,
|
alignItems: 'center',
|
||||||
fontWeight: '700',
|
padding: 12,
|
||||||
},
|
borderRadius: 10,
|
||||||
secret: {
|
|
||||||
alignSelf: 'stretch',
|
alignSelf: 'stretch',
|
||||||
textAlign: 'center',
|
flexDirection: 'row',
|
||||||
paddingHorizontal: 16,
|
gap: 8,
|
||||||
fontSize: 16,
|
|
||||||
lineHeight: 24,
|
|
||||||
},
|
},
|
||||||
secretWritingDirection: {
|
warning: {
|
||||||
writingDirection: 'ltr',
|
fontSize: 20,
|
||||||
|
color: 'white',
|
||||||
|
},
|
||||||
|
scanText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 20,
|
||||||
|
},
|
||||||
|
writeText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 17,
|
||||||
|
},
|
||||||
|
manualText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 20,
|
||||||
|
marginBottom: 10,
|
||||||
|
},
|
||||||
|
typeText: {
|
||||||
|
textAlign: 'center',
|
||||||
|
fontSize: 17,
|
||||||
|
color: 'grey',
|
||||||
|
},
|
||||||
|
copyRoot: {
|
||||||
|
padding: 10,
|
||||||
|
borderRadius: 8,
|
||||||
|
flexDirection: 'row',
|
||||||
|
},
|
||||||
|
copyLeft: {
|
||||||
|
flexShrink: 1,
|
||||||
|
},
|
||||||
|
copyRight: {
|
||||||
|
justifyContent: 'center',
|
||||||
|
marginHorizontal: 8,
|
||||||
|
},
|
||||||
|
copyText: {
|
||||||
|
fontSize: 17,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue