Merge pull request #6660 from BlueWallet/ref

REF: Refactor Handoff component
This commit is contained in:
GLaDOS 2024-06-07 19:16:07 +00:00 committed by GitHub
commit 34fc84cbdc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 77 additions and 104 deletions

View file

@ -2,24 +2,24 @@ import React from 'react';
import DefaultPreference from 'react-native-default-preference'; import DefaultPreference from 'react-native-default-preference';
// @ts-ignore: react-native-handoff is not in the type definition // @ts-ignore: react-native-handoff is not in the type definition
import Handoff from 'react-native-handoff'; import Handoff from 'react-native-handoff';
import { useSettings } from '../hooks/context/useSettings';
import { GROUP_IO_BLUEWALLET } from '../blue_modules/currency'; import { GROUP_IO_BLUEWALLET } from '../blue_modules/currency';
import { BlueApp } from '../class'; import { BlueApp } from '../class';
import { useSettings } from '../hooks/context/useSettings'; import { HandOffComponentProps } from './types';
interface HandOffComponentProps { const HandOffComponent: React.FC<HandOffComponentProps> = props => {
url?: string; const { isHandOffUseEnabled } = useSettings();
title?: string;
type: (typeof HandOffComponent.activityTypes)[keyof typeof HandOffComponent.activityTypes];
userInfo?: object;
}
interface HandOffComponentWithActivityTypes extends React.FC<HandOffComponentProps> { if (process.env.NODE_ENV === 'development') {
activityTypes: { console.debug('HandOffComponent: props', props);
ReceiveOnchain: string; }
Xpub: string; if (isHandOffUseEnabled) {
ViewInBlockExplorer: string; return <Handoff {...props} />;
}; }
} return null;
};
const MemoizedHandOffComponent = React.memo(HandOffComponent);
export const setIsHandOffUseEnabled = async (value: boolean) => { export const setIsHandOffUseEnabled = async (value: boolean) => {
await DefaultPreference.setName(GROUP_IO_BLUEWALLET); await DefaultPreference.setName(GROUP_IO_BLUEWALLET);
@ -39,24 +39,4 @@ export const getIsHandOffUseEnabled = async (): Promise<boolean> => {
return false; return false;
}; };
const HandOffComponent: HandOffComponentWithActivityTypes = props => { export default MemoizedHandOffComponent;
const { isHandOffUseEnabled } = useSettings();
if (process.env.NODE_ENV === 'development') {
console.debug('HandOffComponent: props', props);
}
if (isHandOffUseEnabled) {
return <Handoff {...props} />;
}
return null;
};
const activityTypes = {
ReceiveOnchain: 'io.bluewallet.bluewallet.receiveonchain',
Xpub: 'io.bluewallet.bluewallet.xpub',
ViewInBlockExplorer: 'io.bluewallet.bluewallet.blockexplorer',
};
HandOffComponent.activityTypes = activityTypes;
export default HandOffComponent;

View file

@ -1,21 +1,8 @@
import React from 'react'; import React from 'react';
import { HandOffComponentProps } from './types';
interface HandOffComponentProps { const HandOffComponent: React.FC<HandOffComponentProps> = props => {
url?: string; console.debug('HandOffComponent: props', props);
title?: string;
type: (typeof HandOffComponent.activityTypes)[keyof typeof HandOffComponent.activityTypes];
userInfo?: object;
}
interface HandOffComponentWithActivityTypes extends React.FC<HandOffComponentProps> {
activityTypes: {
ReceiveOnchain: string;
Xpub: string;
ViewInBlockExplorer: string;
};
}
const HandOffComponent: HandOffComponentWithActivityTypes = props => {
return null; return null;
}; };
@ -25,12 +12,4 @@ export const getIsHandOffUseEnabled = async (): Promise<boolean> => {
return false; return false;
}; };
const activityTypes = {
ReceiveOnchain: 'io.bluewallet.bluewallet.receiveonchain',
Xpub: 'io.bluewallet.bluewallet.xpub',
ViewInBlockExplorer: 'io.bluewallet.bluewallet.blockexplorer',
};
HandOffComponent.activityTypes = activityTypes;
export default HandOffComponent; export default HandOffComponent;

