mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-13 19:16:52 +01:00
REF: Reuse existing component
This commit is contained in:
parent
34db010bde
commit
7f97c340f8
6 changed files with 181 additions and 170 deletions
|
@ -1,7 +1,7 @@
|
|||
import React, { useCallback, useMemo } from 'react';
|
||||
import React, { useCallback, useMemo, forwardRef } from 'react';
|
||||
import { Image, Keyboard, Platform, StyleSheet, Text } from 'react-native';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import ToolTipMenu from './TooltipMenu';
|
||||
import ToolTipMenu, { ToolTipMenuRef } from './TooltipMenu';
|
||||
import loc from '../loc';
|
||||
import { showFilePickerAndReadFile, showImagePickerAndReadImage } from '../blue_modules/fs';
|
||||
import presentAlert from './Alert';
|
||||
|
@ -10,145 +10,160 @@ import RNQRGenerator from 'rn-qr-generator';
|
|||
import { CommonToolTipActions } from '../typings/CommonToolTipActions';
|
||||
import { useSettings } from '../hooks/context/useSettings';
|
||||
import { useExtendedNavigation } from '../hooks/useExtendedNavigation';
|
||||
import { isDesktop } from '../blue_modules/environment';
|
||||
|
||||
interface AddressInputScanButtonProps {
|
||||
isLoading: boolean;
|
||||
isLoading?: boolean;
|
||||
onChangeText: (text: string) => void;
|
||||
type?: 'default' | 'link';
|
||||
testID?: string;
|
||||
beforePress?: () => Promise<void> | void;
|
||||
}
|
||||
|
||||
export const AddressInputScanButton = ({
|
||||
isLoading,
|
||||
export const AddressInputScanButton = forwardRef<ToolTipMenuRef, AddressInputScanButtonProps>(
|
||||
({ isLoading, onChangeText, type = 'default', testID = 'BlueAddressInputScanQrButton', beforePress }, ref) => {
|
||||
const { colors } = useTheme();
|
||||
const { isClipboardGetContentEnabled } = useSettings();
|
||||
|
||||
onChangeText,
|
||||
}: AddressInputScanButtonProps) => {
|
||||
const { colors } = useTheme();
|
||||
const { isClipboardGetContentEnabled } = useSettings();
|
||||
|
||||
const navigation = useExtendedNavigation();
|
||||
const stylesHook = StyleSheet.create({
|
||||
scan: {
|
||||
backgroundColor: colors.scanLabel,
|
||||
},
|
||||
scanText: {
|
||||
color: colors.inverseForegroundColor,
|
||||
},
|
||||
});
|
||||
|
||||
const toolTipOnPress = useCallback(async () => {
|
||||
Keyboard.dismiss();
|
||||
navigation.navigate('ScanQRCode', {
|
||||
showFileImportButton: true,
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
const actions = useMemo(() => {
|
||||
const availableActions = [
|
||||
CommonToolTipActions.ScanQR,
|
||||
CommonToolTipActions.ChoosePhoto,
|
||||
CommonToolTipActions.ImportFile,
|
||||
{
|
||||
...CommonToolTipActions.PasteFromClipboard,
|
||||
hidden: !isClipboardGetContentEnabled,
|
||||
const navigation = useExtendedNavigation();
|
||||
const stylesHook = StyleSheet.create({
|
||||
scan: {
|
||||
backgroundColor: colors.scanLabel,
|
||||
},
|
||||
];
|
||||
scanText: {
|
||||
color: colors.inverseForegroundColor,
|
||||
},
|
||||
});
|
||||
|
||||
return availableActions;
|
||||
}, [isClipboardGetContentEnabled]);
|
||||
|
||||
const onMenuItemPressed = useCallback(
|
||||
async (action: string) => {
|
||||
switch (action) {
|
||||
case CommonToolTipActions.ScanQR.id:
|
||||
navigation.navigate('ScanQRCode', {
|
||||
showFileImportButton: true,
|
||||
});
|
||||
break;
|
||||
case CommonToolTipActions.PasteFromClipboard.id:
|
||||
try {
|
||||
let getImage: string | null = null;
|
||||
let hasImage = false;
|
||||
if (Platform.OS === 'android') {
|
||||
hasImage = true;
|
||||
} else {
|
||||
hasImage = await Clipboard.hasImage();
|
||||
}
|
||||
|
||||
if (hasImage) {
|
||||
getImage = await Clipboard.getImage();
|
||||
}
|
||||
|
||||
if (getImage) {
|
||||
try {
|
||||
const base64Data = getImage.replace(/^data:image\/(png|jpeg|jpg);base64,/, '');
|
||||
const values = await RNQRGenerator.detect({
|
||||
base64: base64Data,
|
||||
});
|
||||
|
||||
if (values && values.values.length > 0) {
|
||||
onChangeText(values.values[0]);
|
||||
} else {
|
||||
presentAlert({ message: loc.send.qr_error_no_qrcode });
|
||||
}
|
||||
} catch (error) {
|
||||
presentAlert({ message: (error as Error).message });
|
||||
}
|
||||
} else {
|
||||
const clipboardText = await Clipboard.getString();
|
||||
onChangeText(clipboardText);
|
||||
}
|
||||
} catch (error) {
|
||||
presentAlert({ message: (error as Error).message });
|
||||
}
|
||||
break;
|
||||
case CommonToolTipActions.ChoosePhoto.id:
|
||||
showImagePickerAndReadImage()
|
||||
.then(value => {
|
||||
if (value) {
|
||||
onChangeText(value);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
presentAlert({ message: error.message });
|
||||
});
|
||||
break;
|
||||
case CommonToolTipActions.ImportFile.id:
|
||||
showFilePickerAndReadFile()
|
||||
.then(value => {
|
||||
if (value.data) {
|
||||
onChangeText(value.data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
presentAlert({ message: error.message });
|
||||
});
|
||||
break;
|
||||
const toolTipOnPress = useCallback(async () => {
|
||||
if (beforePress) {
|
||||
await beforePress();
|
||||
}
|
||||
Keyboard.dismiss();
|
||||
},
|
||||
[navigation, onChangeText],
|
||||
);
|
||||
navigation.navigate('ScanQRCode', {
|
||||
showFileImportButton: true,
|
||||
});
|
||||
}, [navigation, beforePress]);
|
||||
|
||||
const buttonStyle = useMemo(() => [styles.scan, stylesHook.scan], [stylesHook.scan]);
|
||||
const actions = useMemo(() => {
|
||||
const availableActions = [
|
||||
CommonToolTipActions.ScanQR,
|
||||
CommonToolTipActions.ChoosePhoto,
|
||||
CommonToolTipActions.ImportFile,
|
||||
{
|
||||
...CommonToolTipActions.PasteFromClipboard,
|
||||
hidden: !isClipboardGetContentEnabled,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ToolTipMenu
|
||||
actions={actions}
|
||||
isButton
|
||||
onPressMenuItem={onMenuItemPressed}
|
||||
testID="BlueAddressInputScanQrButton"
|
||||
disabled={isLoading}
|
||||
onPress={toolTipOnPress}
|
||||
buttonStyle={buttonStyle}
|
||||
accessibilityLabel={loc.send.details_scan}
|
||||
accessibilityHint={loc.send.details_scan_hint}
|
||||
>
|
||||
<Image source={require('../img/scan-white.png')} accessible={false} />
|
||||
<Text style={[styles.scanText, stylesHook.scanText]} accessible={false}>
|
||||
{loc.send.details_scan}
|
||||
</Text>
|
||||
</ToolTipMenu>
|
||||
);
|
||||
};
|
||||
return availableActions;
|
||||
}, [isClipboardGetContentEnabled]);
|
||||
|
||||
const onMenuItemPressed = useCallback(
|
||||
async (action: string) => {
|
||||
switch (action) {
|
||||
case CommonToolTipActions.ScanQR.id:
|
||||
navigation.navigate('ScanQRCode', {
|
||||
showFileImportButton: true,
|
||||
});
|
||||
break;
|
||||
case CommonToolTipActions.PasteFromClipboard.id:
|
||||
try {
|
||||
let getImage: string | null = null;
|
||||
let hasImage = false;
|
||||
if (Platform.OS === 'android') {
|
||||
hasImage = true;
|
||||
} else {
|
||||
hasImage = await Clipboard.hasImage();
|
||||
}
|
||||
|
||||
if (hasImage) {
|
||||
getImage = await Clipboard.getImage();
|
||||
}
|
||||
|
||||
if (getImage) {
|
||||
try {
|
||||
const base64Data = getImage.replace(/^data:image\/(png|jpeg|jpg);base64,/, '');
|
||||
const values = await RNQRGenerator.detect({
|
||||
base64: base64Data,
|
||||
});
|
||||
|
||||
if (values && values.values.length > 0) {
|
||||
onChangeText(values.values[0]);
|
||||
} else {
|
||||
presentAlert({ message: loc.send.qr_error_no_qrcode });
|
||||
}
|
||||
} catch (error) {
|
||||
presentAlert({ message: (error as Error).message });
|
||||
}
|
||||
} else {
|
||||
const clipboardText = await Clipboard.getString();
|
||||
onChangeText(clipboardText);
|
||||
}
|
||||
} catch (error) {
|
||||
presentAlert({ message: (error as Error).message });
|
||||
}
|
||||
break;
|
||||
case CommonToolTipActions.ChoosePhoto.id:
|
||||
showImagePickerAndReadImage()
|
||||
.then(value => {
|
||||
if (value) {
|
||||
onChangeText(value);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
presentAlert({ message: error.message });
|
||||
});
|
||||
break;
|
||||
case CommonToolTipActions.ImportFile.id:
|
||||
showFilePickerAndReadFile()
|
||||
.then(value => {
|
||||
if (value.data) {
|
||||
onChangeText(value.data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
presentAlert({ message: error.message });
|
||||
});
|
||||
break;
|
||||
}
|
||||
Keyboard.dismiss();
|
||||
},
|
||||
[navigation, onChangeText],
|
||||
);
|
||||
|
||||
const buttonStyle = useMemo(() => [styles.scan, stylesHook.scan], [stylesHook.scan]);
|
||||
|
||||
return (
|
||||
<ToolTipMenu
|
||||
ref={ref}
|
||||
actions={actions}
|
||||
isButton
|
||||
onPressMenuItem={onMenuItemPressed}
|
||||
testID={testID}
|
||||
disabled={isLoading}
|
||||
onPress={toolTipOnPress}
|
||||
isMenuPrimaryAction={isDesktop}
|
||||
buttonStyle={type === 'default' ? buttonStyle : undefined}
|
||||
accessibilityLabel={loc.send.details_scan}
|
||||
accessibilityHint={loc.send.details_scan_hint}
|
||||
>
|
||||
{type === 'default' ? (
|
||||
<>
|
||||
<Image source={require('../img/scan-white.png')} accessible={false} />
|
||||
<Text style={[styles.scanText, stylesHook.scanText]} accessible={false}>
|
||||
{loc.send.details_scan}
|
||||
</Text>
|
||||
</>
|
||||
) : (
|
||||
<Text style={[styles.linkText, { color: colors.foregroundColor }]}>{loc.wallets.import_scan_qr}</Text>
|
||||
)}
|
||||
</ToolTipMenu>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
AddressInputScanButton.displayName = 'AddressInputScanButton';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
scan: {
|
||||
|
@ -164,4 +179,8 @@ const styles = StyleSheet.create({
|
|||
scanText: {
|
||||
marginLeft: 4,
|
||||
},
|
||||
linkText: {
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import React, { Ref, useCallback, useMemo } from 'react';
|
||||
import React, { forwardRef, useCallback, useMemo } from 'react';
|
||||
import { Platform, Pressable, TouchableOpacity } from 'react-native';
|
||||
import { MenuView, MenuAction, NativeActionEvent } from '@react-native-menu/menu';
|
||||
import { ContextMenuView, RenderItem, OnPressMenuItemEventObject, IconConfig, MenuElementConfig } from 'react-native-ios-context-menu';
|
||||
import { ToolTipMenuProps, Action } from './types';
|
||||
import { useSettings } from '../hooks/context/useSettings';
|
||||
|
||||
const ToolTipMenu = React.memo((props: ToolTipMenuProps, ref?: Ref<any>) => {
|
||||
export type ToolTipMenuRef = {
|
||||
// Add any methods you want to expose via ref
|
||||
showMenu?: () => void;
|
||||
hideMenu?: () => void;
|
||||
};
|
||||
|
||||
const ToolTipMenu = forwardRef<ToolTipMenuRef, ToolTipMenuProps>((props, _ref) => {
|
||||
const {
|
||||
title = '',
|
||||
isMenuPrimaryAction = false,
|
||||
|
|
|
@ -366,4 +366,4 @@ export const TransactionListItem: React.FC<TransactionListItemProps> = React.mem
|
|||
</ToolTipMenu>
|
||||
);
|
||||
},
|
||||
);
|
||||
);
|
||||
|
|
|
@ -3,7 +3,7 @@ import { RouteProp, useRoute } from '@react-navigation/native';
|
|||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { Keyboard, Platform, ScrollView, StyleSheet, TouchableWithoutFeedback, View, TouchableOpacity, Image } from 'react-native';
|
||||
import { disallowScreenshot } from 'react-native-screen-capture';
|
||||
import { BlueButtonLink, BlueFormLabel, BlueFormMultiInput, BlueSpacing20 } from '../../BlueComponents';
|
||||
import { BlueFormLabel, BlueFormMultiInput, BlueSpacing20 } from '../../BlueComponents';
|
||||
import Button from '../../components/Button';
|
||||
import {
|
||||
DoneAndDismissKeyboardInputAccessory,
|
||||
|
@ -19,6 +19,7 @@ import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
|||
import { AddWalletStackParamList } from '../../navigation/AddWalletStack';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { AddressInputScanButton } from '../../components/AddressInputScanButton';
|
||||
|
||||
type RouteProps = RouteProp<AddWalletStackParamList, 'ImportWallet'>;
|
||||
type NavigationProps = NativeStackNavigationProp<AddWalletStackParamList, 'ImportWallet'>;
|
||||
|
@ -109,12 +110,6 @@ const ImportWallet = () => {
|
|||
[importMnemonic],
|
||||
);
|
||||
|
||||
const importScan = useCallback(async () => {
|
||||
navigation.navigate('ScanQRCode', {
|
||||
showFileImportButton: true,
|
||||
});
|
||||
}, [navigation]);
|
||||
|
||||
useEffect(() => {
|
||||
const data = route.params?.onBarScanned;
|
||||
if (data) {
|
||||
|
@ -199,7 +194,7 @@ const ImportWallet = () => {
|
|||
<>
|
||||
<Button disabled={importText.trim().length === 0} title={loc.wallets.import_do_import} testID="DoImport" onPress={handleImport} />
|
||||
<BlueSpacing20 />
|
||||
<BlueButtonLink title={loc.wallets.import_scan_qr} onPress={importScan} testID="ScanImport" />
|
||||
<AddressInputScanButton type="link" onChangeText={setImportText} />
|
||||
</>
|
||||
</View>
|
||||
</>
|
||||
|
|
|
@ -18,15 +18,7 @@ import {
|
|||
import { Badge, Icon } from '@rneui/themed';
|
||||
import { isDesktop } from '../../blue_modules/environment';
|
||||
import { encodeUR } from '../../blue_modules/ur';
|
||||
import {
|
||||
BlueButtonLink,
|
||||
BlueCard,
|
||||
BlueFormMultiInput,
|
||||
BlueLoading,
|
||||
BlueSpacing10,
|
||||
BlueSpacing20,
|
||||
BlueTextCentered,
|
||||
} from '../../BlueComponents';
|
||||
import { BlueCard, BlueFormMultiInput, BlueLoading, BlueSpacing10, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
|
||||
import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import BottomModal, { BottomModalHandle } from '../../components/BottomModal';
|
||||
|
@ -45,13 +37,14 @@ import { disallowScreenshot } from 'react-native-screen-capture';
|
|||
import loc from '../../loc';
|
||||
import ActionSheet from '../ActionSheet';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import ToolTipMenu from '../../components/TooltipMenu';
|
||||
import ToolTipMenu, { ToolTipMenuRef } from '../../components/TooltipMenu';
|
||||
import { CommonToolTipActions } from '../../typings/CommonToolTipActions';
|
||||
import { useSettings } from '../../hooks/context/useSettings';
|
||||
import { ViewEditMultisigCosignersStackParamList } from '../../navigation/ViewEditMultisigCosignersStack';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
import { TWallet } from '../../class/wallets/types';
|
||||
import { AddressInputScanButton } from '../../components/AddressInputScanButton';
|
||||
|
||||
type RouteParams = RouteProp<ViewEditMultisigCosignersStackParamList, 'ViewEditMultisigCosigners'>;
|
||||
type NavigationProp = NativeStackNavigationProp<ViewEditMultisigCosignersStackParamList, 'ViewEditMultisigCosigners'>;
|
||||
|
@ -62,8 +55,8 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
|||
const { wallets, setWalletsWithNewOrder } = useStorage();
|
||||
const { isBiometricUseCapableAndEnabled } = useBiometrics();
|
||||
const { isElectrumDisabled, isPrivacyBlurEnabled } = useSettings();
|
||||
const { navigate, dispatch, setParams, setOptions } = useExtendedNavigation<NavigationProp>();
|
||||
const openScannerButtonRef = useRef();
|
||||
const { dispatch, setParams, setOptions } = useExtendedNavigation<NavigationProp>();
|
||||
const openScannerButtonRef = useRef<ToolTipMenuRef>(null);
|
||||
const route = useRoute<RouteParams>();
|
||||
const { walletID } = route.params;
|
||||
const w = useRef(wallets.find(wallet => wallet.getID() === walletID));
|
||||
|
@ -516,11 +509,6 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const scanOrOpenFile = async () => {
|
||||
await provideMnemonicsModalRef.current?.dismiss();
|
||||
navigate('ScanQRCode', { showFileImportButton: true });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const scannedData = route.params.onBarScanned;
|
||||
if (scannedData) {
|
||||
|
@ -573,11 +561,14 @@ const ViewEditMultisigCosigners: React.FC = () => {
|
|||
|
||||
{!isLoading && (
|
||||
<>
|
||||
<BlueButtonLink
|
||||
<AddressInputScanButton
|
||||
ref={openScannerButtonRef}
|
||||
disabled={isLoading}
|
||||
onPress={scanOrOpenFile}
|
||||
title={loc.wallets.import_scan_qr}
|
||||
beforePress={async () => {
|
||||
await provideMnemonicsModalRef.current?.dismiss();
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
type="link"
|
||||
onChangeText={setImportText}
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
</>
|
||||
|
|
|
@ -17,7 +17,7 @@ import { Icon } from '@rneui/themed';
|
|||
import A from '../../blue_modules/analytics';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
|
||||
import { encodeUR } from '../../blue_modules/ur';
|
||||
import { BlueButtonLink, BlueFormMultiInput, BlueSpacing10, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
|
||||
import { BlueFormMultiInput, BlueSpacing10, BlueSpacing20, BlueTextCentered } from '../../BlueComponents';
|
||||
import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../class';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import BottomModal from '../../components/BottomModal';
|
||||
|
@ -44,6 +44,7 @@ import MultipleStepsListItem, {
|
|||
MultipleStepsListItemButtonType,
|
||||
MultipleStepsListItemDashType,
|
||||
} from '../../components/MultipleStepsListItem';
|
||||
import { AddressInputScanButton } from '../../components/AddressInputScanButton';
|
||||
|
||||
const staticCache = {};
|
||||
|
||||
|
@ -433,11 +434,6 @@ const WalletsAddMultisigStep2 = () => {
|
|||
[cosigners, format, getXpubCacheForMnemonics, tryUsingXpub],
|
||||
);
|
||||
|
||||
const scanOrOpenFile = async () => {
|
||||
await provideMnemonicsModalRef.current.dismiss();
|
||||
navigation.navigate('ScanQRCode', { showFileImportButton: true });
|
||||
};
|
||||
|
||||
const utilizeMnemonicPhrase = useCallback(async () => {
|
||||
try {
|
||||
await provideMnemonicsModalRef.current.dismiss();
|
||||
|
@ -659,12 +655,16 @@ const WalletsAddMultisigStep2 = () => {
|
|||
onPress={utilizeMnemonicPhrase}
|
||||
/>
|
||||
<View style={styles.height16} />
|
||||
<BlueButtonLink
|
||||
|
||||
<AddressInputScanButton
|
||||
beforePress={async () => {
|
||||
await provideMnemonicsModalRef.current.dismiss();
|
||||
}}
|
||||
onBarScanned={onBarScanned}
|
||||
testID="ScanOrOpenFile"
|
||||
type="link"
|
||||
ref={openScannerButton}
|
||||
disabled={isLoading}
|
||||
onPress={scanOrOpenFile}
|
||||
title={loc.wallets.import_scan_qr}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
|
Loading…
Add table
Reference in a new issue