2020-05-27 13:12:17 +02:00
|
|
|
import 'react-native-gesture-handler'; // should be on top
|
2021-09-24 21:32:22 +02:00
|
|
|
import React, { useContext, useEffect, useRef } from 'react';
|
2020-12-26 11:57:42 +01:00
|
|
|
import {
|
|
|
|
AppState,
|
|
|
|
DeviceEventEmitter,
|
|
|
|
NativeModules,
|
|
|
|
NativeEventEmitter,
|
|
|
|
Linking,
|
|
|
|
Platform,
|
|
|
|
StyleSheet,
|
2021-02-26 03:52:17 +01:00
|
|
|
UIManager,
|
2020-12-26 11:57:42 +01:00
|
|
|
useColorScheme,
|
|
|
|
View,
|
2021-03-12 14:19:51 +01:00
|
|
|
StatusBar,
|
2020-12-26 11:57:42 +01:00
|
|
|
} from 'react-native';
|
2020-07-15 19:32:59 +02:00
|
|
|
import { NavigationContainer, CommonActions } from '@react-navigation/native';
|
2020-05-27 13:12:17 +02:00
|
|
|
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
2020-06-19 02:18:11 +02:00
|
|
|
import { navigationRef } from './NavigationService';
|
|
|
|
import * as NavigationService from './NavigationService';
|
2019-03-05 02:04:40 +01:00
|
|
|
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
2019-08-25 03:14:26 +02:00
|
|
|
import { Chain } from './models/bitcoinUnits';
|
2020-05-24 12:27:08 +02:00
|
|
|
import OnAppLaunch from './class/on-app-launch';
|
2020-04-28 16:48:36 +02:00
|
|
|
import DeeplinkSchemaMatch from './class/deeplink-schema-match';
|
2020-07-20 15:38:46 +02:00
|
|
|
import loc from './loc';
|
2020-07-15 19:32:59 +02:00
|
|
|
import { BlueDefaultTheme, BlueDarkTheme, BlueCurrentTheme } from './components/themes';
|
2020-09-08 18:06:41 +02:00
|
|
|
import InitRoot from './Navigation';
|
2020-10-10 21:19:42 +02:00
|
|
|
import BlueClipboard from './blue_modules/clipboard';
|
2021-08-03 02:56:44 +02:00
|
|
|
import { isDesktop } from './blue_modules/environment';
|
2020-10-24 19:20:59 +02:00
|
|
|
import { BlueStorageContext } from './blue_modules/storage-context';
|
|
|
|
import WatchConnectivity from './WatchConnectivity';
|
|
|
|
import DeviceQuickActions from './class/quick-actions';
|
|
|
|
import Notifications from './blue_modules/notifications';
|
|
|
|
import Biometric from './class/biometrics';
|
2020-11-16 22:22:52 +01:00
|
|
|
import WidgetCommunication from './blue_modules/WidgetCommunication';
|
|
|
|
import changeNavigationBarColor from 'react-native-navigation-bar-color';
|
2021-09-24 21:32:22 +02:00
|
|
|
import ActionSheet from './screen/ActionSheet';
|
2021-09-25 05:36:08 +02:00
|
|
|
import HandoffComponent from './components/handoff';
|
2021-09-25 17:04:45 +02:00
|
|
|
import Privacy from './blue_modules/Privacy';
|
2020-07-01 13:56:52 +02:00
|
|
|
const A = require('./blue_modules/analytics');
|
2021-09-09 21:36:35 +02:00
|
|
|
const currency = require('./blue_modules/currency');
|
2020-11-20 19:28:34 +01:00
|
|
|
|
2022-02-12 18:03:10 +01:00
|
|
|
const eventEmitter = Platform.OS === 'ios' ? new NativeEventEmitter(NativeModules.EventEmitter) : undefined;
|
2021-09-26 19:45:50 +02:00
|
|
|
const { EventEmitter } = NativeModules;
|
2020-12-26 11:57:42 +01:00
|
|
|
|
2020-11-20 19:28:34 +01:00
|
|
|
const ClipboardContentType = Object.freeze({
|
|
|
|
BITCOIN: 'BITCOIN',
|
|
|
|
LIGHTNING: 'LIGHTNING',
|
|
|
|
});
|
2018-12-12 14:29:10 +01:00
|
|
|
|
2021-02-26 03:52:17 +01:00
|
|
|
if (Platform.OS === 'android') {
|
|
|
|
if (UIManager.setLayoutAnimationEnabledExperimental) {
|
|
|
|
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
const App = () => {
|
2022-01-26 18:50:41 +01:00
|
|
|
const { walletsInitialized, wallets, addWallet, saveToDisk, fetchAndSaveWalletTransactions, refreshAllWalletTransactions } =
|
|
|
|
useContext(BlueStorageContext);
|
2020-10-11 09:07:22 +02:00
|
|
|
const appState = useRef(AppState.currentState);
|
2020-12-19 09:39:07 +01:00
|
|
|
const clipboardContent = useRef();
|
2020-10-11 09:07:22 +02:00
|
|
|
const colorScheme = useColorScheme();
|
2019-03-02 13:13:12 +01:00
|
|
|
|
2021-01-01 20:15:40 +01:00
|
|
|
const onNotificationReceived = async notification => {
|
2020-12-27 18:04:32 +01:00
|
|
|
const payload = Object.assign({}, notification, notification.data);
|
|
|
|
if (notification.data && notification.data.data) Object.assign(payload, notification.data.data);
|
2021-01-01 20:15:40 +01:00
|
|
|
payload.foreground = true;
|
|
|
|
|
|
|
|
await Notifications.addNotification(payload);
|
|
|
|
// if user is staring at the app when he receives the notification we process it instantly
|
|
|
|
// so app refetches related wallet
|
|
|
|
if (payload.foreground) await processPushNotifications();
|
2020-12-26 11:57:42 +01:00
|
|
|
};
|
|
|
|
|
2020-12-27 01:10:54 +01:00
|
|
|
const openSettings = () => {
|
|
|
|
NavigationService.dispatch(
|
|
|
|
CommonActions.navigate({
|
|
|
|
name: 'Settings',
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-09-25 05:36:08 +02:00
|
|
|
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: {
|
2021-09-25 18:05:43 +02:00
|
|
|
xpub: data.userInfo.xpub,
|
2021-09-25 05:36:08 +02:00
|
|
|
},
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
useEffect(() => {
|
2020-10-24 19:20:59 +02:00
|
|
|
if (walletsInitialized) {
|
|
|
|
addListeners();
|
|
|
|
}
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
}, [walletsInitialized]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
2020-10-11 09:07:22 +02:00
|
|
|
return () => {
|
|
|
|
Linking.removeEventListener('url', handleOpenURL);
|
|
|
|
AppState.removeEventListener('change', handleAppStateChange);
|
2022-02-12 18:03:10 +01:00
|
|
|
eventEmitter?.removeAllListeners('onNotificationReceived');
|
|
|
|
eventEmitter?.removeAllListeners('openSettings');
|
|
|
|
eventEmitter?.removeAllListeners('onUserActivityOpen');
|
2020-10-11 09:07:22 +02:00
|
|
|
};
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
}, []);
|
2020-06-21 02:16:05 +02:00
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
useEffect(() => {
|
|
|
|
if (colorScheme) {
|
2020-07-23 02:58:02 +02:00
|
|
|
BlueCurrentTheme.updateColorScheme();
|
2020-11-16 22:22:52 +01:00
|
|
|
if (colorScheme === 'light') {
|
|
|
|
changeNavigationBarColor(BlueDefaultTheme.colors.background, true, true);
|
|
|
|
} else {
|
|
|
|
changeNavigationBarColor(BlueDarkTheme.colors.buttonBackgroundColor, false, true);
|
|
|
|
}
|
2020-07-15 19:32:59 +02:00
|
|
|
}
|
2020-10-11 09:07:22 +02:00
|
|
|
}, [colorScheme]);
|
2020-07-15 19:32:59 +02:00
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
const addListeners = () => {
|
|
|
|
Linking.addEventListener('url', handleOpenURL);
|
|
|
|
AppState.addEventListener('change', handleAppStateChange);
|
|
|
|
DeviceEventEmitter.addListener('quickActionShortcut', walletQuickActions);
|
2021-05-15 18:45:02 +02:00
|
|
|
DeviceQuickActions.popInitialAction().then(popInitialAction);
|
2021-09-26 20:55:56 +02:00
|
|
|
EventEmitter?.getMostRecentUserActivity()
|
2021-09-26 19:45:50 +02:00
|
|
|
.then(onUserActivityOpen)
|
|
|
|
.catch(() => console.log('No userActivity object sent'));
|
2020-10-11 09:07:22 +02:00
|
|
|
handleAppStateChange(undefined);
|
2021-01-01 20:15:40 +01:00
|
|
|
/*
|
|
|
|
When a notification on iOS is shown while the app is on foreground;
|
|
|
|
On willPresent on AppDelegate.m
|
|
|
|
*/
|
2022-02-12 18:03:10 +01:00
|
|
|
eventEmitter?.addListener('onNotificationReceived', onNotificationReceived);
|
|
|
|
eventEmitter?.addListener('openSettings', openSettings);
|
|
|
|
eventEmitter?.addListener('onUserActivityOpen', onUserActivityOpen);
|
2020-06-21 02:16:05 +02:00
|
|
|
};
|
2018-12-12 14:29:10 +01:00
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
const popInitialAction = async data => {
|
2019-11-03 01:25:55 +01:00
|
|
|
if (data) {
|
2020-10-24 19:20:59 +02:00
|
|
|
const wallet = wallets.find(wallet => wallet.getID() === data.userInfo.url.split('wallet/')[1]);
|
2020-06-19 02:18:11 +02:00
|
|
|
NavigationService.dispatch(
|
2020-05-27 13:12:17 +02:00
|
|
|
CommonActions.navigate({
|
|
|
|
name: 'WalletTransactions',
|
2020-05-28 15:57:01 +02:00
|
|
|
key: `WalletTransactions-${wallet.getID()}`,
|
2019-11-03 01:25:55 +01:00
|
|
|
params: {
|
2020-10-24 19:20:59 +02:00
|
|
|
walletID: wallet.getID(),
|
|
|
|
walletType: wallet.type,
|
2019-11-03 01:25:55 +01:00
|
|
|
},
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
const url = await Linking.getInitialURL();
|
|
|
|
if (url) {
|
2019-12-28 01:53:34 +01:00
|
|
|
if (DeeplinkSchemaMatch.hasSchema(url)) {
|
2020-10-11 09:07:22 +02:00
|
|
|
handleOpenURL({ url });
|
2019-11-03 01:25:55 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const isViewAllWalletsEnabled = await OnAppLaunch.isViewAllWalletsEnabled();
|
|
|
|
if (!isViewAllWalletsEnabled) {
|
|
|
|
const selectedDefaultWallet = await OnAppLaunch.getSelectedDefaultWallet();
|
2020-10-24 19:20:59 +02:00
|
|
|
const wallet = wallets.find(wallet => wallet.getID() === selectedDefaultWallet.getID());
|
2019-11-03 01:25:55 +01:00
|
|
|
if (wallet) {
|
2020-06-19 02:18:11 +02:00
|
|
|
NavigationService.dispatch(
|
2020-05-27 13:12:17 +02:00
|
|
|
CommonActions.navigate({
|
|
|
|
name: 'WalletTransactions',
|
2019-11-03 01:25:55 +01:00
|
|
|
key: `WalletTransactions-${wallet.getID()}`,
|
|
|
|
params: {
|
2020-10-24 19:20:59 +02:00
|
|
|
walletID: wallet.getID(),
|
|
|
|
walletType: wallet.type,
|
2019-11-03 01:25:55 +01:00
|
|
|
},
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
const walletQuickActions = data => {
|
2020-10-24 19:20:59 +02:00
|
|
|
const wallet = wallets.find(wallet => wallet.getID() === data.userInfo.url.split('wallet/')[1]);
|
2020-06-19 02:18:11 +02:00
|
|
|
NavigationService.dispatch(
|
2020-05-27 13:12:17 +02:00
|
|
|
CommonActions.navigate({
|
|
|
|
name: 'WalletTransactions',
|
2019-11-03 01:25:55 +01:00
|
|
|
key: `WalletTransactions-${wallet.getID()}`,
|
|
|
|
params: {
|
2020-10-24 19:20:59 +02:00
|
|
|
walletID: wallet.getID(),
|
|
|
|
walletType: wallet.type,
|
2019-11-03 01:25:55 +01:00
|
|
|
},
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-08-10 16:17:50 +02:00
|
|
|
/**
|
|
|
|
* Processes push notifications stored in AsyncStorage. Might navigate to some screen.
|
|
|
|
*
|
|
|
|
* @returns {Promise<boolean>} returns TRUE if notification was processed _and acted_ upon, i.e. navigation happened
|
|
|
|
* @private
|
|
|
|
*/
|
2020-10-11 09:07:22 +02:00
|
|
|
const processPushNotifications = async () => {
|
2021-09-07 21:30:07 +02:00
|
|
|
if (!walletsInitialized) {
|
|
|
|
console.log('not processing push notifications because wallets are not initialized');
|
|
|
|
return;
|
|
|
|
}
|
2020-08-10 16:17:50 +02:00
|
|
|
await new Promise(resolve => setTimeout(resolve, 200));
|
|
|
|
// sleep needed as sometimes unsuspend is faster than notification module actually saves notifications to async storage
|
2020-10-24 19:20:59 +02:00
|
|
|
const notifications2process = await Notifications.getStoredNotifications();
|
2021-01-01 20:15:40 +01:00
|
|
|
|
|
|
|
await Notifications.clearStoredNotifications();
|
|
|
|
Notifications.setApplicationIconBadgeNumber(0);
|
2020-12-29 23:54:56 +01:00
|
|
|
const deliveredNotifications = await Notifications.getDeliveredNotifications();
|
2021-01-01 20:15:40 +01:00
|
|
|
setTimeout(() => Notifications.removeAllDeliveredNotifications(), 5000); // so notification bubble wont disappear too fast
|
|
|
|
|
|
|
|
for (const payload of notifications2process) {
|
2021-01-02 00:39:26 +01:00
|
|
|
const wasTapped = payload.foreground === false || (payload.foreground === true && payload.userInteraction);
|
2020-08-10 16:17:50 +02:00
|
|
|
|
|
|
|
console.log('processing push notification:', payload);
|
|
|
|
let wallet;
|
|
|
|
switch (+payload.type) {
|
|
|
|
case 2:
|
|
|
|
case 3:
|
2020-10-24 19:20:59 +02:00
|
|
|
wallet = wallets.find(w => w.weOwnAddress(payload.address));
|
2020-08-10 16:17:50 +02:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 4:
|
2020-10-24 19:20:59 +02:00
|
|
|
wallet = wallets.find(w => w.weOwnTransaction(payload.txid || payload.hash));
|
2020-08-10 16:17:50 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wallet) {
|
2020-10-24 19:20:59 +02:00
|
|
|
const walletID = wallet.getID();
|
|
|
|
fetchAndSaveWalletTransactions(walletID);
|
2020-12-19 10:11:37 +01:00
|
|
|
if (wasTapped) {
|
2021-08-31 15:54:29 +02:00
|
|
|
if (payload.type !== 3 || wallet.chain === Chain.OFFCHAIN) {
|
|
|
|
NavigationService.dispatch(
|
|
|
|
CommonActions.navigate({
|
|
|
|
name: 'WalletTransactions',
|
|
|
|
key: `WalletTransactions-${wallet.getID()}`,
|
|
|
|
params: {
|
|
|
|
walletID,
|
|
|
|
walletType: wallet.type,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
NavigationService.navigate('ReceiveDetailsRoot', {
|
|
|
|
screen: 'ReceiveDetails',
|
2020-12-19 10:11:37 +01:00
|
|
|
params: {
|
|
|
|
walletID,
|
2021-08-31 15:54:29 +02:00
|
|
|
address: payload.address,
|
2020-12-19 10:11:37 +01:00
|
|
|
},
|
2021-08-31 15:54:29 +02:00
|
|
|
});
|
|
|
|
}
|
2021-01-01 20:15:40 +01:00
|
|
|
|
|
|
|
return true;
|
2020-12-19 10:11:37 +01:00
|
|
|
}
|
2020-08-10 16:17:50 +02:00
|
|
|
} else {
|
2021-01-01 20:15:40 +01:00
|
|
|
console.log('could not find wallet while processing push notification, NOP');
|
2020-08-10 16:17:50 +02:00
|
|
|
}
|
2021-01-01 20:15:40 +01:00
|
|
|
} // end foreach notifications loop
|
2020-12-26 11:57:42 +01:00
|
|
|
|
2021-01-01 20:15:40 +01:00
|
|
|
if (deliveredNotifications.length > 0) {
|
|
|
|
// notification object is missing userInfo. We know we received a notification but don't have sufficient
|
|
|
|
// data to refresh 1 wallet. let's refresh all.
|
2020-12-30 03:13:56 +01:00
|
|
|
refreshAllWalletTransactions();
|
|
|
|
}
|
2021-01-01 20:15:40 +01:00
|
|
|
|
|
|
|
// if we are here - we did not act upon any push
|
2020-12-26 11:57:42 +01:00
|
|
|
return false;
|
2020-10-11 09:07:22 +02:00
|
|
|
};
|
2020-08-10 16:17:50 +02:00
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
const handleAppStateChange = async nextAppState => {
|
2021-09-09 21:36:35 +02:00
|
|
|
if (wallets.length === 0) return;
|
|
|
|
if ((appState.current.match(/background/) && nextAppState === 'active') || nextAppState === undefined) {
|
|
|
|
setTimeout(() => A(A.ENUM.APP_UNSUSPENDED), 2000);
|
|
|
|
currency.updateExchangeRate();
|
|
|
|
const processed = await processPushNotifications();
|
|
|
|
if (processed) return;
|
|
|
|
const clipboard = await BlueClipboard.getClipboardContent();
|
|
|
|
const isAddressFromStoredWallet = wallets.some(wallet => {
|
|
|
|
if (wallet.chain === Chain.ONCHAIN) {
|
|
|
|
// checking address validity is faster than unwrapping hierarchy only to compare it to garbage
|
|
|
|
return wallet.isAddressValid && wallet.isAddressValid(clipboard) && wallet.weOwnAddress(clipboard);
|
|
|
|
} else {
|
|
|
|
return wallet.isInvoiceGeneratedByWallet(clipboard) || wallet.weOwnAddress(clipboard);
|
2019-03-05 02:04:40 +01:00
|
|
|
}
|
2021-09-09 21:36:35 +02:00
|
|
|
});
|
|
|
|
const isBitcoinAddress = DeeplinkSchemaMatch.isBitcoinAddress(clipboard);
|
|
|
|
const isLightningInvoice = DeeplinkSchemaMatch.isLightningInvoice(clipboard);
|
|
|
|
const isLNURL = DeeplinkSchemaMatch.isLnUrl(clipboard);
|
|
|
|
const isBothBitcoinAndLightning = DeeplinkSchemaMatch.isBothBitcoinAndLightning(clipboard);
|
|
|
|
if (
|
|
|
|
!isAddressFromStoredWallet &&
|
|
|
|
clipboardContent.current !== clipboard &&
|
|
|
|
(isBitcoinAddress || isLightningInvoice || isLNURL || isBothBitcoinAndLightning)
|
|
|
|
) {
|
2021-09-24 21:32:22 +02:00
|
|
|
let contentType;
|
2021-09-09 21:36:35 +02:00
|
|
|
if (isBitcoinAddress) {
|
2021-09-24 21:32:22 +02:00
|
|
|
contentType = ClipboardContentType.BITCOIN;
|
2021-09-09 21:36:35 +02:00
|
|
|
} else if (isLightningInvoice || isLNURL) {
|
2021-09-24 21:32:22 +02:00
|
|
|
contentType = ClipboardContentType.LIGHTNING;
|
2021-09-09 21:36:35 +02:00
|
|
|
} else if (isBothBitcoinAndLightning) {
|
2021-09-24 21:32:22 +02:00
|
|
|
contentType = ClipboardContentType.BITCOIN;
|
2021-09-09 21:36:35 +02:00
|
|
|
}
|
2021-09-24 21:32:22 +02:00
|
|
|
showClipboardAlert({ contentType });
|
2020-04-06 17:33:45 +02:00
|
|
|
}
|
2021-09-09 21:36:35 +02:00
|
|
|
clipboardContent.current = clipboard;
|
|
|
|
}
|
|
|
|
if (nextAppState) {
|
|
|
|
appState.current = nextAppState;
|
2019-03-02 13:13:12 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
const handleOpenURL = event => {
|
2020-10-24 19:20:59 +02:00
|
|
|
DeeplinkSchemaMatch.navigationRouteFor(event, value => NavigationService.navigate(...value), { wallets, addWallet, saveToDisk });
|
2019-12-15 14:16:29 +01:00
|
|
|
};
|
|
|
|
|
2021-09-24 21:32:22 +02:00
|
|
|
const showClipboardAlert = ({ contentType }) => {
|
|
|
|
ReactNativeHapticFeedback.trigger('impactLight', { ignoreAndroidSystemSettings: false });
|
2021-10-08 16:32:43 +02:00
|
|
|
BlueClipboard.getClipboardContent().then(clipboard => {
|
|
|
|
if (Platform.OS === 'ios' || Platform.OS === 'macos') {
|
|
|
|
ActionSheet.showActionSheetWithOptions(
|
|
|
|
{
|
|
|
|
options: [loc._.cancel, loc._.continue],
|
|
|
|
title: loc._.clipboard,
|
|
|
|
message: contentType === ClipboardContentType.BITCOIN ? loc.wallets.clipboard_bitcoin : loc.wallets.clipboard_lightning,
|
|
|
|
cancelButtonIndex: 0,
|
|
|
|
},
|
|
|
|
buttonIndex => {
|
|
|
|
if (buttonIndex === 1) {
|
|
|
|
handleOpenURL({ url: clipboard });
|
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
ActionSheet.showActionSheetWithOptions({
|
|
|
|
buttons: [
|
|
|
|
{ text: loc._.cancel, style: 'cancel', onPress: () => {} },
|
|
|
|
{
|
|
|
|
text: loc._.continue,
|
|
|
|
style: 'default',
|
|
|
|
onPress: () => {
|
|
|
|
handleOpenURL({ url: clipboard });
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
title: loc._.clipboard,
|
|
|
|
message: contentType === ClipboardContentType.BITCOIN ? loc.wallets.clipboard_bitcoin : loc.wallets.clipboard_lightning,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2019-03-02 13:13:12 +01:00
|
|
|
};
|
2021-09-24 21:32:22 +02:00
|
|
|
|
2020-10-11 09:07:22 +02:00
|
|
|
return (
|
|
|
|
<SafeAreaProvider>
|
|
|
|
<View style={styles.root}>
|
2021-03-12 14:19:51 +01:00
|
|
|
<StatusBar barStyle={colorScheme === 'dark' ? 'light-content' : 'dark-content'} backgroundColor="transparent" translucent />
|
2020-10-11 09:07:22 +02:00
|
|
|
<NavigationContainer ref={navigationRef} theme={colorScheme === 'dark' ? BlueDarkTheme : BlueDefaultTheme}>
|
|
|
|
<InitRoot />
|
2020-10-24 19:20:59 +02:00
|
|
|
<Notifications onProcessNotifications={processPushNotifications} />
|
2020-10-11 09:07:22 +02:00
|
|
|
</NavigationContainer>
|
2021-08-03 16:50:07 +02:00
|
|
|
{walletsInitialized && !isDesktop && <WatchConnectivity />}
|
2020-10-11 09:07:22 +02:00
|
|
|
</View>
|
2020-10-24 19:20:59 +02:00
|
|
|
<DeviceQuickActions />
|
|
|
|
<Biometric />
|
2020-11-02 14:11:28 +01:00
|
|
|
<WidgetCommunication />
|
2021-09-25 17:04:45 +02:00
|
|
|
<Privacy />
|
2020-10-11 09:07:22 +02:00
|
|
|
</SafeAreaProvider>
|
|
|
|
);
|
|
|
|
};
|
2019-03-02 13:13:12 +01:00
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
2020-05-30 10:16:03 +02:00
|
|
|
root: {
|
|
|
|
flex: 1,
|
|
|
|
},
|
2019-03-02 13:13:12 +01:00
|
|
|
});
|
2020-10-11 09:07:22 +02:00
|
|
|
|
|
|
|
export default App;
|