View file

@ -1,11 +1,11 @@
import React, { useEffect } from 'react'; import React, { useEffect, useCallback } from 'react';
import { NativeEventEmitter, NativeModules } from 'react-native'; import { NativeEventEmitter, NativeModules } from 'react-native';
import * as NavigationService from '../NavigationService';
import HandOffComponent from './HandOffComponent.ios';
import { useStorage } from '../hooks/context/useStorage'; import { useStorage } from '../hooks/context/useStorage';
import { useExtendedNavigation } from '../hooks/useExtendedNavigation';
import { HandOffActivityType } from './types';
interface UserActivityData { interface UserActivityData {
activityType: keyof typeof HandOffComponent.activityTypes; activityType: HandOffActivityType;
userInfo: { userInfo: {
address?: string; address?: string;
xpub?: string; xpub?: string;
@ -15,28 +15,22 @@ interface UserActivityData {
const { EventEmitter } = NativeModules; const { EventEmitter } = NativeModules;
const eventEmitter = new NativeEventEmitter(EventEmitter); const eventEmitter = new NativeEventEmitter(EventEmitter);
const HandOffComponentListener: React.FC = () => { const HandOffComponentListener: React.FC = React.memo(() => {
const { walletsInitialized } = useStorage(); const { walletsInitialized } = useStorage();
const { navigate } = useExtendedNavigation();
useEffect(() => { const onUserActivityOpen = useCallback((data: UserActivityData) => {
if (!walletsInitialized) {
return;
}
const onUserActivityOpen = (data: UserActivityData) => {
switch (data.activityType) { switch (data.activityType) {
case HandOffComponent.activityTypes.ReceiveOnchain: case HandOffActivityType.ReceiveOnchain:
NavigationService.navigate('ReceiveDetailsRoot', { navigate('ReceiveDetailsRoot', {
// @ts-ignore: fix later
screen: 'ReceiveDetails', screen: 'ReceiveDetails',
params: { params: {
address: data.userInfo.address, address: data.userInfo.address,
}, },
}); });
break; break;
case HandOffComponent.activityTypes.Xpub: case HandOffActivityType.Xpub:
NavigationService.navigate('WalletXpubRoot', { navigate('WalletXpubRoot', {
// @ts-ignore: fix later
screen: 'WalletXpub', screen: 'WalletXpub',
params: { params: {
xpub: data.userInfo.xpub, xpub: data.userInfo.xpub,
@ -47,7 +41,13 @@ const HandOffComponentListener: React.FC = () => {
console.log(`Unhandled activity type: ${data.activityType}`); console.log(`Unhandled activity type: ${data.activityType}`);
break; break;
} }
}; // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (!walletsInitialized) {
return;
}
const addListeners = () => { const addListeners = () => {
const activitySubscription = eventEmitter.addListener('onUserActivityOpen', onUserActivityOpen); const activitySubscription = eventEmitter.addListener('onUserActivityOpen', onUserActivityOpen);
@ -65,9 +65,9 @@ const HandOffComponentListener: React.FC = () => {
return () => { return () => {
subscriptions.activitySubscription?.remove(); subscriptions.activitySubscription?.remove();
}; };
}, [walletsInitialized]); }, [walletsInitialized, onUserActivityOpen]);
return null; return null;
}; });
export default HandOffComponentListener; export default HandOffComponentListener;

View file

@ -34,3 +34,16 @@ export interface ToolTipMenuProps {
onMenuWillShow?: () => void; onMenuWillShow?: () => void;
onMenuWillHide?: () => void; onMenuWillHide?: () => void;
} }
export enum HandOffActivityType {
ReceiveOnchain = 'io.bluewallet.bluewallet.receiveonchain',
Xpub = 'io.bluewallet.bluewallet.xpub',
ViewInBlockExplorer = 'io.bluewallet.bluewallet.blockexplorer',
}
export interface HandOffComponentProps {
url?: string;
title?: string;
type: HandOffActivityType;
userInfo?: object;
}

View file

@ -32,6 +32,7 @@ import loc, { formatBalance } from '../../loc';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits'; import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import { SuccessView } from '../send/success'; import { SuccessView } from '../send/success';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
const ReceiveDetails = () => { const ReceiveDetails = () => {
const { walletID, address } = useRoute().params; const { walletID, address } = useRoute().params;
@ -426,7 +427,7 @@ const ReceiveDetails = () => {
return ( return (
<View style={[styles.root, stylesHook.root]}> <View style={[styles.root, stylesHook.root]}>
{address !== undefined && showAddress && ( {address !== undefined && showAddress && (
<HandOffComponent title={loc.send.details_address} type={HandOffComponent.activityTypes.ReceiveOnchain} userInfo={{ address }} /> <HandOffComponent title={loc.send.details_address} type={HandOffActivityType.ReceiveOnchain} userInfo={{ address }} />
)} )}
{showConfirmedBalance ? renderConfirmedBalance() : null} {showConfirmedBalance ? renderConfirmedBalance() : null}
{showPendingBalance ? renderPendingBalance() : null} {showPendingBalance ? renderPendingBalance() : null}

View file

@ -1,11 +1,10 @@
import React, { useEffect, useRef } from 'react';
import { useNavigation, useRoute } from '@react-navigation/native'; import { useNavigation, useRoute } from '@react-navigation/native';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
import LottieView from 'lottie-react-native'; import LottieView from 'lottie-react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { useEffect, useRef } from 'react';
import { StyleSheet, View } from 'react-native'; import { StyleSheet, View } from 'react-native';
import { Text } from 'react-native-elements'; import { Text } from 'react-native-elements';
import { BlueCard } from '../../BlueComponents'; import { BlueCard } from '../../BlueComponents';
import Button from '../../components/Button'; import Button from '../../components/Button';
import SafeArea from '../../components/SafeArea'; import SafeArea from '../../components/SafeArea';
@ -13,6 +12,7 @@ import { useTheme } from '../../components/themes';
import loc from '../../loc'; import loc from '../../loc';
import { BitcoinUnit } from '../../models/bitcoinUnits'; import { BitcoinUnit } from '../../models/bitcoinUnits';
import HandOffComponent from '../../components/HandOffComponent'; import HandOffComponent from '../../components/HandOffComponent';
import { HandOffActivityType } from '../../components/types';
const Success = () => { const Success = () => {
const pop = () => { const pop = () => {
@ -51,7 +51,7 @@ const Success = () => {
{txid && ( {txid && (
<HandOffComponent <HandOffComponent
title={loc.transactions.details_title} title={loc.transactions.details_title}
type={HandOffComponent.activityTypes.ViewInBlockExplorer} type={HandOffActivityType.ViewInBlockExplorer}
url={`https://mempool.space/tx/${txid}`} url={`https://mempool.space/tx/${txid}`}
/> />
)} )}

View file

@ -18,6 +18,7 @@ import loc from '../../loc';
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation'; import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList'; import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
interface TransactionDetailsProps { interface TransactionDetailsProps {
route: RouteProp<{ params: { hash: string; walletID: string } }, 'params'>; route: RouteProp<{ params: { hash: string; walletID: string } }, 'params'>;
@ -259,7 +260,7 @@ const TransactionDetails = () => {
<ScrollView style={styles.scroll} automaticallyAdjustContentInsets contentInsetAdjustmentBehavior="automatic"> <ScrollView style={styles.scroll} automaticallyAdjustContentInsets contentInsetAdjustmentBehavior="automatic">
<HandOffComponent <HandOffComponent
title={loc.transactions.details_title} title={loc.transactions.details_title}
type={HandOffComponent.activityTypes.ViewInBlockExplorer} type={HandOffActivityType.ViewInBlockExplorer}
url={`https://mempool.space/tx/${tx.hash}`} url={`https://mempool.space/tx/${tx.hash}`}
/> />
<BlueCard> <BlueCard>

View file

@ -18,6 +18,7 @@ import { useTheme } from '../../components/themes';
import loc, { formatBalanceWithoutSuffix } from '../../loc'; import loc, { formatBalanceWithoutSuffix } from '../../loc';
import { BitcoinUnit } from '../../models/bitcoinUnits'; import { BitcoinUnit } from '../../models/bitcoinUnits';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
import HeaderRightButton from '../../components/HeaderRightButton'; import HeaderRightButton from '../../components/HeaderRightButton';
enum ButtonStatus { enum ButtonStatus {
@ -476,7 +477,7 @@ const TransactionStatus = () => {
<SafeArea> <SafeArea>
<HandOffComponent <HandOffComponent
title={loc.transactions.details_title} title={loc.transactions.details_title}
type={HandOffComponent.activityTypes.ViewInBlockExplorer} type={HandOffActivityType.ViewInBlockExplorer}
url={`https://mempool.space/tx/${tx.hash}`} url={`https://mempool.space/tx/${tx.hash}`}
/> />

View file

@ -11,6 +11,7 @@ import { useTheme } from '../../components/themes';
import usePrivacy from '../../hooks/usePrivacy'; import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc'; import loc from '../../loc';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
const WalletExport = () => { const WalletExport = () => {
const { wallets, saveToDisk } = useStorage(); const { wallets, saveToDisk } = useStorage();
@ -115,11 +116,7 @@ const WalletExport = () => {
</BlueText> </BlueText>
)} )}
{wallet.type === WatchOnlyWallet.type && ( {wallet.type === WatchOnlyWallet.type && (
<HandOffComponent <HandOffComponent title={loc.wallets.xpub_title} type={HandOffActivityType.Xpub} userInfo={{ xpub: wallet.getSecret() }} />
title={loc.wallets.xpub_title}
type={HandOffComponent.activityTypes.Xpub}
userInfo={{ xpub: wallet.getSecret() }}
/>
)} )}
</React.Fragment> </React.Fragment>
))} ))}

View file

@ -12,6 +12,7 @@ import usePrivacy from '../../hooks/usePrivacy';
import loc from '../../loc'; import loc from '../../loc';
import { styles, useDynamicStyles } from './xpub.styles'; import { styles, useDynamicStyles } from './xpub.styles';
import { useStorage } from '../../hooks/context/useStorage'; import { useStorage } from '../../hooks/context/useStorage';
import { HandOffActivityType } from '../../components/types';
type WalletXpubRouteProp = RouteProp<{ params: { walletID: string; xpub: string } }, 'params'>; type WalletXpubRouteProp = RouteProp<{ params: { walletID: string; xpub: string } }, 'params'>;
export type RootStackParamList = { export type RootStackParamList = {
@ -94,7 +95,7 @@ const WalletXpub: React.FC = () => {
<BlueSpacing20 /> <BlueSpacing20 />
{xPubText && <CopyTextToClipboard text={xPubText} />} {xPubText && <CopyTextToClipboard text={xPubText} />}
</View> </View>
<HandOffComponent title={loc.wallets.xpub_title} type={HandOffComponent.activityTypes.Xpub} userInfo={{ xpub: xPubText }} /> <HandOffComponent title={loc.wallets.xpub_title} type={HandOffActivityType.Xpub} userInfo={{ xpub: xPubText }} />
<View style={styles.share}> <View style={styles.share}>
<Button onPress={handleShareButtonPressed} title={loc.receive.details_share} /> <Button onPress={handleShareButtonPressed} title={loc.receive.details_share} />
</View> </View>