mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-01-19 05:45:15 +01:00
Merge pull request #6363 from BlueWallet/hadnoff
REF: Handoff component
This commit is contained in:
commit
4bdf987e26
36
App.js
36
App.js
@ -29,15 +29,15 @@ import Notifications from './blue_modules/notifications';
|
||||
import Biometric from './class/biometrics';
|
||||
import WidgetCommunication from './blue_modules/WidgetCommunication';
|
||||
import ActionSheet from './screen/ActionSheet';
|
||||
import HandoffComponent from './components/handoff';
|
||||
import triggerHapticFeedback, { HapticFeedbackTypes } from './blue_modules/hapticFeedback';
|
||||
import MenuElements from './components/MenuElements';
|
||||
import { updateExchangeRate } from './blue_modules/currency';
|
||||
import { NavigationProvider } from './components/NavigationProvider';
|
||||
import A from './blue_modules/analytics';
|
||||
import HandOffComponentListener from './components/HandOffComponentListener';
|
||||
|
||||
const eventEmitter = Platform.OS === 'ios' ? new NativeEventEmitter(NativeModules.EventEmitter) : undefined;
|
||||
const { EventEmitter, SplashScreen } = NativeModules;
|
||||
const { SplashScreen } = NativeModules;
|
||||
|
||||
LogBox.ignoreLogs(['Require cycle:', 'Battery state `unknown` and monitoring disabled, this is normal for simulators and tvOS.']);
|
||||
|
||||
@ -77,47 +77,17 @@ const App = () => {
|
||||
if (payload.foreground) await processPushNotifications();
|
||||
};
|
||||
|
||||
const onUserActivityOpen = data => {
|
||||
switch (data.activityType) {
|
||||
case HandoffComponent.activityTypes.ReceiveOnchain:
|
||||
NavigationService.navigate('ReceiveDetailsRoot', {
|
||||
screen: 'ReceiveDetails',
|
||||
params: {
|
||||
address: data.userInfo.address,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case HandoffComponent.activityTypes.Xpub:
|
||||
NavigationService.navigate('WalletXpubRoot', {
|
||||
screen: 'WalletXpub',
|
||||
params: {
|
||||
xpub: data.userInfo.xpub,
|
||||
},
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const addListeners = () => {
|
||||
const urlSubscription = Linking.addEventListener('url', handleOpenURL);
|
||||
const appStateSubscription = AppState.addEventListener('change', handleAppStateChange);
|
||||
|
||||
// Note: `getMostRecentUserActivity` doesn't create a persistent listener, so no need to unsubscribe
|
||||
EventEmitter?.getMostRecentUserActivity()
|
||||
.then(onUserActivityOpen)
|
||||
.catch(() => console.log('No userActivity object sent'));
|
||||
|
||||
const notificationSubscription = eventEmitter?.addListener('onNotificationReceived', onNotificationReceived);
|
||||
const activitySubscription = eventEmitter?.addListener('onUserActivityOpen', onUserActivityOpen);
|
||||
|
||||
// Store subscriptions in a ref or state to remove them later
|
||||
return {
|
||||
urlSubscription,
|
||||
appStateSubscription,
|
||||
notificationSubscription,
|
||||
activitySubscription,
|
||||
};
|
||||
};
|
||||
|
||||
@ -130,7 +100,6 @@ const App = () => {
|
||||
subscriptions.urlSubscription?.remove();
|
||||
subscriptions.appStateSubscription?.remove();
|
||||
subscriptions.notificationSubscription?.remove();
|
||||
subscriptions.activitySubscription?.remove();
|
||||
};
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@ -306,6 +275,7 @@ const App = () => {
|
||||
<MenuElements />
|
||||
<DeviceQuickActions />
|
||||
<Biometric />
|
||||
<HandOffComponentListener />
|
||||
</NavigationProvider>
|
||||
</NavigationContainer>
|
||||
</View>
|
||||
|
41
components/HandOffComponent.ios.tsx
Normal file
41
components/HandOffComponent.ios.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import React, { useContext } from 'react';
|
||||
// @ts-ignore: react-native-handoff is not in the type definition
|
||||
import Handoff from 'react-native-handoff';
|
||||
import { BlueStorageContext } from '../blue_modules/storage-context';
|
||||
|
||||
interface HandOffComponentProps {
|
||||
url?: string;
|
||||
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 => {
|
||||
const { isHandOffUseEnabled } = useContext(BlueStorageContext);
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log('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;
|
30
components/HandOffComponent.tsx
Normal file
30
components/HandOffComponent.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
|
||||
interface HandOffComponentProps {
|
||||
url?: string;
|
||||
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;
|
||||
};
|
||||
|
||||
const activityTypes = {
|
||||
ReceiveOnchain: 'io.bluewallet.bluewallet.receiveonchain',
|
||||
Xpub: 'io.bluewallet.bluewallet.xpub',
|
||||
ViewInBlockExplorer: 'io.bluewallet.bluewallet.blockexplorer',
|
||||
};
|
||||
|
||||
HandOffComponent.activityTypes = activityTypes;
|
||||
|
||||
export default HandOffComponent;
|
73
components/HandOffComponentListener.ios.tsx
Normal file
73
components/HandOffComponentListener.ios.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import React, { useEffect, useContext } from 'react';
|
||||
import * as NavigationService from '../NavigationService';
|
||||
import { BlueStorageContext } from '../blue_modules/storage-context';
|
||||
import { NativeEventEmitter, NativeModules } from 'react-native';
|
||||
import HandOffComponent from './HandOffComponent.ios';
|
||||
|
||||
interface UserActivityData {
|
||||
activityType: keyof typeof HandOffComponent.activityTypes;
|
||||
userInfo: {
|
||||
address?: string;
|
||||
xpub?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const { EventEmitter } = NativeModules;
|
||||
const eventEmitter = new NativeEventEmitter(EventEmitter);
|
||||
|
||||
const HandOffComponentListener: React.FC = () => {
|
||||
const { walletsInitialized } = useContext(BlueStorageContext); // Assuming 'walletsInitialized' is stored in context
|
||||
|
||||
useEffect(() => {
|
||||
if (!walletsInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const onUserActivityOpen = (data: UserActivityData) => {
|
||||
switch (data.activityType) {
|
||||
case HandOffComponent.activityTypes.ReceiveOnchain:
|
||||
NavigationService.navigate('ReceiveDetailsRoot', {
|
||||
// @ts-ignore: fix later
|
||||
screen: 'ReceiveDetails',
|
||||
params: {
|
||||
address: data.userInfo.address,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case HandOffComponent.activityTypes.Xpub:
|
||||
NavigationService.navigate('WalletXpubRoot', {
|
||||
// @ts-ignore: fix later
|
||||
screen: 'WalletXpub',
|
||||
params: {
|
||||
xpub: data.userInfo.xpub,
|
||||
},
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log(`Unhandled activity type: ${data.activityType}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const addListeners = () => {
|
||||
const activitySubscription = eventEmitter.addListener('onUserActivityOpen', onUserActivityOpen);
|
||||
|
||||
// Attempt to fetch the most recent user activity
|
||||
EventEmitter.getMostRecentUserActivity?.()
|
||||
.then(onUserActivityOpen)
|
||||
.catch(() => console.log('No userActivity object sent'));
|
||||
|
||||
return { activitySubscription };
|
||||
};
|
||||
|
||||
const subscriptions = addListeners();
|
||||
|
||||
return () => {
|
||||
subscriptions.activitySubscription?.remove();
|
||||
};
|
||||
}, [walletsInitialized]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default HandOffComponentListener;
|
7
components/HandOffComponentListener.tsx
Normal file
7
components/HandOffComponentListener.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
const HandOffComponentListener: React.FC = () => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export default HandOffComponentListener;
|
@ -6,7 +6,7 @@ import { BlueStorageContext } from '../blue_modules/storage-context';
|
||||
interface HandoffComponentProps {
|
||||
url?: string;
|
||||
title?: string;
|
||||
type: (typeof HandoffComponent.activityTypes)[keyof typeof HandoffComponent.activityTypes];
|
||||
type: (typeof HandOffComponent.activityTypes)[keyof typeof HandOffComponent.activityTypes];
|
||||
userInfo?: object;
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ interface HandoffComponentWithActivityTypes extends React.FC<HandoffComponentPro
|
||||
};
|
||||
}
|
||||
|
||||
const HandoffComponent: HandoffComponentWithActivityTypes = props => {
|
||||
const HandOffComponent: HandoffComponentWithActivityTypes = props => {
|
||||
const { isHandOffUseEnabled } = useContext(BlueStorageContext);
|
||||
|
||||
if (isHandOffUseEnabled) {
|
||||
@ -33,6 +33,6 @@ const activityTypes = {
|
||||
ViewInBlockExplorer: 'io.bluewallet.bluewallet.blockexplorer',
|
||||
};
|
||||
|
||||
HandoffComponent.activityTypes = activityTypes;
|
||||
HandOffComponent.activityTypes = activityTypes;
|
||||
|
||||
export default HandoffComponent;
|
||||
export default HandOffComponent;
|
||||
|
@ -17,7 +17,7 @@ import { BlueLoading, BlueButtonLink, BlueText, BlueSpacing20, BlueCard, BlueSpa
|
||||
import navigationStyle from '../../components/navigationStyle';
|
||||
import BottomModal from '../../components/BottomModal';
|
||||
import { Chain, BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import HandoffComponent from '../../components/handoff';
|
||||
import HandOffComponent from '../../components/HandOffComponent';
|
||||
import AmountInput from '../../components/AmountInput';
|
||||
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
|
||||
import loc, { formatBalance } from '../../loc';
|
||||
@ -426,7 +426,7 @@ const ReceiveDetails = () => {
|
||||
return (
|
||||
<View style={[styles.root, stylesHook.root]}>
|
||||
{address !== undefined && showAddress && (
|
||||
<HandoffComponent title={loc.send.details_address} type={HandoffComponent.activityTypes.ReceiveOnchain} userInfo={{ address }} />
|
||||
<HandOffComponent title={loc.send.details_address} type={HandOffComponent.activityTypes.ReceiveOnchain} userInfo={{ address }} />
|
||||
)}
|
||||
{showConfirmedBalance ? renderConfirmedBalance() : null}
|
||||
{showPendingBalance ? renderPendingBalance() : null}
|
||||
|
@ -4,7 +4,7 @@ import { useNavigation, useRoute } from '@react-navigation/native';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents';
|
||||
import navigationStyle from '../../components/navigationStyle';
|
||||
import HandoffComponent from '../../components/handoff';
|
||||
import HandOffComponent from '../../components/HandOffComponent';
|
||||
import loc from '../../loc';
|
||||
import { BlueStorageContext } from '../../blue_modules/storage-context';
|
||||
import ToolTipMenu from '../../components/TooltipMenu';
|
||||
@ -221,9 +221,9 @@ const TransactionsDetails = () => {
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.scroll} automaticallyAdjustContentInsets contentInsetAdjustmentBehavior="automatic">
|
||||
<HandoffComponent
|
||||
<HandOffComponent
|
||||
title={loc.transactions.details_title}
|
||||
type={HandoffComponent.activityTypes.ViewInBlockExplorer}
|
||||
type={HandOffComponent.activityTypes.ViewInBlockExplorer}
|
||||
url={`https://mempool.space/tx/${tx.hash}`}
|
||||
/>
|
||||
<BlueCard>
|
||||
|
@ -8,7 +8,7 @@ import TransactionIncomingIcon from '../../components/icons/TransactionIncomingI
|
||||
import TransactionOutgoingIcon from '../../components/icons/TransactionOutgoingIcon';
|
||||
import TransactionPendingIcon from '../../components/icons/TransactionPendingIcon';
|
||||
import navigationStyle from '../../components/navigationStyle';
|
||||
import HandoffComponent from '../../components/handoff';
|
||||
import HandOffComponent from '../../components/HandOffComponent';
|
||||
import { HDSegwitBech32Transaction } from '../../class';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import loc, { formatBalanceWithoutSuffix } from '../../loc';
|
||||
@ -360,9 +360,9 @@ const TransactionsStatus = () => {
|
||||
}
|
||||
return (
|
||||
<SafeArea>
|
||||
<HandoffComponent
|
||||
<HandOffComponent
|
||||
title={loc.transactions.details_title}
|
||||
type={HandoffComponent.activityTypes.ViewInBlockExplorer}
|
||||
type={HandOffComponent.activityTypes.ViewInBlockExplorer}
|
||||
url={`https://mempool.space/tx/${tx.hash}`}
|
||||
/>
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { LegacyWallet, LightningCustodianWallet, SegwitBech32Wallet, SegwitP2SHW
|
||||
import loc from '../../loc';
|
||||
import { BlueStorageContext } from '../../blue_modules/storage-context';
|
||||
import QRCodeComponent from '../../components/QRCodeComponent';
|
||||
import HandoffComponent from '../../components/handoff';
|
||||
import HandOffComponent from '../../components/HandOffComponent';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
import usePrivacy from '../../hooks/usePrivacy';
|
||||
@ -116,9 +116,9 @@ const WalletExport = () => {
|
||||
</BlueText>
|
||||
)}
|
||||
{wallet.type === WatchOnlyWallet.type && (
|
||||
<HandoffComponent
|
||||
<HandOffComponent
|
||||
title={loc.wallets.xpub_title}
|
||||
type={HandoffComponent.activityTypes.Xpub}
|
||||
type={HandOffComponent.activityTypes.Xpub}
|
||||
userInfo={{ xpub: wallet.getSecret() }}
|
||||
/>
|
||||
)}
|
||||
|
@ -7,7 +7,7 @@ import { BlueStorageContext } from '../../blue_modules/storage-context';
|
||||
import Button from '../../components/Button';
|
||||
import QRCodeComponent from '../../components/QRCodeComponent';
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
import HandoffComponent from '../../components/handoff';
|
||||
import HandOffComponent from '../../components/HandOffComponent';
|
||||
import usePrivacy from '../../hooks/usePrivacy';
|
||||
import loc from '../../loc';
|
||||
import { styles, useDynamicStyles } from './xpub.styles';
|
||||
@ -94,7 +94,7 @@ const WalletXpub: React.FC = () => {
|
||||
<BlueSpacing20 />
|
||||
{xPubText && <CopyTextToClipboard text={xPubText} />}
|
||||
</View>
|
||||
<HandoffComponent title={loc.wallets.xpub_title} type={HandoffComponent.activityTypes.Xpub} userInfo={{ xpub: xPubText }} />
|
||||
<HandOffComponent title={loc.wallets.xpub_title} type={HandOffComponent.activityTypes.Xpub} userInfo={{ xpub: xPubText }} />
|
||||
<View style={styles.share}>
|
||||
<Button onPress={handleShareButtonPressed} title={loc.receive.details_share} />
|
||||
</View>
|
||||
|
Loading…
Reference in New Issue
Block a user