REF: migrate to RN5, fix everything

This commit is contained in:
Ivan Vershigora 2020-05-27 14:12:17 +03:00
parent 94fb26f20b
commit c65709dab6
44 changed files with 1594 additions and 1056 deletions

52
App.js
View file

@ -1,8 +1,10 @@
import 'react-native-gesture-handler'; // should be on top
import React from 'react';
import { Linking, DeviceEventEmitter, AppState, Clipboard, StyleSheet, KeyboardAvoidingView, Platform, View } from 'react-native';
import Modal from 'react-native-modal';
import { NavigationActions } from 'react-navigation';
import MainBottomTabs from './MainBottomTabs';
import { NavigationContainer, CommonActions } from '@react-navigation/native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import Navigation from './Navigation';
import NavigationService from './NavigationService';
import { BlueTextCentered, BlueButton } from './BlueComponents';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
@ -49,9 +51,9 @@ export default class App extends React.Component {
this.navigator.dismiss;
const wallet = BlueApp.getWallets().find(wallet => wallet.getID() === data.userInfo.url.split('wallet/')[1]);
this.navigator.dispatch(
NavigationActions.navigate({
CommonActions.navigate({
key: `WalletTransactions-${wallet.getID()}`,
routeName: 'WalletTransactions',
name: 'WalletTransactions',
params: {
wallet,
},
@ -72,8 +74,8 @@ export default class App extends React.Component {
const wallet = BlueApp.getWallets().find(wallet => wallet.getID() === selectedDefaultWallet.getID());
if (wallet) {
this.navigator.dispatch(
NavigationActions.navigate({
routeName: 'WalletTransactions',
CommonActions.navigate({
name: 'WalletTransactions',
key: `WalletTransactions-${wallet.getID()}`,
params: {
wallet,
@ -91,8 +93,8 @@ export default class App extends React.Component {
// eslint-disable-next-line no-unused-expressions
this.navigator.dismiss;
this.navigator.dispatch(
NavigationActions.navigate({
routeName: 'WalletTransactions',
CommonActions.navigate({
name: 'WalletTransactions',
key: `WalletTransactions-${wallet.getID()}`,
params: {
wallet,
@ -150,8 +152,8 @@ export default class App extends React.Component {
if (wallet.chain === Chain.ONCHAIN) {
this.navigator &&
this.navigator.dispatch(
NavigationActions.navigate({
routeName: 'SendDetails',
CommonActions.navigate({
name: 'SendDetails',
params: {
uri: clipboardContent.bitcoin,
fromWallet: wallet,
@ -161,8 +163,8 @@ export default class App extends React.Component {
} else if (wallet.chain === Chain.OFFCHAIN) {
this.navigator &&
this.navigator.dispatch(
NavigationActions.navigate({
routeName: 'ScanLndInvoice',
CommonActions.navigate({
name: 'ScanLndInvoice',
params: {
uri: clipboardContent.lndInvoice,
fromSecret: wallet.getSecret(),
@ -173,7 +175,8 @@ export default class App extends React.Component {
};
handleOpenURL = event => {
DeeplinkSchemaMatch.navigationRouteFor(event, value => this.navigator && this.navigator.dispatch(NavigationActions.navigate(value)));
// DeeplinkSchemaMatch.navigationRouteFor(event, value => this.navigator && this.navigator.dispatch(CommonActions.navigate(value)));
DeeplinkSchemaMatch.navigationRouteFor(event, value => this.navigator && this.navigator.navigate(...value));
};
renderClipboardContentModal = () => {
@ -217,15 +220,20 @@ export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
<MainBottomTabs
ref={nav => {
this.navigator = nav;
NavigationService.setTopLevelNavigator(nav);
}}
/>
{this.renderClipboardContentModal()}
</View>
<SafeAreaProvider>
<View style={{ flex: 1 }}>
<NavigationContainer
ref={nav => {
this.navigator = nav;
NavigationService.setTopLevelNavigator(nav);
}}
>
<Navigation />
</NavigationContainer>
{this.renderClipboardContentModal()}
</View>
</SafeAreaProvider>
);
}
}

View file

@ -399,28 +399,32 @@ export const BlueNavigationStyle = (navigation, withNavigationCloseButton = fals
backgroundColor: BlueApp.settings.brandingColor,
borderBottomWidth: 0,
elevation: 0,
shadowOffset: { height: 0, width: 0 },
},
headerTitleStyle: {
fontWeight: '600',
color: BlueApp.settings.foregroundColor,
},
headerTintColor: BlueApp.settings.foregroundColor,
headerRight: withNavigationCloseButton ? (
<TouchableOpacity
style={{ width: 40, height: 40, padding: 14 }}
onPress={
customCloseButtonFunction === undefined
? () => {
Keyboard.dismiss();
navigation.goBack(null);
}
: customCloseButtonFunction
}
>
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
</TouchableOpacity>
) : null,
headerBackTitle: null,
headerRight: withNavigationCloseButton
? () => (
<TouchableOpacity
style={{ width: 40, height: 40, padding: 14 }}
onPress={
customCloseButtonFunction === undefined
? () => {
Keyboard.dismiss();
navigation.goBack(null);
}
: customCloseButtonFunction
}
>
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
</TouchableOpacity>
)
: null,
// headerBackTitle: null,
headerBackTitleVisible: false,
});
export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuButton = false, advancedOptionsMenuButtonAction) => ({
@ -434,7 +438,7 @@ export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuB
color: BlueApp.settings.foregroundColor,
},
headerTintColor: BlueApp.settings.foregroundColor,
headerLeft: (
headerLeft: () => (
<TouchableOpacity
style={{ minWwidth: 40, height: 40, padding: 14 }}
onPress={() => {
@ -445,11 +449,13 @@ export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuB
<Image style={{ alignSelf: 'center' }} source={require('./img/close.png')} />
</TouchableOpacity>
),
headerRight: withAdvancedOptionsMenuButton ? (
<TouchableOpacity style={{ minWidth: 40, height: 40, padding: 14 }} onPress={advancedOptionsMenuButtonAction}>
<Icon size={22} name="kebab-horizontal" type="octicon" color={BlueApp.settings.foregroundColor} />
</TouchableOpacity>
) : null,
headerRight: withAdvancedOptionsMenuButton
? () => (
<TouchableOpacity style={{ minWidth: 40, height: 40, padding: 14 }} onPress={advancedOptionsMenuButtonAction}>
<Icon size={22} name="kebab-horizontal" type="octicon" color={BlueApp.settings.foregroundColor} />
</TouchableOpacity>
)
: null,
headerBackTitle: null,
});

View file

@ -1,386 +0,0 @@
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Settings from './screen/settings/settings';
import About from './screen/settings/about';
import ReleaseNotes from './screen/settings/releasenotes';
import Licensing from './screen/settings/licensing';
import Selftest from './screen/selftest';
import Language from './screen/settings/language';
import Currency from './screen/settings/currency';
import EncryptStorage from './screen/settings/encryptStorage';
import PlausibleDeniability from './screen/plausibledeniability';
import LightningSettings from './screen/settings/lightningSettings';
import ElectrumSettings from './screen/settings/electrumSettings';
import GeneralSettings from './screen/settings/GeneralSettings';
import NetworkSettings from './screen/settings/NetworkSettings';
import DefaultView from './screen/settings/defaultView';
import WalletsList from './screen/wallets/list';
import WalletTransactions from './screen/wallets/transactions';
import AddWallet from './screen/wallets/add';
import PleaseBackup from './screen/wallets/pleaseBackup';
import PleaseBackupLNDHub from './screen/wallets/pleaseBackupLNDHub';
import ImportWallet from './screen/wallets/import';
import WalletDetails from './screen/wallets/details';
import WalletExport from './screen/wallets/export';
import WalletXpub from './screen/wallets/xpub';
import BuyBitcoin from './screen/wallets/buyBitcoin';
import HodlHodl from './screen/wallets/hodlHodl';
import Marketplace from './screen/wallets/marketplace';
import ReorderWallets from './screen/wallets/reorderWallets';
import SelectWallet from './screen/wallets/selectWallet';
import details from './screen/transactions/details';
import TransactionStatus from './screen/transactions/transactionStatus';
import cpfp from './screen/transactions/CPFP';
import rbfBumpFee from './screen/transactions/RBFBumpFee';
import rbfCancel from './screen/transactions/RBFCancel';
import receiveDetails from './screen/receive/details';
import sendDetails from './screen/send/details';
import ScanQRCode from './screen/send/ScanQRCode';
import sendCreate from './screen/send/create';
import Confirm from './screen/send/confirm';
import PsbtWithHardwareWallet from './screen/send/psbtWithHardwareWallet';
import Success from './screen/send/success';
import Broadcast from './screen/send/broadcast';
import ScanLndInvoice from './screen/lnd/scanLndInvoice';
import LappBrowser from './screen/lnd/browser';
import LNDCreateInvoice from './screen/lnd/lndCreateInvoice';
import LNDViewInvoice from './screen/lnd/lndViewInvoice';
import LNDViewAdditionalInvoiceInformation from './screen/lnd/lndViewAdditionalInvoiceInformation';
const ReorderWalletsStackNavigator = createStackNavigator({
ReorderWallets: {
screen: ReorderWallets,
},
});
const WalletsStackNavigator = createStackNavigator(
{
Wallets: {
screen: WalletsList,
path: 'wallets',
navigationOptions: {
header: null,
},
},
WalletTransactions: {
screen: WalletTransactions,
path: 'WalletTransactions',
routeName: 'WalletTransactions',
},
TransactionStatus: {
screen: TransactionStatus,
},
TransactionDetails: {
screen: details,
},
WalletDetails: {
screen: WalletDetails,
},
HodlHodl: {
screen: HodlHodl,
},
CPFP: {
screen: cpfp,
},
RBFBumpFee: {
screen: rbfBumpFee,
},
RBFCancel: {
screen: rbfCancel,
},
Settings: {
screen: Settings,
path: 'Settings',
navigationOptions: {
headerStyle: {
backgroundColor: '#FFFFFF',
borderBottomWidth: 0,
elevation: 0,
},
headerTintColor: '#0c2550',
},
},
SelectWallet: {
screen: SelectWallet,
},
Currency: {
screen: Currency,
},
About: {
screen: About,
path: 'About',
},
ReleaseNotes: {
screen: ReleaseNotes,
path: 'ReleaseNotes',
},
Selftest: {
screen: Selftest,
},
Licensing: {
screen: Licensing,
path: 'Licensing',
},
DefaultView: {
screen: DefaultView,
path: 'DefaultView',
},
Language: {
screen: Language,
path: 'Language',
},
EncryptStorage: {
screen: EncryptStorage,
path: 'EncryptStorage',
},
GeneralSettings: {
screen: GeneralSettings,
path: 'GeneralSettings',
},
NetworkSettings: {
screen: NetworkSettings,
path: 'NetworkSettings',
},
PlausibleDeniability: {
screen: PlausibleDeniability,
path: 'PlausibleDeniability',
},
LightningSettings: {
screen: LightningSettings,
path: 'LightningSettings',
},
ElectrumSettings: {
screen: ElectrumSettings,
path: 'ElectrumSettings',
},
LNDViewInvoice: {
screen: LNDViewInvoice,
swipeEnabled: false,
gesturesEnabled: false,
},
LNDViewAdditionalInvoiceInformation: {
screen: LNDViewAdditionalInvoiceInformation,
},
Broadcast: {
screen: Broadcast,
navigationOptions: () => ({
title: 'Broadcast',
headerStyle: {
backgroundColor: '#FFFFFF',
borderBottomWidth: 0,
},
headerTintColor: '#0c2550',
}),
},
},
{ headerBackTitleVisible: false },
);
const CreateTransactionStackNavigator = createStackNavigator({
SendDetails: {
routeName: 'SendDetails',
screen: sendDetails,
},
Confirm: {
screen: Confirm,
},
PsbtWithHardwareWallet: {
screen: PsbtWithHardwareWallet,
},
CreateTransaction: {
screen: sendCreate,
navigationOptions: {
headerStyle: {
backgroundColor: '#FFFFFF',
borderBottomWidth: 0,
},
headerTintColor: '#0c2550',
},
},
Success: {
screen: Success,
},
SelectWallet: {
screen: SelectWallet,
navigationOptions: {
headerRight: null,
},
},
});
const LNDCreateInvoiceStackNavigator = createStackNavigator({
LNDCreateInvoice: {
screen: LNDCreateInvoice,
},
SelectWallet: {
screen: SelectWallet,
navigationOptions: {
headerLeft: null,
},
},
LNDViewInvoice: {
screen: LNDViewInvoice,
swipeEnabled: false,
gesturesEnabled: false,
},
LNDViewAdditionalInvoiceInformation: {
screen: LNDViewAdditionalInvoiceInformation,
},
});
const CreateWalletStackNavigator = createStackNavigator({
AddWallet: {
screen: AddWallet,
},
ImportWallet: {
screen: ImportWallet,
routeName: 'ImportWallet',
},
PleaseBackup: {
screen: PleaseBackup,
},
PleaseBackupLNDHub: {
screen: PleaseBackupLNDHub,
swipeEnabled: false,
gesturesEnabled: false,
navigationOptions: {
header: null,
},
},
});
const LightningScanInvoiceStackNavigator = createStackNavigator({
ScanLndInvoice: {
screen: ScanLndInvoice,
},
SelectWallet: {
screen: SelectWallet,
navigationOptions: {
headerRight: null,
},
},
Success: {
screen: Success,
},
});
const HandleOffchainAndOnChainStackNavigator = createStackNavigator(
{
SelectWallet: {
screen: SelectWallet,
},
// LND:
ScanLndInvoice: {
screen: LightningScanInvoiceStackNavigator,
navigationOptions: {
header: null,
},
},
ScanQRCode: {
screen: ScanQRCode,
},
SendDetails: {
screen: CreateTransactionStackNavigator,
navigationOptions: {
header: null,
},
},
},
{ headerBackTitleVisible: false },
);
const MainBottomTabs = createStackNavigator(
{
Wallets: {
screen: WalletsStackNavigator,
path: 'wallets',
navigationOptions: {
header: null,
},
},
AddWallet: {
screen: CreateWalletStackNavigator,
navigationOptions: {
header: null,
},
},
WalletExport: {
screen: WalletExport,
},
WalletXpub: {
screen: WalletXpub,
},
BuyBitcoin: {
screen: BuyBitcoin,
},
Marketplace: {
screen: Marketplace,
},
//
SendDetails: {
routeName: 'SendDetails',
screen: CreateTransactionStackNavigator,
navigationOptions: {
header: null,
},
},
SelectWallet: {
screen: SelectWallet,
navigationOptions: {
headerLeft: null,
},
},
ReceiveDetails: {
screen: receiveDetails,
},
//
// LND:
ScanLndInvoice: {
screen: LightningScanInvoiceStackNavigator,
navigationOptions: {
header: null,
},
},
ScanQRCode: {
screen: ScanQRCode,
},
LappBrowser: {
screen: LappBrowser,
},
ReorderWallets: {
screen: ReorderWalletsStackNavigator,
navigationOptions: {
header: null,
},
},
LNDCreateInvoice: {
screen: LNDCreateInvoiceStackNavigator,
navigationOptions: {
header: null,
},
},
HandleOffchainAndOnChain: {
screen: HandleOffchainAndOnChainStackNavigator,
navigationOptions: {
header: null,
},
},
},
{
mode: 'modal',
},
);
export default createAppContainer(MainBottomTabs);

230
Navigation.js Normal file
View file

@ -0,0 +1,230 @@
// import { createAppContainer } from '@react-navigation/native';
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import Settings from './screen/settings/settings';
import About from './screen/settings/about';
import ReleaseNotes from './screen/settings/releasenotes';
import Licensing from './screen/settings/licensing';
import Selftest from './screen/selftest';
import Language from './screen/settings/language';
import Currency from './screen/settings/currency';
import EncryptStorage from './screen/settings/encryptStorage';
import PlausibleDeniability from './screen/plausibledeniability';
import LightningSettings from './screen/settings/lightningSettings';
import ElectrumSettings from './screen/settings/electrumSettings';
import GeneralSettings from './screen/settings/GeneralSettings';
import NetworkSettings from './screen/settings/NetworkSettings';
import DefaultView from './screen/settings/defaultView';
import WalletsList from './screen/wallets/list';
import WalletTransactions from './screen/wallets/transactions';
import AddWallet from './screen/wallets/add';
import PleaseBackup from './screen/wallets/pleaseBackup';
import PleaseBackupLNDHub from './screen/wallets/pleaseBackupLNDHub';
import ImportWallet from './screen/wallets/import';
import WalletDetails from './screen/wallets/details';
import WalletExport from './screen/wallets/export';
import WalletXpub from './screen/wallets/xpub';
import BuyBitcoin from './screen/wallets/buyBitcoin';
import HodlHodl from './screen/wallets/hodlHodl';
import Marketplace from './screen/wallets/marketplace';
import ReorderWallets from './screen/wallets/reorderWallets';
import SelectWallet from './screen/wallets/selectWallet';
import TransactionDetails from './screen/transactions/details';
import TransactionStatus from './screen/transactions/transactionStatus';
import CPFP from './screen/transactions/CPFP';
import RBFBumpFee from './screen/transactions/RBFBumpFee';
import RBFCancel from './screen/transactions/RBFCancel';
import ReceiveDetails from './screen/receive/details';
import SendDetails from './screen/send/details';
import ScanQRCode from './screen/send/ScanQRCode';
import SendCreate from './screen/send/create';
import Confirm from './screen/send/confirm';
import PsbtWithHardwareWallet from './screen/send/psbtWithHardwareWallet';
import Success from './screen/send/success';
import Broadcast from './screen/send/broadcast';
import ScanLndInvoice from './screen/lnd/scanLndInvoice';
import LappBrowser from './screen/lnd/browser';
import LNDCreateInvoice from './screen/lnd/lndCreateInvoice';
import LNDViewInvoice from './screen/lnd/lndViewInvoice';
import LNDViewAdditionalInvoiceInformation from './screen/lnd/lndViewAdditionalInvoiceInformation';
const WalletsStack = createStackNavigator();
const WalletsRoot = () => (
<WalletsStack.Navigator screenOptions={{ headerTitle: null, headerBackTitleVisible: false }}>
<WalletsStack.Screen name="WalletsList" component={WalletsList} options={{ headerShown: false }} />
<WalletsStack.Screen name="WalletTransactions" component={WalletTransactions} options={WalletTransactions.navigationOptions} />
<WalletsStack.Screen name="WalletDetails" component={WalletDetails} options={WalletDetails.navigationOptions} />
<WalletsStack.Screen name="TransactionDetails" component={TransactionDetails} options={TransactionDetails.navigationOptions} />
<WalletsStack.Screen name="TransactionStatus" component={TransactionStatus} options={TransactionStatus.navigationOptions} />
<WalletsStack.Screen name="HodlHodl" component={HodlHodl} options={HodlHodl.navigationOptions} />
<WalletsStack.Screen name="CPFP" component={CPFP} options={CPFP.navigationOptions} />
<WalletsStack.Screen name="RBFBumpFee" component={RBFBumpFee} options={RBFBumpFee.navigationOptions} />
<WalletsStack.Screen name="RBFCancel" component={RBFCancel} options={RBFCancel.navigationOptions} />
<WalletsStack.Screen
name="Settings"
component={Settings}
options={{
headerStyle: {
backgroundColor: '#FFFFFF',
borderBottomWidth: 0,
elevation: 0,
},
headerTintColor: '#0c2550',
}}
/>
<WalletsStack.Screen name="SelectWallet" component={SelectWallet} options={SelectWallet.navigationOptions} />
<WalletsStack.Screen name="Currency" component={Currency} options={Currency.navigationOptions} />
<WalletsStack.Screen name="About" component={About} options={About.navigationOptions} />
<WalletsStack.Screen name="ReleaseNotes" component={ReleaseNotes} options={ReleaseNotes.navigationOptions} />
<WalletsStack.Screen name="Selftest" component={Selftest} options={Selftest.navigationOptions} />
<WalletsStack.Screen name="Licensing" component={Licensing} options={Licensing.navigationOptions} />
<WalletsStack.Screen name="DefaultView" component={DefaultView} options={DefaultView.navigationOptions} />
<WalletsStack.Screen name="Language" component={Language} options={Language.navigationOptions} />
<WalletsStack.Screen name="EncryptStorage" component={EncryptStorage} options={EncryptStorage.navigationOptions} />
<WalletsStack.Screen name="GeneralSettings" component={GeneralSettings} options={GeneralSettings.navigationOptions} />
<WalletsStack.Screen name="NetworkSettings" component={NetworkSettings} options={NetworkSettings.navigationOptions} />
<WalletsStack.Screen name="PlausibleDeniability" component={PlausibleDeniability} options={PlausibleDeniability.navigationOptions} />
<WalletsStack.Screen name="LightningSettings" component={LightningSettings} options={LightningSettings.navigationOptions} />
<WalletsStack.Screen name="ElectrumSettings" component={ElectrumSettings} options={ElectrumSettings.navigationOptions} />
<WalletsStack.Screen
name="LNDViewInvoice"
component={LNDViewInvoice}
options={LNDViewInvoice.navigationOptions}
swipeEnabled={false}
gesturesEnabled={false}
/>
<WalletsStack.Screen
name="LNDViewAdditionalInvoiceInformation"
component={LNDViewAdditionalInvoiceInformation}
options={LNDViewAdditionalInvoiceInformation.navigationOptions}
/>
<WalletsStack.Screen
name="Broadcast"
component={Broadcast}
options={{
title: 'Broadcast',
headerStyle: {
backgroundColor: '#FFFFFF',
borderBottomWidth: 0,
},
headerTintColor: '#0c2550',
}}
/>
<WalletsStack.Screen name="ReorderWallets" component={ReorderWallets} options={ReorderWallets.navigationOptions} />
</WalletsStack.Navigator>
);
const AddWalletStack = createStackNavigator();
const AddWalletRoot = () => (
<AddWalletStack.Navigator screenOptions={{}}>
<AddWalletStack.Screen name="AddWallet" component={AddWallet} options={AddWallet.navigationOptions} />
<AddWalletStack.Screen name="ImportWallet" component={ImportWallet} options={ImportWallet.navigationOptions} />
<AddWalletStack.Screen name="PleaseBackup" component={PleaseBackup} options={PleaseBackup.navigationOptions} />
<AddWalletStack.Screen
name="PleaseBackupLNDHub"
component={PleaseBackupLNDHub}
swipeEnabled={false}
gesturesEnabled={false}
options={{ headerShown: null }}
/>
</AddWalletStack.Navigator>
);
// CreateTransactionStackNavigator === SendDetailsStack
const SendDetailsStack = createStackNavigator();
const SendDetailsRoot = () => (
<SendDetailsStack.Navigator>
<SendDetailsStack.Screen name="SendDetails" component={SendDetails} options={SendDetails.navigationOptions} />
<SendDetailsStack.Screen name="Confirm" component={Confirm} options={Confirm.navigationOptions} />
<SendDetailsStack.Screen
name="PsbtWithHardwareWallet"
component={PsbtWithHardwareWallet}
options={PsbtWithHardwareWallet.navigationOptions}
/>
<SendDetailsStack.Screen
name="CreateTransaction"
component={SendCreate}
options={{
headerStyle: {
backgroundColor: '#FFFFFF',
borderBottomWidth: 0,
},
headerTintColor: '#0c2550',
}}
/>
<SendDetailsStack.Screen name="Success" component={Success} options={Success.navigationOptions} />
<SendDetailsStack.Screen name="SelectWallet" component={SelectWallet} options={{ headerRight: null }} />
</SendDetailsStack.Navigator>
);
const LNDCreateInvoiceStack = createStackNavigator();
const LNDCreateInvoiceRoot = () => (
<LNDCreateInvoiceStack.Navigator>
<LNDCreateInvoiceStack.Screen name="LNDCreateInvoice" component={LNDCreateInvoice} options={LNDCreateInvoice.navigationOptions} />
<LNDCreateInvoiceStack.Screen name="SelectWallet" component={SelectWallet} options={{ headerLeft: null }} />
<LNDCreateInvoiceStack.Screen
name="LNDViewInvoice"
component={LNDViewInvoice}
options={LNDViewInvoice.navigationOptions}
swipeEnabled={false}
gesturesEnabled={false}
/>
<LNDCreateInvoiceStack.Screen
name="LNDViewAdditionalInvoiceInformation"
component={LNDViewAdditionalInvoiceInformation}
options={LNDViewAdditionalInvoiceInformation.navigationOptions}
/>
</LNDCreateInvoiceStack.Navigator>
);
// LightningScanInvoiceStackNavigator === ScanLndInvoiceStack
const ScanLndInvoiceStack = createStackNavigator();
const ScanLndInvoiceRoot = () => (
<ScanLndInvoiceStack.Navigator>
<ScanLndInvoiceStack.Screen name="ScanLndInvoice" component={ScanLndInvoice} options={ScanLndInvoice.navigationOptions} />
<ScanLndInvoiceStack.Screen name="SelectWallet" component={SelectWallet} options={{ headerLeft: null }} />
<ScanLndInvoiceStack.Screen name="Success" component={Success} options={Success.navigationOptions} />
</ScanLndInvoiceStack.Navigator>
);
const HandleOffchainAndOnChainStack = createStackNavigator();
const HandleOffchainAndOnChain = () => (
<HandleOffchainAndOnChainStack.Navigator screenOptions={{ headerBackTitleVisible: false }}>
{/* screens */}
<HandleOffchainAndOnChainStack.Screen name="SelectWallet" component={SelectWallet} options={SelectWallet.navigationOptions} />
<HandleOffchainAndOnChainStack.Screen name="ScanQRCode" component={ScanQRCode} options={ScanQRCode.navigationOptions} />
{/* stacks */}
<HandleOffchainAndOnChainStack.Screen name="ScanLndInvoice" component={ScanLndInvoiceRoot} options={{ headerShown: false }} />
<HandleOffchainAndOnChainStack.Screen name="SendDetails" component={SendDetailsRoot} options={{ headerShown: false }} />
</HandleOffchainAndOnChainStack.Navigator>
);
const RootStack = createStackNavigator();
const Navigation = () => (
<RootStack.Navigator mode="modal">
{/* stacks */}
<RootStack.Screen name="WalletsRoot" component={WalletsRoot} options={{ headerShown: false }} />
<RootStack.Screen name="AddWalletRoot" component={AddWalletRoot} options={{ headerShown: false }} />
<RootStack.Screen name="SendDetailsRoot" component={SendDetailsRoot} options={{ headerShown: false }} />
<RootStack.Screen name="LNDCreateInvoiceRoot" component={LNDCreateInvoiceRoot} options={{ headerShown: false }} />
<RootStack.Screen name="ScanLndInvoiceRoot" component={ScanLndInvoiceRoot} options={{ headerShown: false }} />
<RootStack.Screen name="HandleOffchainAndOnChain" component={HandleOffchainAndOnChain} />
{/* screens */}
<RootStack.Screen name="WalletExport" component={WalletExport} options={WalletExport.navigationOptions} />
<RootStack.Screen name="WalletXpub" component={WalletXpub} options={WalletXpub.navigationOptions} />
<RootStack.Screen name="BuyBitcoin" component={BuyBitcoin} options={BuyBitcoin.navigationOptions} />
<RootStack.Screen name="Marketplace" component={Marketplace} options={Marketplace.navigationOptions} />
<RootStack.Screen name="SelectWallet" component={SelectWallet} options={{ headerLeft: null }} />
<RootStack.Screen name="ReceiveDetails" component={ReceiveDetails} options={ReceiveDetails.navigationOptions} />
<RootStack.Screen name="ScanQRCode" component={ScanQRCode} options={{ headerShown: false }} />
<RootStack.Screen name="LappBrowser" component={LappBrowser} options={LappBrowser.navigationOptions} />
</RootStack.Navigator>
);
export default Navigation;

View file

@ -1,4 +1,4 @@
import { NavigationActions } from 'react-navigation';
// import { CommonActions } from '@react-navigation/native';
let _navigator;
@ -6,13 +6,8 @@ function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
}),
);
function navigate(name, params) {
_navigator.navigate(name, params);
}
export default {

View file

@ -3,7 +3,7 @@ import { View, Image, TouchableOpacity } from 'react-native';
import { Icon } from 'react-native-elements';
import Biometric from './class/biometrics';
import PropTypes from 'prop-types';
import { SafeAreaView } from 'react-navigation';
import { SafeAreaView } from 'react-native-safe-area-context';
/** @type {AppStorage} */
const BlueApp = require('./BlueApp');

View file

@ -27,7 +27,7 @@ class DeeplinkSchemaMatch {
* navigation dictionary required by react-navigation
*
* @param event {{url: string}} URL deeplink as passed to app, e.g. `bitcoin:bc1qh6tf004ty7z7un2v5ntu4mkf630545gvhs45u7?amount=666&label=Yo`
* @param completionHandler {function} Returns {routeName: string, params: object}
* @param completionHandler {function} Returns [string, params: object]
*/
static navigationRouteFor(event, completionHandler) {
if (event.url === null) {
@ -45,12 +45,15 @@ class DeeplinkSchemaMatch {
RNFS.readFile(event.url)
.then(file => {
if (file) {
completionHandler({
routeName: 'PsbtWithHardwareWallet',
params: {
deepLinkPSBT: file,
completionHandler([
'SendDetailsRoot',
{
screen: 'PsbtWithHardwareWallet',
params: {
deepLinkPSBT: file,
},
},
});
]);
}
})
.catch(e => console.warn(e));
@ -63,46 +66,58 @@ class DeeplinkSchemaMatch {
console.log(e);
}
if (isBothBitcoinAndLightning) {
completionHandler({
routeName: 'HandleOffchainAndOnChain',
params: {
onWalletSelect: wallet =>
completionHandler(DeeplinkSchemaMatch.isBothBitcoinAndLightningOnWalletSelect(wallet, isBothBitcoinAndLightning)),
completionHandler([
'HandleOffchainAndOnChain',
{
screen: 'SelectWallet',
params: {
onWalletSelect: wallet =>
completionHandler(DeeplinkSchemaMatch.isBothBitcoinAndLightningOnWalletSelect(wallet, isBothBitcoinAndLightning)),
},
},
});
]);
} else if (DeeplinkSchemaMatch.isBitcoinAddress(event.url) || BitcoinBIP70TransactionDecode.matchesPaymentURL(event.url)) {
completionHandler({
routeName: 'SendDetails',
params: {
uri: event.url,
completionHandler([
'SendDetailsRoot',
{
screen: 'SendDetails',
params: {
uri: event.url,
},
},
});
]);
} else if (DeeplinkSchemaMatch.isLightningInvoice(event.url)) {
completionHandler({
routeName: 'ScanLndInvoice',
params: {
uri: event.url,
completionHandler([
'ScanLndInvoiceRoot',
{
screen: 'ScanLndInvoice',
params: {
uri: event.url,
},
},
});
]);
} else if (DeeplinkSchemaMatch.isLnUrl(event.url)) {
completionHandler({
routeName: 'LNDCreateInvoice',
params: {
uri: event.url,
completionHandler([
'LNDCreateInvoiceRoot',
{
screen: 'LNDCreateInvoice',
params: {
uri: event.url,
},
},
});
]);
} else if (DeeplinkSchemaMatch.isSafelloRedirect(event)) {
let urlObject = url.parse(event.url, true) // eslint-disable-line
const safelloStateToken = urlObject.query['safello-state-token'];
completionHandler({
routeName: 'BuyBitcoin',
params: {
completionHandler([
'BuyBitcoin',
{
uri: event.url,
safelloStateToken,
},
});
]);
} else {
let urlObject = url.parse(event.url, true); // eslint-disable-line
console.log('parsed', urlObject);
@ -155,14 +170,14 @@ class DeeplinkSchemaMatch {
return;
}
completionHandler({
routeName: 'LappBrowser',
params: {
completionHandler([
'LappBrowser',
{
fromSecret: lnWallet.getSecret(),
fromWallet: lnWallet,
url: urlObject.query.url,
},
});
]);
break;
}
}
@ -180,21 +195,21 @@ class DeeplinkSchemaMatch {
static isBothBitcoinAndLightningOnWalletSelect(wallet, uri) {
if (wallet.chain === Chain.ONCHAIN) {
return {
routeName: 'SendDetails',
params: {
return [
'SendDetails',
{
uri: uri.bitcoin,
fromWallet: wallet,
},
};
];
} else if (wallet.chain === Chain.OFFCHAIN) {
return {
routeName: 'ScanLndInvoice',
params: {
return [
'ScanLndInvoice',
{
uri: uri.lndInvoice,
fromSecret: wallet.getSecret(),
},
};
];
}
}

1001
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -3,12 +3,12 @@
"version": "5.3.8",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@babel/core": "^7.9.6",
"@babel/runtime": "^7.9.6",
"@react-native-community/eslint-config": "^0.0.5",
"babel-cli": "^6.26.0",
"babel-eslint": "^10.0.2",
"babel-jest": "^24.9.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.0.1",
"babel-preset-flow": "^6.23.0",
"detox": "^16.4.0",
"eslint": "^6.5.1",
@ -17,10 +17,10 @@
"eslint-plugin-node": "^9.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.14.2",
"flow-bin": "^0.102.0",
"flow-bin": "^0.125.1",
"jest": "^24.9.0",
"jetifier": "^1.6.3",
"metro-react-native-babel-preset": "^0.56.0",
"metro-react-native-babel-preset": "^0.59.0",
"prettier-eslint-cli": "^5.0.0",
"react-test-renderer": "16.9.0",
"rn-nodeify": "github:tradle/rn-nodeify"
@ -62,11 +62,13 @@
]
},
"dependencies": {
"@babel/preset-env": "7.9.5",
"@babel/preset-env": "7.9.6",
"@react-native-community/async-storage": "1.8.1",
"@react-native-community/blur": "3.6.0",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/slider": "2.0.8",
"@react-navigation/native": "5.4.3",
"@react-navigation/stack": "5.4.0",
"@remobile/react-native-qrcode-local-image": "git+https://github.com/BlueWallet/react-native-qrcode-local-image.git",
"@sentry/react-native": "1.3.5",
"amplitude-js": "5.9.0",
@ -138,9 +140,6 @@
"react-native-vector-icons": "6.6.0",
"react-native-watch-connectivity": "0.4.2",
"react-native-webview": "6.11.1",
"react-navigation": "4.3.9",
"react-navigation-hooks": "1.1.0",
"react-navigation-stack": "2.5.1",
"react-test-render": "1.1.2",
"readable-stream": "3.6.0",
"secure-random": "1.1.2",

View file

@ -30,9 +30,9 @@ var webln = {
window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
return new Promise(function(resolve, reject) {
/* nop. intentionally, forever hang promise.
lapp page usually asynchroniously checks payment itself, via ajax,
so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
might change in future */
lapp page usually asynchroniously checks payment itself, via ajax,
so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
might change in future */
});
},
makeInvoice: function(RequestInvoiceArgs) {
@ -90,51 +90,51 @@ bluewalletResponses = {};
webln = {
enable : function () {
window.ReactNativeWebView.postMessage(JSON.stringify({'enable': true}));
return new Promise(function(resolve, reject){
resolve(true);
})
},
getInfo : function () {
window.ReactNativeWebView.postMessage('getInfo');
return new Promise(function(resolve, reject){
reject('not implemented');
})
},
sendPayment: function(paymentRequest) {
window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
return new Promise(function(resolve, reject) {
/* nop. intentionally, forever hang promise.
lapp page usually asynchroniously checks payment itself, via ajax,
so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
might change in future */
});
},
makeInvoice: function (RequestInvoiceArgs) {
var id = Math.random();
window.ReactNativeWebView.postMessage(JSON.stringify({makeInvoice: RequestInvoiceArgs, id: id}));
return new Promise(function(resolve, reject) {
var interval = setInterval(function () {
if (bluewalletResponses[id]) {
clearInterval(interval);
resolve(bluewalletResponses[id]);
}
}, 1000);
});
},
signMessage: function () {
window.ReactNativeWebView.postMessage('signMessage');
return new Promise(function(resolve, reject){
reject('not implemented');
})
},
verifyMessage: function () {
window.ReactNativeWebView.postMessage('verifyMessage');
return new Promise(function(resolve, reject){
reject('not implemented');
})
},
enable : function () {
window.ReactNativeWebView.postMessage(JSON.stringify({'enable': true}));
return new Promise(function(resolve, reject){
resolve(true);
})
},
getInfo : function () {
window.ReactNativeWebView.postMessage('getInfo');
return new Promise(function(resolve, reject){
reject('not implemented');
})
},
sendPayment: function(paymentRequest) {
window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
return new Promise(function(resolve, reject) {
/* nop. intentionally, forever hang promise.
lapp page usually asynchroniously checks payment itself, via ajax,
so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
might change in future */
});
},
makeInvoice: function (RequestInvoiceArgs) {
var id = Math.random();
window.ReactNativeWebView.postMessage(JSON.stringify({makeInvoice: RequestInvoiceArgs, id: id}));
return new Promise(function(resolve, reject) {
var interval = setInterval(function () {
if (bluewalletResponses[id]) {
clearInterval(interval);
resolve(bluewalletResponses[id]);
}
}, 1000);
});
},
signMessage: function () {
window.ReactNativeWebView.postMessage('signMessage');
return new Promise(function(resolve, reject){
reject('not implemented');
})
},
verifyMessage: function () {
window.ReactNativeWebView.postMessage('verifyMessage');
return new Promise(function(resolve, reject){
reject('not implemented');
})
},
};
@ -142,17 +142,17 @@ webln = {
/* listening to events that might come from RN: */
document.addEventListener("message", function(event) {
window.ReactNativeWebView.postMessage("inside webview, received post message: " + event.detail);
var json;
try {
json = JSON.parse(event.detail);
} catch (_) {}
window.ReactNativeWebView.postMessage("inside webview, received post message: " + event.detail);
var json;
try {
json = JSON.parse(event.detail);
} catch (_) {}
if (json && json.bluewalletResponse) {
/* this is an answer to one of our inside-webview calls.
we store it in answers hashmap for someone who cares about it */
bluewalletResponses[json.id] = json.bluewalletResponse
}
if (json && json.bluewalletResponse) {
/* this is an answer to one of our inside-webview calls.
we store it in answers hashmap for someone who cares about it */
bluewalletResponses[json.id] = json.bluewalletResponse
}
}, false);
@ -160,50 +160,50 @@ document.addEventListener("message", function(event) {
function tryToPay(invoice) {
window.ReactNativeWebView.postMessage(JSON.stringify({sendPayment:invoice}));
window.ReactNativeWebView.postMessage(JSON.stringify({sendPayment:invoice}));
}
/* for non-webln compatible pages we do it oldschool,
searching for all bolt11 manually */
searching for all bolt11 manually */
setInterval(function() {
window.ReactNativeWebView.postMessage('interval');
var searchText = "lnbc";
var searchText = "lnbc";
var aTags = document.getElementsByTagName("span");
var i;
for (i = 0; i < aTags.length; i++) {
if (aTags[i].textContent.indexOf(searchText) === 0) {
tryToPay(aTags[i].textContent);
}
}
var aTags = document.getElementsByTagName("span");
var i;
for (i = 0; i < aTags.length; i++) {
if (aTags[i].textContent.indexOf(searchText) === 0) {
tryToPay(aTags[i].textContent);
}
}
/* ------------------------- */
/* ------------------------- */
aTags = document.getElementsByTagName("input");
for (i = 0; i < aTags.length; i++) {
if (aTags[i].value.indexOf(searchText) === 0) {
tryToPay(aTags[i].value);
}
}
aTags = document.getElementsByTagName("input");
for (i = 0; i < aTags.length; i++) {
if (aTags[i].value.indexOf(searchText) === 0) {
tryToPay(aTags[i].value);
}
}
/* ------------------------- */
/* ------------------------- */
aTags = document.getElementsByTagName("a");
searchText = "lightning:lnbc";
aTags = document.getElementsByTagName("a");
searchText = "lightning:lnbc";
for (i = 0; i < aTags.length; i++) {
var href = aTags[i].getAttribute('href') + '';
if (href.indexOf(searchText) === 0) {
tryToPay(href.replace('lightning:', ''));
}
}
for (i = 0; i < aTags.length; i++) {
var href = aTags[i].getAttribute('href') + '';
if (href.indexOf(searchText) === 0) {
tryToPay(href.replace('lightning:', ''));
}
}
}, 1000);
`;
`;
export default class Browser extends Component {
static navigationOptions = ({ navigation }) => ({
@ -214,15 +214,15 @@ export default class Browser extends Component {
constructor(props) {
super(props);
if (!props.navigation.getParam('fromSecret')) throw new Error('Invalid param');
if (!props.navigation.getParam('fromWallet')) throw new Error('Invalid param');
if (!props.route.params.fromSecret) throw new Error('Invalid param');
if (!props.route.params.fromWallet) throw new Error('Invalid param');
let url;
if (props.navigation.getParam('url')) url = props.navigation.getParam('url');
if (props.route.params.url) url = props.route.params.url;
this.state = {
url: url || 'https://bluewallet.io/marketplace/',
fromSecret: props.navigation.getParam('fromSecret'),
fromWallet: props.navigation.getParam('fromWallet'),
fromSecret: props.route.params.fromSecret,
fromWallet: props.route.params.fromWallet,
canGoBack: false,
pageIsLoading: false,
stateURL: url || 'https://bluewallet.io/marketplace/',
@ -280,12 +280,9 @@ export default class Browser extends Component {
text: 'Pay',
onPress: () => {
console.log('OK Pressed');
this.props.navigation.navigate({
routeName: 'ScanLndInvoice',
params: {
uri: json.sendPayment,
fromSecret: this.state.fromSecret,
},
this.props.navigation.navigate('ScanLndInvoice', {
uri: json.sendPayment,
fromSecret: this.state.fromSecret,
});
},
},
@ -459,8 +456,10 @@ export default class Browser extends Component {
Browser.propTypes = {
navigation: PropTypes.shape({
getParam: PropTypes.func,
navigate: PropTypes.func,
goBack: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -39,7 +39,7 @@ export default class LNDCreateInvoice extends Component {
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
let fromWallet;
if (props.navigation.state.params.fromWallet) fromWallet = props.navigation.getParam('fromWallet');
if (props.route.params.fromWallet) fromWallet = props.route.params.fromWallet;
// fallback to first wallet if it exists
if (!fromWallet) {
@ -64,8 +64,8 @@ export default class LNDCreateInvoice extends Component {
renderReceiveDetails = async () => {
this.state.fromWallet.setUserHasSavedExport(true);
await BlueApp.saveToDisk();
if (this.props.navigation.state.params.uri) {
this.processLnurl(this.props.navigation.getParam('uri'));
if (this.props.route.params.uri) {
this.processLnurl(this.props.route.params.uri);
}
this.setState({ isLoading: false });
};
@ -77,7 +77,7 @@ export default class LNDCreateInvoice extends Component {
BlueAlertWalletExportReminder({
onSuccess: this.renderReceiveDetails,
onFailure: () => {
this.props.navigation.dismiss();
this.props.navigation.dangerouslyGetParent().pop();
this.props.navigation.navigate('WalletExport', {
wallet: this.state.fromWallet,
});
@ -211,7 +211,7 @@ export default class LNDCreateInvoice extends Component {
onPress={() => {
NavigationService.navigate('ScanQRCode', {
onBarScanned: this.processLnurl,
launchedBy: this.props.navigation.state.routeName,
launchedBy: this.props.route.name,
});
Keyboard.dismiss();
}}
@ -349,16 +349,15 @@ export default class LNDCreateInvoice extends Component {
LNDCreateInvoice.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
dismiss: PropTypes.func,
dangerouslyGetParent: PropTypes.func,
navigate: PropTypes.func,
getParam: PropTypes.func,
pop: PropTypes.func,
state: PropTypes.shape({
routeName: PropTypes.string,
params: PropTypes.shape({
uri: PropTypes.string,
fromWallet: PropTypes.shape({}),
}),
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
uri: PropTypes.string,
fromWallet: PropTypes.shape({}),
}),
}),
};

View file

@ -25,7 +25,7 @@ export default class LNDViewAdditionalInvoiceInformation extends Component {
state = { walletInfo: undefined };
async componentDidMount() {
const fromWallet = this.props.navigation.getParam('fromWallet');
const fromWallet = this.props.route.params.fromWallet;
try {
await fromWallet.fetchInfo();
} catch (_) {
@ -84,7 +84,9 @@ export default class LNDViewAdditionalInvoiceInformation extends Component {
LNDViewAdditionalInvoiceInformation.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
getParam: PropTypes.func,
dismiss: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -22,10 +22,10 @@ const EV = require('../../events');
const { width, height } = Dimensions.get('window');
export default class LNDViewInvoice extends Component {
static navigationOptions = ({ navigation }) =>
navigation.getParam('isModal') === true
static navigationOptions = ({ navigation, route }) =>
route.params.isModal === true
? {
...BlueNavigationStyle(navigation, true, () => navigation.dismiss()),
...BlueNavigationStyle(navigation, true, () => navigation.dangerouslyGetParent().pop()),
title: 'Lightning Invoice',
headerLeft: null,
}
@ -33,8 +33,8 @@ export default class LNDViewInvoice extends Component {
constructor(props) {
super(props);
const invoice = props.navigation.getParam('invoice');
const fromWallet = props.navigation.getParam('fromWallet');
const invoice = props.route.params.invoice;
const fromWallet = props.route.params.fromWallet;
this.state = {
invoice,
fromWallet,
@ -323,7 +323,9 @@ LNDViewInvoice.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
navigate: PropTypes.func,
getParam: PropTypes.func,
popToTop: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -42,10 +42,10 @@ export default class ScanLndInvoice extends React.Component {
if (!BlueApp.getWallets().some(item => item.type === LightningCustodianWallet.type)) {
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
alert('Before paying a Lightning invoice, you must first add a Lightning wallet.');
props.navigation.dismiss();
props.navigation.dangerouslyGetParent().pop();
} else {
let fromSecret;
if (props.navigation.state.params.fromSecret) fromSecret = props.navigation.state.params.fromSecret;
if (props.route.params.fromSecret) fromSecret = props.route.params.fromSecret;
let fromWallet = {};
if (!fromSecret) {
@ -72,8 +72,8 @@ export default class ScanLndInvoice extends React.Component {
}
static getDerivedStateFromProps(props, state) {
if (props.navigation.state.params.uri) {
let data = props.navigation.state.params.uri;
if (props.route.params.uri) {
let data = props.route.params.uri;
// handling BIP21 w/BOLT11 support
let ind = data.indexOf('lightning=');
if (ind !== -1) {
@ -290,7 +290,7 @@ export default class ScanLndInvoice extends React.Component {
isLoading={this.state.isLoading}
placeholder={loc.lnd.placeholder}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
launchedBy={this.props.navigation.state.routeName}
launchedBy={this.props.route.name}
/>
<View
style={{
@ -340,15 +340,14 @@ ScanLndInvoice.propTypes = {
goBack: PropTypes.func,
navigate: PropTypes.func,
pop: PropTypes.func,
getParam: PropTypes.func,
setParams: PropTypes.func,
dismiss: PropTypes.func,
state: PropTypes.shape({
routeName: PropTypes.string,
params: PropTypes.shape({
uri: PropTypes.string,
fromSecret: PropTypes.string,
}),
dangerouslyGetParent: PropTypes.func,
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
uri: PropTypes.string,
fromSecret: PropTypes.string,
}),
}),
};

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState, useCallback } from 'react';
import { View, InteractionManager, Platform, TextInput, KeyboardAvoidingView, Keyboard, StyleSheet, ScrollView } from 'react-native';
import QRCode from 'react-native-qrcode-svg';
import { useNavigation, useNavigationParam } from 'react-navigation-hooks';
import { useNavigation, useRoute } from '@react-navigation/native';
import {
BlueLoading,
SafeBlueArea,
@ -27,7 +27,7 @@ const BlueApp = require('../../BlueApp');
const loc = require('../../loc');
const ReceiveDetails = () => {
const secret = useNavigationParam('secret');
const { secret } = useRoute().params;
const [wallet, setWallet] = useState();
const [isHandOffUseEnabled, setIsHandOffUseEnabled] = useState(false);
const [address, setAddress] = useState('');

View file

@ -5,21 +5,18 @@ import { RNCamera } from 'react-native-camera';
import { Icon } from 'react-native-elements';
import ImagePicker from 'react-native-image-picker';
import PropTypes from 'prop-types';
import { useNavigationParam, useNavigation } from 'react-navigation-hooks';
import { useNavigation, useRoute } from '@react-navigation/native';
import DocumentPicker from 'react-native-document-picker';
import RNFS from 'react-native-fs';
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const createHash = require('create-hash');
const ScanQRCode = ({
showCloseButton = true,
// eslint-disable-next-line react-hooks/rules-of-hooks
showFileImportButton = useNavigationParam('showFileImportButton') || false,
}) => {
const ScanQRCode = ({ showCloseButton = true, showFileImportButton: showFileImportButtonProps }) => {
const [isLoading, setIsLoading] = useState(false);
const { navigate } = useNavigation();
const launchedBy = useNavigationParam('launchedBy');
const onBarScanned = useNavigationParam('onBarScanned');
const route = useRoute();
const showFileImportButton = showFileImportButtonProps || route.params.showFileImportButton || false;
const { launchedBy, onBarScanned } = route.params;
const scannedCache = {};
const HashIt = function(s) {
@ -173,7 +170,7 @@ const ScanQRCode = ({
};
ScanQRCode.navigationOptions = {
header: null,
headerShown: false,
};
ScanQRCode.propTypes = {
showFileImportButton: PropTypes.bool,

View file

@ -36,14 +36,14 @@ export default class Confirm extends Component {
this.state = {
isLoading: false,
fee: props.navigation.getParam('fee'),
feeSatoshi: new Bignumber(props.navigation.getParam('fee')).multipliedBy(100000000).toNumber(),
memo: props.navigation.getParam('memo'),
recipients: props.navigation.getParam('recipients'),
size: Math.round(props.navigation.getParam('tx').length / 2),
tx: props.navigation.getParam('tx'),
satoshiPerByte: props.navigation.getParam('satoshiPerByte'),
fromWallet: props.navigation.getParam('fromWallet'),
fee: props.route.params.fee,
feeSatoshi: new Bignumber(props.route.params.fee).multipliedBy(100000000).toNumber(),
memo: props.route.params.memo,
recipients: props.route.params.recipients,
size: Math.round(props.route.params.tx.length / 2),
tx: props.route.params.tx,
satoshiPerByte: props.route.params.satoshiPerByte,
fromWallet: props.route.params.fromWallet,
};
}
@ -100,7 +100,7 @@ export default class Confirm extends Component {
this.props.navigation.navigate('Success', {
fee: Number(this.state.fee),
amount,
dismissModal: () => this.props.navigation.dismiss(),
dismissModal: () => this.props.navigation.dangerouslyGetParent().pop(),
});
this.setState({ isLoading: false });
}
@ -244,20 +244,10 @@ const styles = StyleSheet.create({
Confirm.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
getParam: PropTypes.func,
navigate: PropTypes.func,
dismiss: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
amount: PropTypes.string,
fee: PropTypes.number,
address: PropTypes.string,
memo: PropTypes.string,
fromWallet: PropTypes.shape({
fromAddress: PropTypes.string,
fromSecret: PropTypes.string,
}),
}),
}),
dangerouslyGetParent: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -28,14 +28,16 @@ const loc = require('../../loc');
const currency = require('../../currency');
export default class SendCreate extends Component {
static navigationOptions = ({ navigation }) => ({
static navigationOptions = ({ navigation, route }) => ({
...BlueNavigationStyle,
title: loc.send.create.details,
headerRight: navigation.state.params.exportTXN ? (
<TouchableOpacity style={{ marginRight: 16 }} onPress={navigation.state.params.exportTXN}>
<Icon size={22} name="share-alternative" type="entypo" color={BlueApp.settings.foregroundColor} />
</TouchableOpacity>
) : null,
headerRight: route.params.exportTXN
? () => (
<TouchableOpacity style={{ marginRight: 16 }} onPress={route.params.exportTXN}>
<Icon size={22} name="share-alternative" type="entypo" color={BlueApp.settings.foregroundColor} />
</TouchableOpacity>
)
: null,
});
constructor(props) {
@ -44,14 +46,14 @@ export default class SendCreate extends Component {
props.navigation.setParams({ exportTXN: this.exportTXN });
this.state = {
isLoading: false,
fee: props.navigation.getParam('fee'),
recipients: props.navigation.getParam('recipients'),
memo: props.navigation.getParam('memo') || '',
size: Math.round(props.navigation.getParam('tx').length / 2),
tx: props.navigation.getParam('tx'),
satoshiPerByte: props.navigation.getParam('satoshiPerByte'),
wallet: props.navigation.getParam('wallet'),
feeSatoshi: props.navigation.getParam('feeSatoshi'),
fee: props.route.params.fee,
recipients: props.route.params.recipients,
memo: props.route.params.memo || '',
size: Math.round(props.route.params.tx.length / 2),
tx: props.route.params.tx,
satoshiPerByte: props.route.params.satoshiPerByte,
wallet: props.route.params.wallet,
feeSatoshi: props.route.params.feeSatoshi,
};
}
@ -209,16 +211,10 @@ SendCreate.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
setParams: PropTypes.func,
getParam: PropTypes.func,
navigate: PropTypes.func,
dismiss: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
amount: PropTypes.string,
fee: PropTypes.number,
address: PropTypes.string,
memo: PropTypes.string,
}),
}),
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -50,12 +50,8 @@ let loc = require('../../loc');
const btcAddressRx = /^[a-zA-Z0-9]{26,35}$/;
export default class SendDetails extends Component {
static navigationOptions = ({ navigation }) => ({
...BlueCreateTxNavigationStyle(
navigation,
navigation.state.params.withAdvancedOptionsMenuButton,
navigation.state.params.advancedOptionsMenuButtonAction,
),
static navigationOptions = ({ navigation, route }) => ({
...BlueCreateTxNavigationStyle(navigation, route.params.withAdvancedOptionsMenuButton, route.params.advancedOptionsMenuButtonAction),
title: loc.send.header,
});
@ -69,7 +65,7 @@ export default class SendDetails extends Component {
/** @type {LegacyWallet} */
let fromWallet = null;
if (props.navigation.state.params) fromWallet = props.navigation.state.params.fromWallet;
if (props.route.params) fromWallet = props.route.params.fromWallet;
const wallets = BlueApp.getWallets().filter(wallet => wallet.type !== LightningCustodianWallet.type);
@ -179,8 +175,8 @@ export default class SendDetails extends Component {
StatusBar.setBarStyle('dark-content');
let addresses = [];
let initialMemo = '';
if (this.props.navigation.state.params.uri) {
const uri = this.props.navigation.state.params.uri;
if (this.props.route.params.uri) {
const uri = this.props.route.params.uri;
if (BitcoinBIP70TransactionDecode.matchesPaymentURL(uri)) {
const { recipient, memo, fee, feeSliderValue } = await this.processBIP70Invoice(uri);
addresses.push(recipient);
@ -197,9 +193,9 @@ export default class SendDetails extends Component {
alert('Error: Unable to decode Bitcoin address');
}
}
} else if (this.props.navigation.state.params.address) {
addresses.push(new BitcoinTransaction(this.props.navigation.state.params.address));
if (this.props.navigation.state.params.memo) initialMemo = this.props.navigation.state.params.memo;
} else if (this.props.route.params.address) {
addresses.push(new BitcoinTransaction(this.props.route.params.address));
if (this.props.route.params.memo) initialMemo = this.props.route.params.memo;
this.setState({ addresses, memo: initialMemo, isLoading: false });
} else {
this.setState({ addresses: [new BitcoinTransaction()], isLoading: false });
@ -227,12 +223,12 @@ export default class SendDetails extends Component {
feeSliderValue: recommendedFees.fastestFee,
});
if (this.props.navigation.state.params.uri) {
if (BitcoinBIP70TransactionDecode.matchesPaymentURL(this.props.navigation.state.params.uri)) {
this.processBIP70Invoice(this.props.navigation.state.params.uri);
if (this.props.route.params.uri) {
if (BitcoinBIP70TransactionDecode.matchesPaymentURL(this.props.route.params.uri)) {
this.processBIP70Invoice(this.props.route.params.uri);
} else {
try {
const { address, amount, memo } = this.decodeBitcoinUri(this.props.navigation.getParam('uri'));
const { address, amount, memo } = this.decodeBitcoinUri(this.props.route.params.uri);
this.setState({ address, amount, memo, isLoading: false });
} catch (error) {
console.log(error);
@ -822,7 +818,7 @@ export default class SendDetails extends Component {
address={item.address}
isLoading={this.state.isLoading}
inputAccessoryViewID={BlueDismissKeyboardInputAccessory.InputAccessoryViewID}
launchedBy={this.props.navigation.state.routeName}
launchedBy={this.props.route.name}
/>
{this.state.addresses.length > 1 && (
<BlueText style={{ alignSelf: 'flex-end', marginRight: 18, marginVertical: 8 }}>
@ -995,18 +991,17 @@ SendDetails.propTypes = {
pop: PropTypes.func,
goBack: PropTypes.func,
navigate: PropTypes.func,
getParam: PropTypes.func,
setParams: PropTypes.func,
state: PropTypes.shape({
routeName: PropTypes.string,
params: PropTypes.shape({
amount: PropTypes.number,
address: PropTypes.string,
satoshiPerByte: PropTypes.string,
fromWallet: PropTypes.fromWallet,
memo: PropTypes.string,
uri: PropTypes.string,
}),
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
amount: PropTypes.number,
address: PropTypes.string,
satoshiPerByte: PropTypes.string,
fromWallet: PropTypes.fromWallet,
memo: PropTypes.string,
uri: PropTypes.string,
}),
}),
};

View file

@ -75,20 +75,20 @@ export default class PsbtWithHardwareWallet extends Component {
isLoading: false,
renderScanner: false,
qrCodeHeight: height > width ? width - 40 : width / 3,
memo: props.navigation.getParam('memo'),
psbt: props.navigation.getParam('psbt'),
fromWallet: props.navigation.getParam('fromWallet'),
isFirstPSBTAlreadyBase64: props.navigation.getParam('isFirstPSBTAlreadyBase64'),
memo: props.route.params.memo,
psbt: props.route.params.psbt,
fromWallet: props.route.params.fromWallet,
isFirstPSBTAlreadyBase64: props.route.params.isFirstPSBTAlreadyBase64,
isSecondPSBTAlreadyBase64: false,
deepLinkPSBT: undefined,
txhex: props.navigation.getParam('txhex') || undefined,
txhex: props.route.params.txhex || undefined,
};
this.fileName = `${Date.now()}.psbt`;
}
static getDerivedStateFromProps(nextProps, prevState) {
const deepLinkPSBT = nextProps.navigation.state.params.deepLinkPSBT;
const txhex = nextProps.navigation.state.params.txhex;
const deepLinkPSBT = nextProps.props.route.params.deepLinkPSBT;
const txhex = nextProps.props.route.params.txhex;
if (deepLinkPSBT) {
try {
let Tx = prevState.fromWallet.combinePsbt(
@ -182,7 +182,7 @@ export default class PsbtWithHardwareWallet extends Component {
<SafeBlueArea style={{ flex: 1 }}>
<BlueBigCheckmark style={{ marginTop: 143, marginBottom: 53 }} />
<BlueCard>
<BlueButton onPress={this.props.navigation.dismiss} title={loc.send.success.done} />
<BlueButton onPress={this.props.navigation.dangerouslyGetParent().pop} title={loc.send.success.done} />
</BlueCard>
</SafeBlueArea>
);
@ -352,17 +352,10 @@ export default class PsbtWithHardwareWallet extends Component {
PsbtWithHardwareWallet.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
getParam: PropTypes.func,
navigate: PropTypes.func,
dismiss: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
memo: PropTypes.string,
fromWallet: PropTypes.shape({
fromAddress: PropTypes.string,
fromSecret: PropTypes.string,
}),
}),
}),
dangerouslyGetParent: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -9,7 +9,7 @@ let loc = require('../../loc');
export default class Success extends Component {
static navigationOptions = {
header: null,
headerShown: false,
gesturesEnabled: false,
};
@ -18,10 +18,10 @@ export default class Success extends Component {
console.log('send/success constructor');
this.state = {
amount: props.navigation.getParam('amount'),
fee: props.navigation.getParam('fee') || 0,
amountUnit: props.navigation.getParam('amountUnit') || BitcoinUnit.BTC,
invoiceDescription: props.navigation.getParam('invoiceDescription') || '',
amount: props.route.params.amount,
fee: props.route.params.fee || 0,
amountUnit: props.route.params.amountUnit || BitcoinUnit.BTC,
invoiceDescription: props.route.params.invoiceDescription || '',
};
}
@ -104,7 +104,7 @@ export default class Success extends Component {
<BlueCard>
<BlueButton
onPress={() => {
this.props.navigation.dismiss();
this.props.navigation.dangerouslyGetParent().pop();
}}
title={loc.send.success.done}
/>
@ -117,9 +117,8 @@ export default class Success extends Component {
Success.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
getParam: PropTypes.func,
navigate: PropTypes.func,
dismiss: PropTypes.func,
dangerouslyGetParent: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
amount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
@ -127,4 +126,7 @@ Success.propTypes = {
}),
}),
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -3,7 +3,7 @@ import { ScrollView, Platform, TouchableWithoutFeedback, TouchableOpacity } from
import { BlueLoading, BlueText, BlueSpacing20, BlueListItem, SafeBlueArea, BlueNavigationStyle, BlueCard } from '../../BlueComponents';
import PropTypes from 'prop-types';
import { AppStorage } from '../../class';
import { useNavigation } from 'react-navigation-hooks';
import { useNavigation } from '@react-navigation/native';
import HandoffSettings from '../../class/handoff';
let BlueApp: AppStorage = require('../../BlueApp');
let loc = require('../../loc');

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { ScrollView, TouchableOpacity } from 'react-native';
import { BlueNavigationStyle, BlueLoading, SafeBlueArea, BlueListItem } from '../../BlueComponents';
import { useNavigation } from 'react-navigation-hooks';
import { useNavigation } from '@react-navigation/native';
const loc = require('../../loc');
const NetworkSettings = () => {

View file

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { ScrollView, Linking, Dimensions, Image, View, Text } from 'react-native';
import { useNavigation } from 'react-navigation-hooks';
import { useNavigation } from '@react-navigation/native';
import {
BlueTextCentered,
BlueLoading,

View file

@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
import { TouchableOpacity, View, TouchableWithoutFeedback } from 'react-native';
import { SafeBlueArea, BlueCard, BlueText, BlueNavigationStyle, BlueListItem } from '../../BlueComponents';
import OnAppLaunch from '../../class/onAppLaunch';
import { useNavigation } from 'react-navigation-hooks';
import { useNavigation } from '@react-navigation/native';
const BlueApp = require('../../BlueApp');
const DefaultView = () => {

View file

@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import { ScrollView, TouchableOpacity } from 'react-native';
import { BlueNavigationStyle, BlueLoading, SafeBlueArea, BlueHeaderDefaultSub, BlueListItem } from '../../BlueComponents';
import { useNavigation } from 'react-navigation-hooks';
import { useNavigation } from '@react-navigation/native';
const loc = require('../../loc');
const Settings = () => {

View file

@ -33,8 +33,8 @@ export default class CPFP extends Component {
super(props);
let txid;
let wallet;
if (props.navigation.state.params) txid = props.navigation.state.params.txid;
if (props.navigation.state.params) wallet = props.navigation.state.params.wallet;
if (props.route.params) txid = props.route.params.txid;
if (props.route.params) wallet = props.route.params.wallet;
this.state = {
isLoading: true,
@ -230,11 +230,11 @@ CPFP.propTypes = {
navigation: PropTypes.shape({
popToTop: PropTypes.func,
navigate: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
txid: PropTypes.string,
wallet: PropTypes.object,
}),
}),
route: PropTypes.shape({
params: PropTypes.shape({
txid: PropTypes.string,
wallet: PropTypes.object,
}),
}),
};

View file

@ -39,7 +39,7 @@ export default class TransactionsDetails extends Component {
constructor(props) {
super(props);
let hash = props.navigation.state.params.hash;
let hash = props.route.params.hash;
let foundTx = {};
let from = [];
let to = [];
@ -203,10 +203,11 @@ TransactionsDetails.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
navigate: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
hash: PropTypes.string,
}),
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
hash: PropTypes.string,
}),
}),
};

View file

@ -35,7 +35,7 @@ export default class TransactionsStatus extends Component {
constructor(props) {
super(props);
let hash = props.navigation.state.params.hash;
let hash = props.route.params.hash;
let foundTx = {};
let from = [];
let to = [];
@ -358,4 +358,7 @@ TransactionsStatus.propTypes = {
}),
}),
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -340,7 +340,7 @@ export default class WalletsAdd extends Component {
secret: w.getSecret(),
});
} else {
this.props.navigation.dismiss();
this.props.navigation.goBack();
}
}
});
@ -370,6 +370,5 @@ WalletsAdd.propTypes = {
navigation: PropTypes.shape({
navigate: PropTypes.func,
goBack: PropTypes.func,
dismiss: PropTypes.func,
}),
};

View file

@ -16,7 +16,7 @@ export default class BuyBitcoin extends Component {
constructor(props) {
super(props);
let wallet = props.navigation.state.params.wallet;
let wallet = props.route.params.wallet;
if (!wallet) console.warn('wallet was not passed to buyBitcoin');
this.state = {
@ -77,7 +77,7 @@ export default class BuyBitcoin extends Component {
return <BlueLoading />;
}
const { safelloStateToken } = this.props.navigation.state.params;
const { safelloStateToken } = this.props.route.params;
let uri = 'https://bluewallet.io/buy-bitcoin-redirect.html?address=' + this.state.address;
@ -104,11 +104,12 @@ export default class BuyBitcoin extends Component {
BuyBitcoin.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
wallet: PropTypes.object.isRequired,
safelloStateToken: PropTypes.string,
}),
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
wallet: PropTypes.object.isRequired,
safelloStateToken: PropTypes.string,
}),
}),
};

View file

@ -31,16 +31,16 @@ const BlueApp = require('../../BlueApp');
const loc = require('../../loc');
export default class WalletDetails extends Component {
static navigationOptions = ({ navigation }) => ({
static navigationOptions = ({ navigation, route }) => ({
...BlueNavigationStyle(),
title: loc.wallets.details.title,
headerRight: (
headerRight: () => (
<TouchableOpacity
disabled={navigation.getParam('isLoading') === true}
disabled={route.params.isLoading === true}
style={{ marginHorizontal: 16, justifyContent: 'center', alignItems: 'center' }}
onPress={() => {
if (navigation.state.params.saveAction) {
navigation.getParam('saveAction')();
if (route.params.saveAction) {
route.params.saveAction();
}
}}
>
@ -52,7 +52,7 @@ export default class WalletDetails extends Component {
constructor(props) {
super(props);
const wallet = props.navigation.getParam('wallet');
const wallet = props.route.params.wallet;
const isLoading = true;
this.state = {
isLoading,
@ -333,7 +333,6 @@ export default class WalletDetails extends Component {
WalletDetails.propTypes = {
navigation: PropTypes.shape({
getParam: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
secret: PropTypes.string,
@ -343,4 +342,7 @@ WalletDetails.propTypes = {
goBack: PropTypes.func,
setParams: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -20,7 +20,7 @@ export default class WalletExport extends Component {
constructor(props) {
super(props);
let wallet = props.navigation.state.params.wallet;
let wallet = props.route.params.wallet;
this.state = {
isLoading: true,
qrCodeHeight: height > width ? width - 40 : width / 2,
@ -111,12 +111,13 @@ export default class WalletExport extends Component {
WalletExport.propTypes = {
navigation: PropTypes.shape({
state: PropTypes.shape({
params: PropTypes.shape({
wallet: PropTypes.object.isRequired,
}),
}),
navigate: PropTypes.func,
goBack: PropTypes.func,
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
wallet: PropTypes.object.isRequired,
}),
}),
};

View file

@ -166,7 +166,7 @@ export default class HodlHodl extends Component {
constructor(props) {
super(props);
/** @type {AbstractWallet} */
let wallet = props.navigation.state.params.wallet;
let wallet = props.route.params.wallet;
this.state = {
isLoading: true,
@ -911,10 +911,10 @@ export default class HodlHodl extends Component {
HodlHodl.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
state: PropTypes.shape({
params: PropTypes.shape({
wallet: PropTypes.object,
}),
}),
route: PropTypes.shape({
params: PropTypes.shape({
wallet: PropTypes.object,
}),
}),
};

View file

@ -13,15 +13,16 @@ import {
} from '../../BlueComponents';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Privacy from '../../Privacy';
import { useNavigation, useNavigationParam } from 'react-navigation-hooks';
import { useNavigation, useRoute } from '@react-navigation/native';
import WalletImport from '../../class/walletImport';
let loc = require('../../loc');
const { width } = Dimensions.get('window');
const WalletsImport = () => {
const [isToolbarVisibleForAndroid, setIsToolbarVisibleForAndroid] = useState(false);
const [importText, setImportText] = useState(useNavigationParam('label') || '');
const { navigate, dismiss } = useNavigation();
const { label } = useRoute().params;
const [importText, setImportText] = useState(label || '');
const navigation = useNavigation();
useEffect(() => {
Privacy.enableBlur();
@ -49,7 +50,7 @@ const WalletsImport = () => {
const importMnemonic = (importText, additionalProperties) => {
try {
WalletImport.processImportText(importText, additionalProperties);
dismiss();
navigation.dangerouslyGetParent().pop();
} catch (error) {
alert(loc.wallets.import.error);
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
@ -93,7 +94,7 @@ const WalletsImport = () => {
<BlueButtonLink
title={loc.wallets.import.scan_qr}
onPress={() => {
navigate('ScanQRCode', { launchedBy: 'ImportWallet', onBarScanned, showFileImportButton: true });
navigation.navigate('ScanQRCode', { launchedBy: 'ImportWallet', onBarScanned, showFileImportButton: true });
}}
/>
</View>

View file

@ -2,7 +2,6 @@ import React, { Component } from 'react';
import { View, TouchableOpacity, Text, StyleSheet, InteractionManager, RefreshControl, SectionList, Alert, Platform } from 'react-native';
import { BlueScanButton, WalletsCarousel, BlueHeaderDefaultMain, BlueTransactionListItem } from '../../BlueComponents';
import { Icon } from 'react-native-elements';
import { NavigationEvents } from 'react-navigation';
import DeeplinkSchemaMatch from '../../class/deeplink-schema-match';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import PropTypes from 'prop-types';
@ -59,10 +58,13 @@ export default class WalletsList extends Component {
this.setState(prev => ({ timeElapsed: prev.timeElapsed + 1 }));
}, 60000);
this.redrawScreen();
this._unsubscribe = this.props.navigation.addListener('focus', this.redrawScreen);
}
componentWillUnmount() {
clearInterval(this.interval);
this._unsubscribe();
}
/**
@ -178,7 +180,7 @@ export default class WalletsList extends Component {
} else {
// if its out of index - this must be last card with incentive to create wallet
if (!BlueApp.getWallets().some(wallet => wallet.type === PlaceholderWallet.type)) {
this.props.navigation.navigate('AddWallet');
this.props.navigation.navigate('AddWalletRoot');
}
}
};
@ -370,7 +372,7 @@ export default class WalletsList extends Component {
leftText={loc.wallets.list.title}
onNewWalletPress={
!BlueApp.getWallets().some(wallet => wallet.type === PlaceholderWallet.type)
? () => this.props.navigation.navigate('AddWallet')
? () => this.props.navigation.navigate('AddWalletRoot')
: null
}
/>
@ -446,7 +448,7 @@ export default class WalletsList extends Component {
onScanButtonPressed = () => {
this.props.navigation.navigate('ScanQRCode', {
launchedBy: this.props.navigation.state.routeName,
launchedBy: this.props.route.name,
onBarScanned: this.onBarScanned,
showFileImportButton: false,
});
@ -462,11 +464,6 @@ export default class WalletsList extends Component {
render() {
return (
<View style={{ flex: 1 }}>
<NavigationEvents
onDidFocus={() => {
this.redrawScreen();
}}
/>
<View style={styles.walletsListWrapper}>
{this.renderNavigationHeader()}
<SectionList
@ -519,9 +516,11 @@ const styles = StyleSheet.create({
WalletsList.propTypes = {
navigation: PropTypes.shape({
state: PropTypes.shape({
routeName: PropTypes.string,
}),
navigate: PropTypes.func,
addListener: PropTypes.func,
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.object,
}),
};

View file

@ -15,8 +15,8 @@ export default class Marketplace extends Component {
constructor(props) {
super(props);
if (!props.navigation.getParam('fromWallet')) throw new Error('Invalid param');
let fromWallet = props.navigation.getParam('fromWallet');
if (!props.route.params.fromWallet) throw new Error('Invalid param');
let fromWallet = props.route.params.fromWallet;
this.state = {
url: '',
@ -73,8 +73,10 @@ export default class Marketplace extends Component {
Marketplace.propTypes = {
navigation: PropTypes.shape({
getParam: PropTypes.func,
navigate: PropTypes.func,
goBack: PropTypes.func,
}),
route: PropTypes.shape({
params: PropTypes.object,
}),
};

View file

@ -1,19 +1,20 @@
import React, { useEffect, useState, useCallback } from 'react';
import { ActivityIndicator, View, BackHandler, Text, ScrollView } from 'react-native';
import { useNavigation, useRoute } from '@react-navigation/native';
import { BlueSpacing20, SafeBlueArea, BlueNavigationStyle, BlueText, BlueButton } from '../../BlueComponents';
import Privacy from '../../Privacy';
import { useNavigation, useNavigationParam } from 'react-navigation-hooks';
const loc = require('../../loc');
const PleaseBackup = () => {
const [isLoading, setIsLoading] = useState(true);
const words = useNavigationParam('secret').split(' ');
const { dismiss } = useNavigation();
const route = useRoute();
const words = route.params.secret.split(' ');
const navigation = useNavigation();
const handleBackButton = useCallback(() => {
dismiss();
navigation.dangerouslyGetParent().pop();
return true;
}, [dismiss]);
}, [navigation]);
useEffect(() => {
Privacy.enableBlur();
@ -77,7 +78,7 @@ const PleaseBackup = () => {
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', flexWrap: 'wrap' }}>
<View style={{ flex: 1 }}>
<BlueSpacing20 />
<BlueButton testID="PleasebackupOk" onPress={dismiss} title={loc.pleasebackup.ok} />
<BlueButton testID="PleasebackupOk" onPress={handleBackButton} title={loc.pleasebackup.ok} />
</View>
</View>
</View>

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { useNavigation, useNavigationParam } from 'react-navigation-hooks';
import { useNavigation, useRoute } from '@react-navigation/native';
import { View, Dimensions } from 'react-native';
import { SafeBlueArea, BlueSpacing20, BlueCopyTextToClipboard, BlueButton, BlueCard, BlueTextCentered } from '../../BlueComponents';
import QRCode from 'react-native-qrcode-svg';
@ -8,7 +8,7 @@ const { height, width } = Dimensions.get('window');
const BlueApp = require('../../BlueApp');
const PleaseBackupLNDHub = () => {
const wallet = useNavigationParam('wallet');
const { wallet } = useRoute().params;
const navigation = useNavigation();
const [qrCodeHeight, setQrCodeHeight] = useState(height > width ? width - 40 : width / 2);
@ -41,7 +41,7 @@ const PleaseBackupLNDHub = () => {
<BlueSpacing20 />
<BlueCopyTextToClipboard text={wallet.secret} />
<BlueSpacing20 />
<BlueButton onPress={navigation.dismiss} title="OK, I have saved it." />
<BlueButton onPress={() => navigation.dangerouslyGetParent().pop()} title="OK, I have saved it." />
</BlueCard>
</ScrollView>
</SafeBlueArea>

View file

@ -13,13 +13,13 @@ let BlueApp = require('../../BlueApp');
let loc = require('../../loc/');
export default class ReorderWallets extends Component {
static navigationOptions = ({ navigation }) => ({
static navigationOptions = ({ navigation, route }) => ({
...BlueNavigationStyle(
navigation,
true,
navigation.getParam('customCloseButtonFunction') ? navigation.state.params.customCloseButtonFunction : undefined,
route.params && route.params.customCloseButtonFunction ? route.params.customCloseButtonFunction : undefined,
),
title: loc.wallets.reorder.title,
headerTitle: loc.wallets.reorder.title,
});
constructor(props) {
@ -44,9 +44,9 @@ export default class ReorderWallets extends Component {
setTimeout(function() {
EV(EV.enum.WALLETS_COUNT_CHANGED);
}, 500); // adds some animaton
this.props.navigation.dismiss();
this.props.navigation.goBack();
} else {
this.props.navigation.dismiss();
this.props.navigation.goBack();
}
},
});
@ -180,6 +180,6 @@ ReorderWallets.propTypes = {
navigation: PropTypes.shape({
navigate: PropTypes.func,
setParams: PropTypes.func,
dismiss: PropTypes.func,
goBack: PropTypes.func,
}),
};

View file

@ -6,14 +6,13 @@ import LinearGradient from 'react-native-linear-gradient';
import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import WalletGradient from '../../class/walletGradient';
import { useNavigationParam } from 'react-navigation-hooks';
import { useRoute } from '@react-navigation/native';
/** @type {AppStorage} */
const BlueApp = require('../../BlueApp');
const loc = require('../../loc');
const SelectWallet = () => {
const chainType = useNavigationParam('chainType');
const onWalletSelect = useNavigationParam('onWalletSelect');
const { chainType, onWalletSelect } = useRoute().params;
const [isLoading, setIsLoading] = useState(true);
const data = chainType
? BlueApp.getWallets().filter(item => item.chain === chainType && item.allowSend())

View file

@ -20,7 +20,6 @@ import {
Clipboard,
} from 'react-native';
import PropTypes from 'prop-types';
import { NavigationEvents } from 'react-navigation';
import ImagePicker from 'react-native-image-picker';
import {
BlueSendButtonIcon,
@ -46,28 +45,34 @@ let BlueElectrum = require('../../BlueElectrum');
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
export default class WalletTransactions extends Component {
static navigationOptions = ({ navigation }) => {
static navigationOptions = ({ navigation, route }) => {
// route.params.isLoading
console.log('route.params.isLoading123321', route.params.isLoading);
// return {}
return {
headerRight: (
headerRight: () => (
<TouchableOpacity
disabled={navigation.getParam('isLoading') === true}
disabled={route.params.isLoading === true}
style={{ marginHorizontal: 16, minWidth: 150, justifyContent: 'center', alignItems: 'flex-end' }}
onPress={() =>
navigation.navigate('WalletDetails', {
wallet: navigation.state.params.wallet,
wallet: route.params.wallet,
})
}
>
<Icon name="kebab-horizontal" type="octicon" size={22} color="#FFFFFF" />
</TouchableOpacity>
),
headerTitle: () => null,
headerStyle: {
backgroundColor: WalletGradient.headerColorFor(navigation.state.params.wallet.type),
backgroundColor: WalletGradient.headerColorFor(route.params.wallet.type),
borderBottomWidth: 0,
elevation: 0,
shadowRadius: 0,
// shadowRadius: 0,
shadowOffset: { height: 0, width: 0 },
},
headerTintColor: '#FFFFFF',
headerBackTitleVisible: false,
};
};
@ -78,7 +83,7 @@ export default class WalletTransactions extends Component {
// here, when we receive REMOTE_TRANSACTIONS_COUNT_CHANGED we fetch TXs and balance for current wallet
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED, this.refreshTransactionsFunction.bind(this));
const wallet = props.navigation.getParam('wallet');
const wallet = props.route.params.wallet;
this.props.navigation.setParams({ wallet: wallet, isLoading: true });
this.state = {
isHandOffUseEnabled: false,
@ -100,6 +105,13 @@ export default class WalletTransactions extends Component {
}, 60000);
const isHandOffUseEnabled = await HandoffSettings.isHandoffUseEnabled();
this.setState({ isHandOffUseEnabled });
this._unsubscribeFocus = this.props.navigation.addListener('focus', () => {
StatusBar.setBarStyle('light-content');
this.redrawScreen();
this.props.navigation.setParams({ isLoading: false });
});
this._unsubscribeBlur = this.props.navigation.addListener('blur', this.onWillBlur);
}
/**
@ -120,7 +132,7 @@ export default class WalletTransactions extends Component {
* @returns {Array}
*/
getTransactions(limit = Infinity) {
let wallet = this.props.navigation.getParam('wallet');
let wallet = this.props.route.params.wallet;
let txs = wallet.getTransactions();
for (let tx of txs) {
@ -230,7 +242,7 @@ export default class WalletTransactions extends Component {
- Shows Marketplace button to open in browser (iOS)
The idea is to avoid showing on iOS an appstore/market style app that goes against the TOS.
*/}
{this.state.wallet.getTransactions().length > 0 &&
this.state.wallet.type !== LightningCustodianWallet.type &&
@ -446,10 +458,13 @@ export default class WalletTransactions extends Component {
return alert(Err.message);
}
}
this.props.navigation.navigate('SendDetails', {
memo: loc.lnd.refill_lnd_balance,
address: toAddress,
fromWallet: wallet,
this.props.navigation.navigate('SendDetailsRoot', {
screen: 'SendDetails',
params: {
memo: loc.lnd.refill_lnd_balance,
address: toAddress,
fromWallet: wallet,
},
});
}
};
@ -461,11 +476,16 @@ export default class WalletTransactions extends Component {
componentWillUnmount() {
this.onWillBlur();
clearInterval(this.interval);
this._unsubscribeFocus();
this._unsubscribeBlur();
}
navigateToSendScreen = () => {
this.props.navigation.navigate('SendDetails', {
fromWallet: this.state.wallet,
this.props.navigation.navigate('SendDetailsRoot', {
screen: 'SendDetails',
params: {
fromWallet: this.state.wallet,
},
});
};
@ -485,12 +505,17 @@ export default class WalletTransactions extends Component {
if (!this.state.isLoading) {
this.setState({ isLoading: true }, () => {
this.setState({ isLoading: false });
this.props.navigation.navigate(this.state.wallet.chain === Chain.ONCHAIN ? 'SendDetails' : 'ScanLndInvoice', {
const params = {
fromSecret: this.state.wallet.getSecret(),
// ScanLndInvoice actrually uses `fromSecret` so keeping it for now
uri: ret.data ? ret.data : ret,
fromWallet: this.state.wallet,
});
};
if (this.state.wallet.chain === Chain.ONCHAIN) {
this.props.navigation.navigate('SendDetailsRoot', { screen: 'SendDetails', params });
} else {
this.props.navigation.navigate('ScanLndInvoiceRoot', { screen: 'ScanLndInvoice', params });
}
});
}
};
@ -530,7 +555,7 @@ export default class WalletTransactions extends Component {
this.choosePhoto();
} else if (buttonIndex === 2) {
this.props.navigation.navigate('ScanQRCode', {
launchedBy: this.props.navigation.state.routeName,
launchedBy: this.props.route.name,
onBarScanned: this.onBarCodeRead,
showFileImportButton: false,
});
@ -557,7 +582,7 @@ export default class WalletTransactions extends Component {
text: 'Scan QR Code',
onPress: () =>
this.props.navigation.navigate('ScanQRCode', {
launchedBy: this.props.navigation.state.routeName,
launchedBy: this.props.route.name,
onBarScanned: this.onBarCodeRead,
showFileImportButton: false,
}),
@ -582,14 +607,6 @@ export default class WalletTransactions extends Component {
url={`https://blockpath.com/search/addr?q=${this.state.wallet.getXpub()}`}
/>
)}
<NavigationEvents
onWillFocus={() => {
StatusBar.setBarStyle('light-content');
this.redrawScreen();
}}
onWillBlur={() => this.onWillBlur()}
onDidFocus={() => this.props.navigation.setParams({ isLoading: false })}
/>
<BlueWalletNavigationHeader
wallet={this.state.wallet}
onWalletUnitChange={wallet =>
@ -723,7 +740,7 @@ export default class WalletTransactions extends Component {
<BlueReceiveButtonIcon
onPress={() => {
if (this.state.wallet.chain === Chain.OFFCHAIN) {
navigate('LNDCreateInvoice', { fromWallet: this.state.wallet });
navigate('LNDCreateInvoiceRoot', { screen: 'LNDCreateInvoice', params: { fromWallet: this.state.wallet } });
} else {
navigate('ReceiveDetails', { secret: this.state.wallet.getSecret() });
}
@ -745,7 +762,7 @@ export default class WalletTransactions extends Component {
onLongPress={this.sendButtonLongPress}
onPress={() => {
if (this.state.wallet.chain === Chain.OFFCHAIN) {
navigate('ScanLndInvoice', { fromSecret: this.state.wallet.getSecret() });
navigate('ScanLndInvoiceRoot', { screen: 'ScanLndInvoice', params: { fromSecret: this.state.wallet.getSecret() } });
} else {
if (
this.state.wallet.type === WatchOnlyWallet.type &&
@ -822,10 +839,11 @@ WalletTransactions.propTypes = {
navigation: PropTypes.shape({
navigate: PropTypes.func,
goBack: PropTypes.func,
getParam: PropTypes.func,
setParams: PropTypes.func,
state: PropTypes.shape({
routeName: PropTypes.string,
}),
addListener: PropTypes.func,
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.object,
}),
};

View file

@ -20,7 +20,7 @@ export default class WalletXpub extends Component {
constructor(props) {
super(props);
let secret = props.navigation.state.params.secret;
let secret = props.route.params.secret;
let wallet;
for (let w of BlueApp.getWallets()) {
@ -100,12 +100,13 @@ export default class WalletXpub extends Component {
WalletXpub.propTypes = {
navigation: PropTypes.shape({
state: PropTypes.shape({
params: PropTypes.shape({
secret: PropTypes.string,
}),
}),
navigate: PropTypes.func,
goBack: PropTypes.func,
}),
route: PropTypes.shape({
name: PropTypes.string,
params: PropTypes.shape({
secret: PropTypes.string,
}),
}),
};

View file

@ -75,65 +75,57 @@ describe('unit - DeepLinkSchemaMatch', function() {
const events = [
{
argument: { url: '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG' },
expected: {
routeName: 'SendDetails',
params: {
uri: '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG',
},
},
expected: ['SendDetailsRoot', { screen: 'SendDetails', params: { uri: '12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG' } }],
},
{
argument: { url: 'bitcoin:12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG' },
expected: {
routeName: 'SendDetails',
params: {
uri: 'bitcoin:12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG',
},
},
expected: ['SendDetailsRoot', { screen: 'SendDetails', params: { uri: 'bitcoin:12eQ9m4sgAwTSQoNXkRABKhCXCsjm2jdVG' } }],
},
{
argument: { url: 'BITCOIN:BC1Q3RL0MKYK0ZRTXFMQN9WPCD3GNAZ00YV9YP0HXE?amount=666&label=Yo' },
expected: {
routeName: 'SendDetails',
params: {
uri: 'BITCOIN:BC1Q3RL0MKYK0ZRTXFMQN9WPCD3GNAZ00YV9YP0HXE?amount=666&label=Yo',
},
},
expected: [
'SendDetailsRoot',
{ screen: 'SendDetails', params: { uri: 'BITCOIN:BC1Q3RL0MKYK0ZRTXFMQN9WPCD3GNAZ00YV9YP0HXE?amount=666&label=Yo' } },
],
},
{
argument: { url: 'bluewallet:BITCOIN:BC1Q3RL0MKYK0ZRTXFMQN9WPCD3GNAZ00YV9YP0HXE?amount=666&label=Yo' },
expected: {
routeName: 'SendDetails',
params: {
uri: 'BITCOIN:BC1Q3RL0MKYK0ZRTXFMQN9WPCD3GNAZ00YV9YP0HXE?amount=666&label=Yo',
},
},
expected: [
'SendDetailsRoot',
{ screen: 'SendDetails', params: { uri: 'BITCOIN:BC1Q3RL0MKYK0ZRTXFMQN9WPCD3GNAZ00YV9YP0HXE?amount=666&label=Yo' } },
],
},
{
argument: {
url:
'lightning:lnbc10u1pwjqwkkpp5vlc3tttdzhpk9fwzkkue0sf2pumtza7qyw9vucxyyeh0yaqq66yqdq5f38z6mmwd3ujqar9wd6qcqzpgxq97zvuqrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqz9hx5qqtmgqqqqqqqlgqqqqqqgqjq5duu3fs9xq9vn89qk3ezwpygecu4p3n69wm3tnl28rpgn2gmk5hjaznemw0gy32wrslpn3g24khcgnpua9q04fttm2y8pnhmhhc2gncplz0zde',
},
expected: {
routeName: 'ScanLndInvoice',
params: {
uri:
'lightning:lnbc10u1pwjqwkkpp5vlc3tttdzhpk9fwzkkue0sf2pumtza7qyw9vucxyyeh0yaqq66yqdq5f38z6mmwd3ujqar9wd6qcqzpgxq97zvuqrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqz9hx5qqtmgqqqqqqqlgqqqqqqgqjq5duu3fs9xq9vn89qk3ezwpygecu4p3n69wm3tnl28rpgn2gmk5hjaznemw0gy32wrslpn3g24khcgnpua9q04fttm2y8pnhmhhc2gncplz0zde',
expected: [
'ScanLndInvoiceRoot',
{
screen: 'ScanLndInvoice',
params: {
uri:
'lightning:lnbc10u1pwjqwkkpp5vlc3tttdzhpk9fwzkkue0sf2pumtza7qyw9vucxyyeh0yaqq66yqdq5f38z6mmwd3ujqar9wd6qcqzpgxq97zvuqrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqz9hx5qqtmgqqqqqqqlgqqqqqqgqjq5duu3fs9xq9vn89qk3ezwpygecu4p3n69wm3tnl28rpgn2gmk5hjaznemw0gy32wrslpn3g24khcgnpua9q04fttm2y8pnhmhhc2gncplz0zde',
},
},
},
],
},
{
argument: {
url:
'bluewallet:lightning:lnbc10u1pwjqwkkpp5vlc3tttdzhpk9fwzkkue0sf2pumtza7qyw9vucxyyeh0yaqq66yqdq5f38z6mmwd3ujqar9wd6qcqzpgxq97zvuqrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqz9hx5qqtmgqqqqqqqlgqqqqqqgqjq5duu3fs9xq9vn89qk3ezwpygecu4p3n69wm3tnl28rpgn2gmk5hjaznemw0gy32wrslpn3g24khcgnpua9q04fttm2y8pnhmhhc2gncplz0zde',
},
expected: {
routeName: 'ScanLndInvoice',
params: {
uri:
'lightning:lnbc10u1pwjqwkkpp5vlc3tttdzhpk9fwzkkue0sf2pumtza7qyw9vucxyyeh0yaqq66yqdq5f38z6mmwd3ujqar9wd6qcqzpgxq97zvuqrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqz9hx5qqtmgqqqqqqqlgqqqqqqgqjq5duu3fs9xq9vn89qk3ezwpygecu4p3n69wm3tnl28rpgn2gmk5hjaznemw0gy32wrslpn3g24khcgnpua9q04fttm2y8pnhmhhc2gncplz0zde',
expected: [
'ScanLndInvoiceRoot',
{
screen: 'ScanLndInvoice',
params: {
uri:
'lightning:lnbc10u1pwjqwkkpp5vlc3tttdzhpk9fwzkkue0sf2pumtza7qyw9vucxyyeh0yaqq66yqdq5f38z6mmwd3ujqar9wd6qcqzpgxq97zvuqrzjqvgptfurj3528snx6e3dtwepafxw5fpzdymw9pj20jj09sunnqmwqz9hx5qqtmgqqqqqqqlgqqqqqqgqjq5duu3fs9xq9vn89qk3ezwpygecu4p3n69wm3tnl28rpgn2gmk5hjaznemw0gy32wrslpn3g24khcgnpua9q04fttm2y8pnhmhhc2gncplz0zde',
},
},
},
],
},
];