diff --git a/App.tsx b/App.tsx index f01bf8f772..0706f852bb 100644 --- a/App.tsx +++ b/App.tsx @@ -1,18 +1,177 @@ import * as React from 'react'; -import { Provider } from 'mobx-react'; +import { Observer, Provider } from 'mobx-react'; +import { GestureHandlerRootView } from 'react-native-gesture-handler'; +import { NavigationContainer } from '@react-navigation/native'; +import { createStackNavigator } from '@react-navigation/stack'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { BackHandler, NativeEventSubscription } from 'react-native'; import Stores from './stores/Stores'; -import Navigation from './Navigation'; import NavigationService from './NavigationService'; import PushNotificationManager from './PushNotificationManager'; import { AppContainer } from './components/layout/AppContainer'; import ExternalLinkModal from './components/Modals/ExternalLinkModal'; import AndroidNfcModal from './components/Modals/AndroidNfcModal'; import InfoModal from './components/Modals/InfoModal'; -import { GestureHandlerRootView } from 'react-native-gesture-handler'; + +// Views +import Transaction from './views/Transaction'; +import Wallet from './views/Wallet/Wallet'; +import Send from './views/Send'; +import LnurlPay from './views/LnurlPay/LnurlPay'; +import LnurlChannel from './views/LnurlChannel'; +import LnurlAuth from './views/LnurlAuth'; +import Receive from './views/Receive'; +import PaymentRequest from './views/PaymentRequest'; +import HandleAnythingQRScanner from './views/HandleAnythingQRScanner'; +import NodeQRScanner from './views/NodeQRScanner'; +import OpenChannel from './views/OpenChannel'; +import SendingOnChain from './views/SendingOnChain'; +import SendingLightning from './views/SendingLightning'; +import Channel from './views/Channels/Channel'; +import Payment from './views/Payment'; +import PaymentPaths from './views/PaymentPaths'; +import Invoice from './views/Invoice'; +import Sweep from './views/Sweep'; + +import SparkQRScanner from './views/SparkQRScanner'; +import NodeInfo from './views/NodeInfo'; +import NetworkInfo from './views/NetworkInfo'; +import Lockscreen from './views/Lockscreen'; +import NostrContacts from './views/NostrContacts'; +import ContactQR from './views/ContactQR'; + +// Settings views +import Settings from './views/Settings/Settings'; +import NodeConfiguration from './views/Settings/NodeConfiguration'; +import Nodes from './views/Settings/Nodes'; +import Privacy from './views/Settings/Privacy'; +import Security from './views/Settings/Security'; +import SetPassword from './views/Settings/SetPassword'; +import SetDuressPassword from './views/Settings/SetDuressPassword'; +import SetPin from './views/Settings/SetPin'; +import SetDuressPin from './views/Settings/SetDuressPin'; +import Language from './views/Settings/Language'; +import Currency from './views/Settings/Currency'; +import SelectCurrency from './views/Settings/SelectCurrency'; +import Display from './views/Settings/Display'; +import CertInstallInstructions from './views/Settings/CertInstallInstructions'; +import SignVerifyMessage from './views/Settings/SignVerifyMessage'; +import Support from './views/Settings/Support'; +import Help from './views/Settings/Help'; +import SocialMedia from './views/Settings/SocialMedia'; +import Sponsors from './views/Settings/Sponsors'; +import Olympians from './views/Settings/Olympians'; +import Gods from './views/Settings/Gods'; +import Mortals from './views/Settings/Mortals'; +import PointOfSale from './views/Settings/PointOfSale'; +import PointOfSaleRecon from './views/Settings/PointOfSaleRecon'; +import PointOfSaleReconExport from './views/Settings/PointOfSaleReconExport'; +import Categories from './views/POS/Categories'; +import ProductCategoryDetails from './views/POS/ProductCategoryDetails'; +import Products from './views/POS/Products'; +import ProductDetails from './views/POS/ProductDetails'; +import PaymentsSettings from './views/Settings/PaymentsSettings'; +import InvoicesSettings from './views/Settings/InvoicesSettings'; +import LSP from './views/Settings/LSP'; +import ChannelsSettings from './views/Settings/ChannelsSettings'; +import SetNodePicture from './views/Settings/SetNodePicture'; + +// Lightning address +import LightningAddress from './views/Settings/LightningAddress'; +import LightningAddressInfo from './views/Settings/LightningAddress/LightningAddressInfo'; +import LightningAddressSettings from './views/Settings/LightningAddress/LightningAddressSettings'; +import Attestation from './views/Settings/LightningAddress/Attestation'; +import Attestations from './views/Settings/LightningAddress/Attestations'; +import NostrKeys from './views/Settings/LightningAddress/NostrKeys'; +import NostrRelays from './views/Settings/LightningAddress/NostrRelays'; +import ChangeAddress from './views/Settings/LightningAddress/ChangeAddress'; + +//Embedded Node +import EmbeddedNode from './views/Settings/EmbeddedNode'; +import DisasterRecovery from './views/Settings/EmbeddedNode/DisasterRecovery'; +import DisasterRecoveryAdvanced from './views/Settings/EmbeddedNode/DisasterRecoveryAdvanced'; +import Pathfinding from './views/Settings/EmbeddedNode/Pathfinding'; +import ExpressGraphSync from './views/Settings/EmbeddedNode/ExpressGraphSync'; +import LNDLogs from './views/Settings/EmbeddedNode/LNDLogs'; +import Peers from './views/Settings/EmbeddedNode/Peers'; +import NeutrinoPeers from './views/Settings/EmbeddedNode/Peers/NeutrinoPeers'; +import ZeroConfPeers from './views/Settings/EmbeddedNode/Peers/ZeroConfPeers'; +import Advanced from './views/Settings/EmbeddedNode/Advanced'; + +// Routing +import Routing from './views/Routing/Routing'; +import RoutingEvent from './views/Routing/RoutingEvent'; +import SetFees from './views/Routing/SetFees'; + +// new views +import Activity from './views/Activity/Activity'; +import ActivityFilter from './views/Activity/ActivityFilter'; +import CoinControl from './views/UTXOs/CoinControl'; +import Utxo from './views/UTXOs/UTXO'; +import Accounts from './views/Accounts/Accounts'; +import ImportAccount from './views/Accounts/ImportAccount'; +import ImportingAccount from './views/Accounts/ImportingAccount'; +import BumpFee from './views/BumpFee'; +import QR from './views/QR'; +import AddNotes from './views/AddNotes'; +import Contacts from './views/Settings/Contacts'; +import AddContact from './views/Settings/AddContact'; +import ContactDetails from './views/ContactDetails'; +import CurrencyConverter from './views/Settings/CurrencyConverter'; + +// POS +import Order from './views/Order'; + +import Intro from './views/Intro'; +import IntroSplash from './views/IntroSplash'; + +import EditFee from './views/EditFee'; + +// Embedded LND +import Seed from './views/Settings/Seed'; +import SeedRecovery from './views/Settings/SeedRecovery'; +import Sync from './views/Sync'; +import LspExplanationFees from './views/Explanations/LspExplanationFees'; +import LspExplanationRouting from './views/Explanations/LspExplanationRouting'; +import LspExplanationWrappedInvoices from './views/Explanations/LspExplanationWrappedInvoices'; +import LspExplanationOverview from './views/Explanations/LspExplanationOverview'; +import RestoreChannelBackups from './views/Settings/EmbeddedNode/RestoreChannelBackups'; + +import RawTxHex from './views/RawTxHex'; + +import CustodialWalletWarning from './views/Settings/CustodialWalletWarning'; + +import PSBT from './views/PSBT'; +import TxHex from './views/TxHex'; + +import { themeColor } from './utils/ThemeUtils'; export default class App extends React.PureComponent { + private backPressListenerSubscription: NativeEventSubscription; + + private handleBackPress = (navigation: any) => { + const dialogHasBeenClosed = Stores.modalStore.closeVisibleModalDialog(); + if (dialogHasBeenClosed) { + return true; + } + + if (Stores.settingsStore.loginRequired()) { + BackHandler.exitApp(); + return true; + } + + const navigationState = navigation.getState(); + if (navigationState.routes.length > 1) { + navigation.pop(); + return true; + } + + return false; + }; + render() { + const Stack = createStackNavigator(); return ( - { - NavigationService.setTopLevelNavigator( - navigatorRef - ); - }} - /> + + + {() => ( + { + if (nav != null) { + NavigationService.setTopLevelNavigator( + nav + ); + } + }} + theme={{ + dark: true, + colors: { + background: + themeColor( + 'background' + ), + border: themeColor( + 'background' + ), + card: themeColor( + 'background' + ), + notification: + themeColor('text'), + primary: + themeColor('highlight'), + text: themeColor('text') + } + }} + > + ({ + focus: () => { + this.backPressListenerSubscription?.remove(); + this.backPressListenerSubscription = + BackHandler.addEventListener( + 'hardwareBackPress', + () => + this.handleBackPress( + navigation + ) + ); + }, + blur: () => + this.backPressListenerSubscription?.remove() + })} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} + + diff --git a/Navigation.ts b/Navigation.ts deleted file mode 100644 index e8e305eba9..0000000000 --- a/Navigation.ts +++ /dev/null @@ -1,495 +0,0 @@ -import { createAppContainer } from 'react-navigation'; -import { createStackNavigator } from 'react-navigation-stack'; - -// Views -import Transaction from './views/Transaction'; -import Wallet from './views/Wallet/Wallet'; -import Send from './views/Send'; -import LnurlPay from './views/LnurlPay/LnurlPay'; -import LnurlChannel from './views/LnurlChannel'; -import LnurlAuth from './views/LnurlAuth'; -import Receive from './views/Receive'; -import PaymentRequest from './views/PaymentRequest'; -import HandleAnythingQRScanner from './views/handleAnythingQRScanner'; -import NodeQRScanner from './views/NodeQRScanner'; -import OpenChannel from './views/OpenChannel'; -import SendingOnChain from './views/SendingOnChain'; -import SendingLightning from './views/SendingLightning'; -import Channel from './views/Channels/Channel'; -import Payment from './views/Payment'; -import PaymentPaths from './views/PaymentPaths'; -import Invoice from './views/Invoice'; -import Sweep from './views/Sweep'; - -import SparkQRScanner from './views/SparkQRScanner'; -import NodeInfo from './views/NodeInfo'; -import NetworkInfo from './views/NetworkInfo'; -import Lockscreen from './views/Lockscreen'; -import NostrContacts from './views/NostrContacts'; -import ContactQR from './views/ContactQR'; - -// Settings views -import Settings from './views/Settings/Settings'; -import NodeConfiguration from './views/Settings/NodeConfiguration'; -import Nodes from './views/Settings/Nodes'; -import Privacy from './views/Settings/Privacy'; -import Security from './views/Settings/Security'; -import SetPassword from './views/Settings/SetPassword'; -import SetDuressPassword from './views/Settings/SetDuressPassword'; -import SetPin from './views/Settings/SetPin'; -import SetDuressPin from './views/Settings/SetDuressPin'; -import Language from './views/Settings/Language'; -import Currency from './views/Settings/Currency'; -import SelectCurrency from './views/Settings/SelectCurrency'; -import Display from './views/Settings/Display'; -import CertInstallInstructions from './views/Settings/CertInstallInstructions'; -import SignVerifyMessage from './views/Settings/SignVerifyMessage'; -import Support from './views/Settings/Support'; -import Help from './views/Settings/Help'; -import SocialMedia from './views/Settings/SocialMedia'; -import Sponsors from './views/Settings/Sponsors'; -import Olympians from './views/Settings/Olympians'; -import Gods from './views/Settings/Gods'; -import Mortals from './views/Settings/Mortals'; -import PointOfSale from './views/Settings/PointOfSale'; -import PointOfSaleRecon from './views/Settings/PointOfSaleRecon'; -import PointOfSaleReconExport from './views/Settings/PointOfSaleReconExport'; -import Categories from './views/POS/Categories'; -import ProductCategoryDetails from './views/POS/ProductCategoryDetails'; -import Products from './views/POS/Products'; -import ProductDetails from './views/POS/ProductDetails'; -import PaymentsSettings from './views/Settings/PaymentsSettings'; -import InvoicesSettings from './views/Settings/InvoicesSettings'; -import LSPServicesList from './views/Settings/LSPServicesList'; -import LSP from './views/Settings/LSP'; // Flow 2.0 -import ChannelsSettings from './views/Settings/ChannelsSettings'; -import SetNodePicture from './views/Settings/SetNodePicture'; - -// Lightning address -import LightningAddress from './views/Settings/LightningAddress'; -import LightningAddressInfo from './views/Settings/LightningAddress/LightningAddressInfo'; -import LightningAddressSettings from './views/Settings/LightningAddress/LightningAddressSettings'; -import Attestation from './views/Settings/LightningAddress/Attestation'; -import Attestations from './views/Settings/LightningAddress/Attestations'; -import NostrKeys from './views/Settings/LightningAddress/NostrKeys'; -import NostrRelays from './views/Settings/LightningAddress/NostrRelays'; -import ChangeAddress from './views/Settings/LightningAddress/ChangeAddress'; - -//Embedded Node -import EmbeddedNode from './views/Settings/EmbeddedNode'; -import DisasterRecovery from './views/Settings/EmbeddedNode/DisasterRecovery'; -import DisasterRecoveryAdvanced from './views/Settings/EmbeddedNode/DisasterRecoveryAdvanced'; -import Pathfinding from './views/Settings/EmbeddedNode/Pathfinding'; -import ExpressGraphSync from './views/Settings/EmbeddedNode/ExpressGraphSync'; -import LNDLogs from './views/Settings/EmbeddedNode/LNDLogs'; -import Peers from './views/Settings/EmbeddedNode/Peers'; -import NeutrinoPeers from './views/Settings/EmbeddedNode/Peers/NeutrinoPeers'; -import ZeroConfPeers from './views/Settings/EmbeddedNode/Peers/ZeroConfPeers'; -import Advanced from './views/Settings/EmbeddedNode/Advanced'; - -// Routing -import Routing from './views/Routing/Routing'; -import RoutingEvent from './views/Routing/RoutingEvent'; -import SetFees from './views/Routing/SetFees'; - -// new views -import Activity from './views/Activity/Activity'; -import ActivityFilter from './views/Activity/ActivityFilter'; -import CoinControl from './views/UTXOs/CoinControl'; -import Utxo from './views/UTXOs/UTXO'; -import Accounts from './views/Accounts/Accounts'; -import ImportAccount from './views/Accounts/ImportAccount'; -import ImportingAccount from './views/Accounts/ImportingAccount'; -import BumpFee from './views/BumpFee'; -import QR from './views/QR'; -import AddNotes from './views/AddNotes'; -import Contacts from './views/Settings/Contacts'; -import AddContact from './views/Settings/AddContact'; -import ContactDetails from './views/ContactDetails'; -import CurrencyConverter from './views/Settings/CurrencyConverter'; - -// POS -import Order from './views/Order'; - -import Intro from './views/Intro'; -import IntroSplash from './views/IntroSplash'; - -import EditFee from './views/EditFee'; - -// Embedded LND -import Seed from './views/Settings/Seed'; -import SeedRecovery from './views/Settings/SeedRecovery'; -import Sync from './views/Sync'; -import LspExplanationFees from './views/Explanations/LspExplanationFees'; -import LspExplanationRouting from './views/Explanations/LspExplanationRouting'; -import LspExplanationWrappedInvoices from './views/Explanations/LspExplanationWrappedInvoices'; -import LspExplanationOverview from './views/Explanations/LspExplanationOverview'; -import RestoreChannelBackups from './views/Settings/EmbeddedNode/RestoreChannelBackups'; - -import RawTxHex from './views/RawTxHex'; - -import CustodialWalletWarning from './views/Settings/CustodialWalletWarning'; -import LSPS1 from './views/Settings/LSPS1/index'; -import OrdersPane from './views/Settings/LSPS1/OrdersPane'; -import LSPS1Order from './views/Settings/LSPS1/Order'; -import LSPS1Settings from './views/Settings/LSPS1/Settings'; - -import PSBT from './views/PSBT'; -import TxHex from './views/TxHex'; - -const AppScenes = { - Wallet: { - screen: Wallet - }, - IntroSplash: { - screen: IntroSplash - }, - Intro: { - screen: Intro - }, - Lockscreen: { - screen: Lockscreen - }, - Accounts: { - screen: Accounts - }, - Send: { - screen: Send - }, - Sweep: { - screen: Sweep - }, - EditFee: { - screen: EditFee - }, - Settings: { - screen: Settings - }, - NodeConfiguration: { - screen: NodeConfiguration - }, - Nodes: { - screen: Nodes - }, - Privacy: { - screen: Privacy - }, - Security: { - screen: Security - }, - SetPassword: { - screen: SetPassword - }, - SetDuressPassword: { - screen: SetDuressPassword - }, - SetPin: { - screen: SetPin - }, - SetDuressPin: { - screen: SetDuressPin - }, - Language: { - screen: Language - }, - Currency: { - screen: Currency - }, - SelectCurrency: { - screen: SelectCurrency - }, - Display: { - screen: Display - }, - Support: { - screen: Support - }, - Help: { - screen: Help - }, - Sponsors: { - screen: Sponsors - }, - Olympians: { - screen: Olympians - }, - Gods: { - screen: Gods - }, - Mortals: { - screen: Mortals - }, - CertInstallInstructions: { - screen: CertInstallInstructions - }, - SignVerifyMessage: { - screen: SignVerifyMessage - }, - Transaction: { - screen: Transaction - }, - Channel: { - screen: Channel - }, - Payment: { - screen: Payment - }, - PaymentPaths: { - screen: PaymentPaths - }, - Invoice: { - screen: Invoice - }, - LnurlPay: { - screen: LnurlPay - }, - Receive: { - screen: Receive - }, - LnurlChannel: { - screen: LnurlChannel - }, - LnurlAuth: { - screen: LnurlAuth - }, - PaymentRequest: { - screen: PaymentRequest - }, - OpenChannel: { - screen: OpenChannel - }, - SendingOnChain: { - screen: SendingOnChain - }, - SendingLightning: { - screen: SendingLightning - }, - NetworkInfo: { - screen: NetworkInfo - }, - NodeInfo: { - screen: NodeInfo - }, - Routing: { - screen: Routing - }, - RoutingEvent: { - screen: RoutingEvent - }, - SetFees: { - screen: SetFees - }, - Activity: { - screen: Activity - }, - ActivityFilter: { - screen: ActivityFilter - }, - CoinControl: { - screen: CoinControl - }, - Utxo: { - screen: Utxo - }, - ImportAccount: { - screen: ImportAccount - }, - ImportingAccount: { - screen: ImportingAccount - }, - HandleAnythingQRScanner: { - screen: HandleAnythingQRScanner - }, - NodeQRCodeScanner: { - screen: NodeQRScanner - }, - SparkQRScanner: { - screen: SparkQRScanner - }, - Order: { - screen: Order - }, - PointOfSaleSettings: { - screen: PointOfSale - }, - PointOfSaleRecon: { - screen: PointOfSaleRecon - }, - PointOfSaleReconExport: { - screen: PointOfSaleReconExport - }, - Categories: { - screen: Categories - }, - ProductCategoryDetails: { - screen: ProductCategoryDetails - }, - Products: { - screen: Products - }, - ProductDetails: { - screen: ProductDetails - }, - PaymentsSettings: { - screen: PaymentsSettings - }, - InvoicesSettings: { - screen: InvoicesSettings - }, - Seed: { - screen: Seed - }, - SeedRecovery: { - screen: SeedRecovery - }, - Sync: { - screen: Sync - }, - BumpFee: { - screen: BumpFee - }, - QR: { - screen: QR - }, - AddNotes: { - screen: AddNotes - }, - LspExplanationFees: { - screen: LspExplanationFees - }, - LspExplanationRouting: { - screen: LspExplanationRouting - }, - LspExplanationWrappedInvoices: { - screen: LspExplanationWrappedInvoices - }, - LspExplanationOverview: { - screen: LspExplanationOverview - }, - EmbeddedNodeSettings: { - screen: EmbeddedNode - }, - DisasterRecovery: { - screen: DisasterRecovery - }, - DisasterRecoveryAdvanced: { - screen: DisasterRecoveryAdvanced - }, - Pathfinding: { - screen: Pathfinding - }, - ExpressGraphSync: { - screen: ExpressGraphSync - }, - LNDLogs: { - screen: LNDLogs - }, - Peers: { - screen: Peers - }, - NeutrinoPeers: { - screen: NeutrinoPeers - }, - ZeroConfPeers: { - screen: ZeroConfPeers - }, - EmbeddedNodeSettingsAdvanced: { - screen: Advanced - }, - LSPServicesList: { - screen: LSPServicesList - }, - LSPSettings: { - screen: LSP - }, - LightningAddress: { - screen: LightningAddress - }, - LightningAddressInfo: { - screen: LightningAddressInfo - }, - LightningAddressSettings: { - screen: LightningAddressSettings - }, - Attestations: { - screen: Attestations - }, - Attestation: { - screen: Attestation - }, - Contacts: { - screen: Contacts - }, - AddContact: { - screen: AddContact - }, - ContactDetails: { - screen: ContactDetails - }, - NostrKeys: { - screen: NostrKeys - }, - NostrRelays: { - screen: NostrRelays - }, - ChangeAddress: { - screen: ChangeAddress - }, - SocialMedia: { - screen: SocialMedia - }, - NostrContacts: { - screen: NostrContacts - }, - ContactQR: { - screen: ContactQR - }, - CurrencyConverter: { - screen: CurrencyConverter - }, - ChannelsSettings: { - screen: ChannelsSettings - }, - RawTxHex: { - screen: RawTxHex - }, - RestoreChannelBackups: { - screen: RestoreChannelBackups - }, - SetNodePicture: { - screen: SetNodePicture - }, - CustodialWalletWarning: { - screen: CustodialWalletWarning - }, - PSBT: { - screen: PSBT - }, - TxHex: { - screen: TxHex - }, - LSPS1: { - screen: LSPS1 - }, - OrdersPane: { - screen: OrdersPane - }, - LSPS1Order: { - screen: LSPS1Order - }, - LSPS1Settings: { - screen: LSPS1Settings - } -}; - -const AppNavigator = createStackNavigator(AppScenes, { - headerMode: 'none', - mode: 'modal', - defaultNavigationOptions: { - gestureEnabled: false - } -}); - -const Navigation = createAppContainer(AppNavigator); - -export default Navigation; diff --git a/NavigationService.ts b/NavigationService.ts index deba73fa6e..d8c071b110 100644 --- a/NavigationService.ts +++ b/NavigationService.ts @@ -1,15 +1,18 @@ -import { NavigationActions } from 'react-navigation'; +import { + CommonActions, + NavigationContainerRef +} from '@react-navigation/native'; -let _navigator; +let _navigator: NavigationContainerRef<{}>; -function setTopLevelNavigator(navigatorRef) { +function setTopLevelNavigator(navigatorRef: NavigationContainerRef<{}>) { _navigator = navigatorRef; } function navigate(routeName: string, params?: any) { _navigator.dispatch( - NavigationActions.navigate({ - routeName, + CommonActions.navigate({ + name: routeName, params }) ); diff --git a/README.md b/README.md index e1b30f6b2b..e86ce01e59 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ Reproducible builds are available for Android only right now. You'll need Docker 2. Change to the zeus directory: `cd zeus` 3. Execute the build script: `./build.sh` 4. If everything goes well, the script will print a list of all the generated APK files and SHA256 hashes for each one of them: armv7, armv8, x86, x86_64, universal. The equivalent to the one provided in the web page is the one ending in 'universal'. You can compare SHA256 hashes with the ones provided on the [GitHub releases page](https://github.com/ZeusLN/zeus/releases) -5. Download the oficial APK from [GitHub releases page](https://github.com/ZeusLN/zeus/releases) or from the [ZEUS homepage](https://zeusln.com/): `wget https://zeusln.com/zeus-v0.8.0-universal.apk` +5. Download the official APK from [GitHub releases page](https://github.com/ZeusLN/zeus/releases) or from the [ZEUS homepage](https://zeusln.com/): `wget https://zeusln.com/zeus-v0.8.0-universal.apk` 6. Compare both APKs with a suitable utility like `diffoscope`, `apksigcopier` or by running `diff --brief --recursive ./unpacked_oficial_apk ./unpacked_built_apk`. You should only get differences for the certificates used to sign the official APK If you want to install the APK built this way onto your own smartphone, you'll need to sign it yourself (see next section). Note that the first time you install a build made using this procedure, you'll need to uninstall your current version of ZEUS and then install the one built here because certificates will not match. You'll lose your connection details and you'll need to reconfigure ZEUS again to connect to your nodes. diff --git a/android/app/build.gradle b/android/app/build.gradle index 6cc589c783..f7d2684830 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -101,7 +101,7 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 84 - versionName "0.9.0-alpha3" + versionName "0.9.0-alpha4" multiDexEnabled true missingDimensionStrategy 'react-native-camera', 'general' } @@ -191,8 +191,8 @@ dependencies { implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01' implementation files("../../node_modules/react-native-tor/android/libs/sifir_android.aar") // gif - implementation 'com.facebook.fresco:fresco:2.6.0' - implementation 'com.facebook.fresco:animated-gif:2.6.0' + implementation 'com.facebook.fresco:fresco:3.1.3' + implementation 'com.facebook.fresco:animated-gif:3.1.3' // Pegasus // implementation(name:"Lndmobile", ext:"aar") diff --git a/android/app/src/main/java/com/zeus/LndMobile.java b/android/app/src/main/java/com/zeus/LndMobile.java index b3b64700c0..182c80248a 100644 --- a/android/app/src/main/java/com/zeus/LndMobile.java +++ b/android/app/src/main/java/com/zeus/LndMobile.java @@ -386,13 +386,17 @@ public void stopLnd(Promise promise) { } @ReactMethod - public void gossipSync(String networkType, Promise promise) { + public void gossipSync(String serviceUrl, String networkType, Promise promise) { int req = new Random().nextInt(); requests.put(req, promise); Message message = Message.obtain(null, LndMobileService.MSG_GOSSIP_SYNC, req, 0); message.replyTo = messenger; Bundle bundle = new Bundle(); + bundle.putString( + "serviceUrl", + serviceUrl + ); bundle.putString( "networkType", networkType @@ -406,6 +410,21 @@ public void gossipSync(String networkType, Promise promise) { } } + @ReactMethod + public void cancelGossipSync(Promise promise) { + int req = new Random().nextInt(); + requests.put(req, promise); + + Message message = Message.obtain(null, LndMobileService.MSG_CANCEL_GOSSIP_SYNC, req, 0); + message.replyTo = messenger; + + try { + lndMobileServiceMessenger.send(message); + } catch (RemoteException e) { + promise.reject(TAG, "Could not Send MSG_CANCEL_GOSSIP_SYNC to LndMobileService", e); + } + } + @ReactMethod public void sendCommand(String method, String payloadStr, final Promise promise) { int req = new Random().nextInt(); diff --git a/android/app/src/main/java/com/zeus/LndMobileService.java b/android/app/src/main/java/com/zeus/LndMobileService.java index f0a7e66cec..55e669a433 100644 --- a/android/app/src/main/java/com/zeus/LndMobileService.java +++ b/android/app/src/main/java/com/zeus/LndMobileService.java @@ -73,6 +73,8 @@ public class LndMobileService extends Service { static final int MSG_GRPC_STREAM_WRITE_RESULT = 22; static final int MSG_GOSSIP_SYNC = 23; static final int MSG_GOSSIP_SYNC_RESULT = 24; + static final int MSG_CANCEL_GOSSIP_SYNC = 25; + static final int MSG_CANCEL_GOSSIP_SYNC_RESULT = 26; private Map syncMethods = new HashMap<>(); private Map streamMethods = new HashMap<>(); @@ -236,8 +238,13 @@ public void handleMessage(Message msg) { break; case MSG_GOSSIP_SYNC: + final String serviceUrl = bundle.getString("serviceUrl", ""); final String networkType = bundle.getString("networkType", ""); - gossipSync(msg.replyTo, networkType, request); + gossipSync(msg.replyTo, serviceUrl, networkType, request); + break; + + case MSG_CANCEL_GOSSIP_SYNC: + cancelGossipSync(msg.replyTo, request); break; case MSG_PING: @@ -367,10 +374,11 @@ public void onResponse(byte[] bytes) { } } - void gossipSync(Messenger recipient, String networkType, int request) { + void gossipSync(Messenger recipient, String serviceUrl, String networkType, int request) { Runnable gossipSync = new Runnable() { public void run() { Lndmobile.gossipSync( + serviceUrl, getApplicationContext().getCacheDir().getAbsolutePath(), getApplicationContext().getFilesDir().getAbsolutePath(), networkType, @@ -631,4 +639,11 @@ public void onResponse(byte[] bytes) { } ); } + + private void cancelGossipSync(Messenger recipient, int request) { + if (notificationManager != null) { + notificationManager.cancelAll(); + } + Lndmobile.cancelGossipSync(); + } } diff --git a/android/link-assets-manifest.json b/android/link-assets-manifest.json index 30485b9ae1..bf975478a4 100644 --- a/android/link-assets-manifest.json +++ b/android/link-assets-manifest.json @@ -177,10 +177,6 @@ "path": "assets/images/SVG/Edit.svg", "sha1": "1f6acf36aa5a17040c73377b528ed5b953a48850" }, - { - "path": "assets/images/SVG/Error.svg", - "sha1": "1bf7ab74cc3be1adca93c821e0c577374a2238de" - }, { "path": "assets/images/SVG/ErrorIcon.svg", "sha1": "05da1a652815c751b35361d0433742894988be0a" diff --git a/android/settings.gradle b/android/settings.gradle index 106359d1e8..35f36e6324 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -10,3 +10,5 @@ apply from: file("../node_modules/@react-native-community/cli-platform-android/n include ':lndmobile' include ':app' includeBuild('../node_modules/@react-native/gradle-plugin') +include ':react-native-haptic-feedback' +project(':react-native-haptic-feedback').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-haptic-feedback/android') \ No newline at end of file diff --git a/assets/images/SVG/Error.svg b/assets/images/SVG/Error.svg deleted file mode 100644 index 96f4347409..0000000000 --- a/assets/images/SVG/Error.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/assets/images/SVG/ErrorIcon.svg b/assets/images/SVG/ErrorIcon.svg index a6ee28d14c..90869194fe 100644 --- a/assets/images/SVG/ErrorIcon.svg +++ b/assets/images/SVG/ErrorIcon.svg @@ -1,4 +1,4 @@ - + diff --git a/backends/EmbeddedLND.ts b/backends/EmbeddedLND.ts index d6c557d305..9ee0e7f554 100644 --- a/backends/EmbeddedLND.ts +++ b/backends/EmbeddedLND.ts @@ -84,7 +84,8 @@ export default class EmbeddedLND extends LND { expiry: data.expiry, is_amp: data.is_amp, is_private: data.private, - preimage: data.preimage + preimage: data.preimage, + route_hints: data.route_hints }); getPayments = async () => await listPayments(); getNewAddress = async (data: any) => diff --git a/backends/LND.ts b/backends/LND.ts index faa21d4a16..326f49fcaf 100644 --- a/backends/LND.ts +++ b/backends/LND.ts @@ -318,7 +318,8 @@ export default class LND { private: data.private, r_preimage: data.preimage ? Base64Utils.hexToBase64(data.preimage) - : undefined + : undefined, + route_hints: data.route_hints }); getPayments = () => this.getRequest('/v1/payments?include_incomplete=true'); getNewAddress = (data: any) => this.getRequest('/v1/newaddress', data); diff --git a/backends/LightningNodeConnect.ts b/backends/LightningNodeConnect.ts index 986c5d8653..a39724571f 100644 --- a/backends/LightningNodeConnect.ts +++ b/backends/LightningNodeConnect.ts @@ -151,7 +151,8 @@ export default class LightningNodeConnect { private: data.private, r_preimage: data.preimage ? Base64Utils.hexToBase64(data.preimage) - : undefined + : undefined, + route_hints: data.route_hints }) .then((data: lnrpc.AddInvoiceResponse) => snakeize(data)); getPayments = async () => diff --git a/components/Button.tsx b/components/Button.tsx index 1a2a5e124b..0f6eac3780 100644 --- a/components/Button.tsx +++ b/components/Button.tsx @@ -87,6 +87,8 @@ function Button(props: ButtonProps) { ? themeColor('highlight') : secondary ? themeColor('secondary') + : warning + ? themeColor('delete') : themeColor('text'), ...buttonStyle }} @@ -101,9 +103,9 @@ function Button(props: ButtonProps) { color: iconOnly ? textColor : quaternary - ? warning - ? themeColor('warning') - : textColor + ? textColor + : warning + ? themeColor('text') : secondary ? themeColor('highlight') : themeColor('background'), diff --git a/components/HopPicker.tsx b/components/HopPicker.tsx index ec34205858..3c10a1d28a 100644 --- a/components/HopPicker.tsx +++ b/components/HopPicker.tsx @@ -7,12 +7,14 @@ import { View, Text, TouchableOpacity, - TouchableHighlight + TouchableHighlight, + ViewStyle } from 'react-native'; import { inject, observer } from 'mobx-react'; import { themeColor } from '../utils/ThemeUtils'; import { localeString } from '../utils/LocaleUtils'; +import backendUtils from '../utils/BackendUtils'; import Button from '../components/Button'; import { ChannelItem } from './Channels/ChannelItem'; @@ -27,18 +29,24 @@ import UnitsStore from '../stores/UnitsStore'; interface ChannelPickerProps { title?: string; displayValue?: string; - onValueChange: (value: any) => void; + onValueChange: (channels: Channel[]) => void; + onCancel?: () => void; ChannelsStore: ChannelsStore; UnitsStore: UnitsStore; + containerStyle: ViewStyle; + clearOnTap: boolean; + selectionMode?: 'single' | 'multiple'; + selectedChannels?: Channel[]; } interface ChannelPickerState { - channelSelected: Channel | null; + selectedChannels: Channel[]; valueSet: string; showChannelModal: boolean; } const DEFAULT_TITLE = localeString('components.HopPicker.defaultTitle'); +const MAX_NUMBER_ROUTE_HINTS_LND = 20; @inject('ChannelsStore', 'UnitsStore') @observer @@ -46,37 +54,90 @@ export default class ChannelPicker extends React.Component< ChannelPickerProps, ChannelPickerState > { - state = { - channelSelected: null, + state: ChannelPickerState = { + selectedChannels: [], valueSet: '', showChannelModal: false }; + componentDidMount(): void { + if (this.props.selectedChannels != null) { + this.setState( + { selectedChannels: this.props.selectedChannels }, + this.updateValueSet + ); + } + } + + refreshChannels(): void { + stores.channelsStore.getChannels().then(() => { + this.setState({ + selectedChannels: this.state.selectedChannels + .map((c1) => + stores.channelsStore.channels.find( + (c2) => c2.channelId === c1.channelId + ) + ) + .filter((chan) => chan != null) as Channel[] + }); + }); + } + + updateValueSet(): void { + const nodes = this.props.ChannelsStore.nodes; + const displayNames = this.state.selectedChannels + .map( + (chan) => + chan.alias || + (nodes[chan.remote_pubkey] && + nodes[chan.remote_pubkey].alias) || + (chan && chan.remote_pubkey) || + (chan && chan.channelId) + ) + .join(', '); + + this.setState({ + showChannelModal: false, + valueSet: displayNames + }); + } + openPicker() { - stores.channelsStore.getChannels(); + this.refreshChannels(); this.setState({ - channelSelected: null, showChannelModal: true }); } clearSelection() { + const selectedChannels: Channel[] = []; this.setState({ - channelSelected: null, + selectedChannels, valueSet: '' }); + this.props.onValueChange(selectedChannels); } - toggleItem(item: any) { - this.setState({ channelSelected: item }); + toggleItem(item: Channel) { + if (this.props.selectionMode === 'multiple') { + const selectedChannels = this.state.selectedChannels; + if (selectedChannels.includes(item)) { + selectedChannels.splice(selectedChannels.indexOf(item), 1); + } else { + selectedChannels.push(item); + } + this.setState({ selectedChannels }); + } else { + this.setState({ selectedChannels: [item] }); + } } renderItem = ({ item }: { item: Channel }) => { const { ChannelsStore } = this.props; - const { channelSelected } = this.state; + const { selectedChannels } = this.state; const { largestChannelSats, channelsType } = ChannelsStore; - const selected = channelSelected === item; + const selected = selectedChannels.includes(item); if (channelsType === ChannelsType.Open) { return ( @@ -105,9 +166,17 @@ export default class ChannelPicker extends React.Component< }; render() { - const { title, onValueChange, ChannelsStore } = this.props; - const { showChannelModal, valueSet } = this.state; - const { filteredChannels, nodes, loading, getChannels } = ChannelsStore; + const { + title, + onValueChange, + onCancel, + ChannelsStore, + containerStyle, + selectionMode + } = this.props; + const clearOnTap = this.props.clearOnTap ?? true; + const { showChannelModal, valueSet, selectedChannels } = this.state; + const { filteredChannels, loading } = ChannelsStore; const channels = filteredChannels; @@ -132,21 +201,29 @@ export default class ChannelPicker extends React.Component< fontSize: 25 }} > - {localeString( - 'components.ChannelPicker.modal.title' - )} + {selectionMode === 'multiple' + ? localeString( + 'components.ChannelPicker.modal.title.multiple' + ) + : localeString( + 'components.ChannelPicker.modal.title' + )} - {localeString( - 'components.ChannelPicker.modal.description' - )} + {selectionMode === 'multiple' + ? localeString( + 'components.ChannelPicker.modal.description.multiple' + ) + : localeString( + 'components.ChannelPicker.modal.description' + )} @@ -156,45 +233,45 @@ export default class ChannelPicker extends React.Component< renderItem={(item) => this.renderItem(item)} onEndReachedThreshold={50} refreshing={loading} - onRefresh={() => getChannels()} + onRefresh={() => this.refreshChannels()} /> + {selectionMode === 'multiple' && + backendUtils.isLNDBased() && + selectedChannels.length > + MAX_NUMBER_ROUTE_HINTS_LND && ( + + {MAX_NUMBER_ROUTE_HINTS_LND}{' '} + {localeString( + 'components.HopPicker.routeHintsMax' + )} + + )} + @@ -202,11 +279,12 @@ export default class ChannelPicker extends React.Component< @@ -214,7 +292,7 @@ export default class ChannelPicker extends React.Component< - + {valueSet ? ( - this.clearSelection()}> + { + if (clearOnTap) { + this.clearSelection(); + } else { + this.openPicker(); + } + }} + > ; lightning?: string; locked?: boolean; } diff --git a/components/LayerBalances/OnchainSwipeableRow.tsx b/components/LayerBalances/OnchainSwipeableRow.tsx index ff5bed151b..f55095aa76 100644 --- a/components/LayerBalances/OnchainSwipeableRow.tsx +++ b/components/LayerBalances/OnchainSwipeableRow.tsx @@ -7,9 +7,10 @@ import { I18nManager, TouchableOpacity } from 'react-native'; - import { RectButton } from 'react-native-gesture-handler'; import Swipeable from 'react-native-gesture-handler/Swipeable'; +import { StackNavigationProp } from '@react-navigation/stack'; + import BackendUtils from './../../utils/BackendUtils'; import { localeString } from './../../utils/LocaleUtils'; import { themeColor } from './../../utils/ThemeUtils'; @@ -19,7 +20,7 @@ import Receive from './../../assets/images/SVG/Receive.svg'; import Send from './../../assets/images/SVG/Send.svg'; interface OnchainSwipeableRowProps { - navigation: any; + navigation: StackNavigationProp; value?: string; amount?: string; locked?: boolean; diff --git a/components/LayerBalances/index.tsx b/components/LayerBalances/index.tsx index 5b15a4aca4..3fae7f65b0 100644 --- a/components/LayerBalances/index.tsx +++ b/components/LayerBalances/index.tsx @@ -9,6 +9,7 @@ import { } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; import { RectButton } from 'react-native-gesture-handler'; +import { StackNavigationProp } from '@react-navigation/stack'; import { inject, observer } from 'mobx-react'; import Amount from '../Amount'; @@ -37,7 +38,7 @@ interface LayerBalancesProps { BalanceStore: BalanceStore; UTXOsStore: UTXOsStore; UnitsStore: UnitsStore; - navigation: any; + navigation: StackNavigationProp; onRefresh?: any; value?: string; amount?: string; @@ -164,7 +165,7 @@ const SwipeableRow = ({ }: { item: DataRow; index: number; - navigation: any; + navigation: StackNavigationProp; selectMode: boolean; value?: string; amount?: string; diff --git a/components/OnchainFeeInput.tsx b/components/OnchainFeeInput.tsx index 1ceef6a553..39f7f02c83 100644 --- a/components/OnchainFeeInput.tsx +++ b/components/OnchainFeeInput.tsx @@ -1,18 +1,21 @@ import React, { useEffect, useState } from 'react'; import { Text, TouchableWithoutFeedback, View } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/native'; + import TextInput from '../components/TextInput'; import { themeColor } from '../utils/ThemeUtils'; +import { localeString } from '../utils/LocaleUtils'; import stores from '../stores/Stores'; -import NavigationService from '../NavigationService'; import LoadingIndicator from './LoadingIndicator'; interface OnchainFeeInputProps { + navigation: StackNavigationProp; fee?: string; onChangeFee: (fee: string) => void; } export default function OnchainFeeInput(props: OnchainFeeInputProps) { - const { fee, onChangeFee } = props; + const { fee, onChangeFee, navigation } = props; const { settingsStore, feeStore } = stores; const { settings } = settingsStore; @@ -22,10 +25,10 @@ export default function OnchainFeeInput(props: OnchainFeeInputProps) { const [newFee, setNewFee] = useState(fee); const [loading, setLoading] = useState(false); + const [errorOccurredLoadingFees, setErrorOccurredLoadingFees] = + useState(false); - useEffect(() => { - setNewFee(fee); - }, [fee]); + useEffect(() => setNewFee(fee), [fee]); useEffect(() => { if (enableMempoolRates) { @@ -38,6 +41,7 @@ export default function OnchainFeeInput(props: OnchainFeeInputProps) { setLoading(false); }) .catch(() => { + setErrorOccurredLoadingFees(true); setLoading(false); }); } @@ -48,8 +52,13 @@ export default function OnchainFeeInput(props: OnchainFeeInputProps) { {enableMempoolRates ? ( - NavigationService.navigate('EditFee', { - onNavigateBack: onChangeFee, + navigation.navigate('EditFee', { + onNavigateBack: (fee: string) => { + if (fee) { + setErrorOccurredLoadingFees(false); + } + onChangeFee(fee); + }, fee: newFee }) } @@ -70,12 +79,16 @@ export default function OnchainFeeInput(props: OnchainFeeInputProps) { ) : ( - {newFee} + {errorOccurredLoadingFees + ? localeString('views.EditFee.error') + : newFee} )} diff --git a/components/PinPad.tsx b/components/PinPad.tsx index 79b850afb9..384f3b5927 100644 --- a/components/PinPad.tsx +++ b/components/PinPad.tsx @@ -1,11 +1,19 @@ import * as React from 'react'; import { useMemo, useState } from 'react'; -import { StyleSheet, Text, Pressable, View, AppState } from 'react-native'; +import { + StyleSheet, + Text, + Pressable, + View, + AppState, + Platform +} from 'react-native'; import { themeColor } from '../utils/ThemeUtils'; import { Row } from './layout/Row'; import Success from '../assets/images/SVG/Success.svg'; import Touchable from './Touchable'; import Stores from '../stores/Stores'; +import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; interface PinPadProps { appendValue: (newValue: string) => void; @@ -89,6 +97,14 @@ export default function PinPad({ setPinValueLength(0); }; + const triggerHapticFeedback = () => { + if (!amount) { + // effectClick is only available on Android + const type = Platform.OS === 'android' ? 'effectClick' : 'soft'; + ReactNativeHapticFeedback.trigger(type); + } + }; + return ( @@ -96,6 +112,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[1]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -114,6 +131,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[2]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -132,6 +150,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[3]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -152,6 +171,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[4]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -170,6 +190,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[5]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -188,6 +209,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[6]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -208,6 +230,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[7]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -226,6 +249,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[8]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -244,6 +268,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[9]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -285,6 +310,7 @@ export default function PinPad({ touch={() => { decrementPinValueLength(); deleteValue(); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -306,6 +332,7 @@ export default function PinPad({ touch={() => { incrementPinValueLength(); appendValue(pinNumbers[0]); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -347,6 +374,7 @@ export default function PinPad({ touch={() => { clearPinValueLength(); clearValue(); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} @@ -369,6 +397,7 @@ export default function PinPad({ touch={() => { submitValue(); clearPinValueLength(); + triggerHapticFeedback(); }} highlight={numberHighlight} style={styles.key} diff --git a/components/QRCodeScanner.tsx b/components/QRCodeScanner.tsx index ec606b0a5e..64666b7a2c 100644 --- a/components/QRCodeScanner.tsx +++ b/components/QRCodeScanner.tsx @@ -11,6 +11,7 @@ import { import { Camera } from 'react-native-camera-kit'; import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions'; import { launchImageLibrary } from 'react-native-image-picker'; +import { StackNavigationProp } from '@react-navigation/stack'; const LocalQRCode = require('@remobile/react-native-qrcode-local-image'); @@ -29,7 +30,7 @@ interface QRProps { text?: string; handleQRScanned: any; goBack: any; - navigation: any; + navigation: StackNavigationProp; parts?: number; totalParts?: number; mode?: string; @@ -101,11 +102,11 @@ export default class QRCodeScanner extends React.Component { } }; + handleFocus = () => (this.scannedCache = {}); + async componentDidMount() { // triggers when loaded from navigation or back action - this.props.navigation.addListener('didFocus', () => { - this.scannedCache = {}; - }); + this.props.navigation.addListener('focus', this.handleFocus); if (Platform.OS !== 'ios' && Platform.OS !== 'macos') { // For android @@ -176,7 +177,7 @@ export default class QRCodeScanner extends React.Component { componentWillUnmount() { this.props.navigation.removeListener && - this.props.navigation.removeListener('didFocus'); + this.props.navigation.removeListener('focus', this.handleFocus); } render() { diff --git a/components/WalletHeader.tsx b/components/WalletHeader.tsx index 05105b5de6..576a383e1d 100644 --- a/components/WalletHeader.tsx +++ b/components/WalletHeader.tsx @@ -12,6 +12,7 @@ import { } from 'react-native'; import { inject, observer } from 'mobx-react'; import Clipboard from '@react-native-clipboard/clipboard'; +import { StackNavigationProp } from '@react-navigation/stack'; import ChannelsStore from '../stores/ChannelsStore'; import LightningAddressStore from '../stores/LightningAddressStore'; @@ -35,7 +36,7 @@ import { themeColor } from '../utils/ThemeUtils'; import Add from '../assets/images/SVG/Add.svg'; import ClipboardSVG from '../assets/images/SVG/Clipboard.svg'; -import Scan from '../assets/images/SVG/Scan.svg'; +import Gear from '../assets/images/SVG/Gear.svg'; import POS from '../assets/images/SVG/POS.svg'; import Search from '../assets/images/SVG/Search.svg'; import Temple from '../assets/images/SVG/Temple.svg'; @@ -83,7 +84,11 @@ const MailboxAnimated = () => { ); }; -const ActivityButton = ({ navigation }: { navigation: any }) => ( +const ActivityButton = ({ + navigation +}: { + navigation: StackNavigationProp; +}) => ( ); -const TempleButton = ({ navigation }: { navigation: any }) => ( +const TempleButton = ({ + navigation +}: { + navigation: StackNavigationProp; +}) => ( protectedNavigation(navigation, 'Wallet', true)} > @@ -111,12 +120,16 @@ const TempleButton = ({ navigation }: { navigation: any }) => ( ); -const ScanBadge = ({ navigation }: { navigation: any }) => ( +const SettingsBadge = ({ + navigation +}: { + navigation: StackNavigationProp; +}) => ( navigation.navigate('HandleAnythingQRScanner')} - accessibilityLabel={localeString('general.scan')} + onPress={() => navigation.navigate('Settings')} + accessibilityLabel={localeString('views.Settings.title')} > - + ); @@ -124,7 +137,7 @@ const ClipboardBadge = ({ navigation, clipboard }: { - navigation: any; + navigation: StackNavigationProp; clipboard: string; }) => ( ; loading: boolean; title: string; channels: boolean; @@ -237,10 +250,9 @@ export default class WalletHeader extends React.Component< (settings && settings.pos && settings.pos.posEnabled) || PosEnabled.Disabled; - const SettingsButton = () => ( + const NodeButton = () => ( protectedNavigation(navigation, 'Settings')} - onLongPress={() => protectedNavigation(navigation, 'Nodes')} + onPress={() => protectedNavigation(navigation, 'Nodes')} accessibilityLabel={localeString('views.Settings.title')} > {selectedNode && selectedNode.photo ? ( @@ -383,7 +395,11 @@ export default class WalletHeader extends React.Component< ); - const SyncBadge = ({ navigation }: { navigation: any }) => { + const SyncBadge = ({ + navigation + }: { + navigation: StackNavigationProp; + }) => { const [spinAnim] = useState(new Animated.Value(0)); const interpolateRotation = spinAnim.interpolate({ @@ -426,7 +442,7 @@ export default class WalletHeader extends React.Component< leftComponent={ loading ? undefined : ( - + {paid && paid.length > 0 && ( @@ -548,7 +564,7 @@ export default class WalletHeader extends React.Component< )} - + {posEnabled !== PosEnabled.Disabled && ( ; writeToStream(method: string, payload: string): Promise; + // Express Graph Sync / Speedloader + gossipSync( + serviceUrl: string, + networkType: string + ): Promise<{ data: string }>; + cancelGossipSync(): void; + // Android-specific unbindLndMobileService(): Promise; // TODO(hsjoberg): function looks broken sendPongToLndMobileservice(): Promise<{ data: string }>; checkLndMobileServiceConnected(): Promise; - gossipSync(networkType: string): Promise<{ data: string }>; } export interface ILndMobileTools { diff --git a/lndmobile/LndMobileInjection.ts b/lndmobile/LndMobileInjection.ts index 4f8c645fe5..932eb4f7da 100644 --- a/lndmobile/LndMobileInjection.ts +++ b/lndmobile/LndMobileInjection.ts @@ -13,6 +13,7 @@ import { checkLndFolderExists, createIOSApplicationSupportAndLndDirectories, gossipSync, + cancelGossipSync, TEMP_moveLndToApplicationSupport, excludeLndICloudBackup, queryRoutes, @@ -114,7 +115,11 @@ export interface ILndMobileInjections { isTestnet?: boolean ) => Promise; stopLnd: () => Promise; - gossipSync: (networkType: string) => Promise<{ data: string }>; + gossipSync: ( + serviceUrl: string, + networkType: string + ) => Promise<{ data: string }>; + cancelGossipSync: () => void; checkICloudEnabled: () => Promise; checkApplicationSupportExists: () => Promise; checkLndFolderExists: () => Promise; @@ -129,7 +134,8 @@ export interface ILndMobileInjections { expiry, is_amp, is_private, - preimage + preimage, + route_hints }: { amount?: number; amount_msat?: number; @@ -138,6 +144,7 @@ export interface ILndMobileInjections { is_amp?: boolean; is_private?: boolean; preimage?: string; + route_hints?: lnrpc.IRouteHint[] | null; }) => Promise; cancelInvoice: ( paymentHash: string @@ -446,6 +453,7 @@ export default { startLnd, stopLnd, gossipSync, + cancelGossipSync, checkICloudEnabled, checkApplicationSupportExists, checkLndFolderExists, diff --git a/lndmobile/index.ts b/lndmobile/index.ts index 5d3e06400a..d421370186 100644 --- a/lndmobile/index.ts +++ b/lndmobile/index.ts @@ -87,9 +87,17 @@ export const startLnd = async ( * @throws */ export const gossipSync = async ( + serviceUrl: string, networkType: string ): Promise<{ data: string }> => { - return await LndMobile.gossipSync(networkType); + return await LndMobile.gossipSync(serviceUrl, networkType); +}; + +/** + * @throws + */ +export const cancelGossipSync = async () => { + return LndMobile.cancelGossipSync(); }; export const checkICloudEnabled = async (): Promise => { @@ -561,7 +569,8 @@ export const addInvoice = async ({ expiry = 3600, is_amp, is_private, - preimage + preimage, + route_hints }: { amount?: number; amount_msat?: number; @@ -570,6 +579,7 @@ export const addInvoice = async ({ is_amp?: boolean; is_private?: boolean; preimage?: string; + route_hints?: lnrpc.IRouteHint[] | null; }): Promise => { const response = await sendCommand< lnrpc.IInvoice, @@ -587,7 +597,8 @@ export const addInvoice = async ({ private: is_private, min_hop_hints: is_private ? 6 : 0, is_amp, - r_preimage: preimage ? Base64Utils.hexToBytes(preimage) : undefined + r_preimage: preimage ? Base64Utils.hexToBytes(preimage) : undefined, + route_hints } }); return response; diff --git a/locales/ar.json b/locales/ar.json index 29d3491e8b..ee5662c4e3 100644 --- a/locales/ar.json +++ b/locales/ar.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "رسوم نصف الساعة", "views.EditFee.hourFee": "رسوم الساعة", "views.EditFee.minimumFee": "الحد الأدنى للرسوم", - "views.EditFee.custom": "تخصيص", "views.EditFee.confirmFee": "تأكيد الرسوم", "views.EditFee.error": "Error fetching fee rates", "views.Invoice.title": "فاتورة", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Set UTXOs", "components.ChannelPicker.modal.title": "اختر قناة للإستخدام", "components.ChannelPicker.modal.description": "Select the Channel to be used in this operation. You may want to only use specific channels to preserve your privacy.", - "components.ChannelPicker.modal.set": "Set Channel", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Error fetching Lightning Address data", diff --git a/locales/cs.json b/locales/cs.json index 4b9d98c513..1b278e1c96 100644 --- a/locales/cs.json +++ b/locales/cs.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Půlhodinový poplatek", "views.EditFee.hourFee": "Hodinový poplatek", "views.EditFee.minimumFee": "Minimální poplatek", - "views.EditFee.custom": "Vlastní", "views.EditFee.confirmFee": "Potvrdit poplatek", "views.EditFee.error": "Chybné načtení sazeb poplatků", "views.Invoice.title": "Faktura", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Nastavit UTXOs", "components.ChannelPicker.modal.title": "Vyberte kanál, který chcete použít", "components.ChannelPicker.modal.description": "Vyberte kanál, který se má při této operaci použít. V zájmu ochrany vašeho soukromí možná budete chtít používat pouze konkrétní kanály.", - "components.ChannelPicker.modal.set": "Nastavit kanál", "backends.LND.wsReq.warning": "Možná budete muset povolit ověřování certifikátů, abyste mohli tato volání uskutečnit", "backends.LND.restReq.connectionError": "Chyba připojení", "utils.handleAnything.lightningAddressError": "Chyba při načítání dat Lightning adresy", diff --git a/locales/de.json b/locales/de.json index 6c0ae459aa..16f6a71328 100644 --- a/locales/de.json +++ b/locales/de.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Gebühr für eine halbe Stunde", "views.EditFee.hourFee": "Gebühr für eine Stunde", "views.EditFee.minimumFee": "Mindestgebühr", - "views.EditFee.custom": "Benutzerdefiniert", "views.EditFee.confirmFee": "Gebühr bestätigen", "views.EditFee.error": "Fehler beim Abrufen der Gebühren", "views.Invoice.title": "Rechnung", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "UTXOs festlegen", "components.ChannelPicker.modal.title": "Zu verwendenden Kanal wählen", "components.ChannelPicker.modal.description": "Kanal auswählen, der bei diesem Vorgang verwendet werden soll. Gegebenenfalls möchtest du nur bestimmte Kanäle verwenden, um deine Privatsphäre zu schützen.", - "components.ChannelPicker.modal.set": "Kanal wählen", "backends.LND.wsReq.warning": "Möglicherweise muss die Zertifikatsprüfung aktiviert werden, um diese Art von Aufrufen zu tätigen", "backends.LND.restReq.connectionError": "Verbindungs-Fehler", "utils.handleAnything.lightningAddressError": "Fehler beim Abrufen der Lightning-Adressdaten ", diff --git a/locales/el.json b/locales/el.json index 645aa77257..358143064f 100644 --- a/locales/el.json +++ b/locales/el.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Τέλη μισής ώρας", "views.EditFee.hourFee": "Τέλη μιας ώρας", "views.EditFee.minimumFee": "Ελάχιστο τέλος", - "views.EditFee.custom": "Προσαρμοσμένο", "views.EditFee.confirmFee": "Επιβεβαίωση τέλους", "views.EditFee.error": "Αδυναμία λήψης δεικτών τελών", "views.Invoice.title": "Τιμολόγιο", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Καθορισμός UTXOs", "components.ChannelPicker.modal.title": "Επιλέξτε το κανάλι που θα χρησιμοποιηθεί", "components.ChannelPicker.modal.description": "Επιλέξτε ένα κανάλι για χρήση σε αυτή την διαδικασία. Μπορεί να θέλετε να κάνετε χρήση μόνο σε συγκεκριμένα κανάλια για να διατηρήσετε την ιδιωτικότητα σας.", - "components.ChannelPicker.modal.set": "Ορισμός καναλιού", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Σφάλμα σύνδεσης", "utils.handleAnything.lightningAddressError": "Error fetching Lightning Address data", diff --git a/locales/en.json b/locales/en.json index 7f6c74566c..1c584b8fe7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -105,7 +105,10 @@ "general.destination": "Destination", "general.externalAccount": "External account", "general.version": "Version", - "general.state": "State", + "general.mode": "Mode", + "general.automatic": "Automatic", + "general.custom": "Custom", + "general.skip": "Skip", "restart.title": "Restart required", "restart.msg": "ZEUS has to be restarted before the new configuration is applied.", "restart.msg1": "Would you like to restart now?", @@ -133,6 +136,7 @@ "components.FeeBreakdown.nowClosed": "Now closed", "components.HopPicker.defaultTitle": "Channel to use", "components.HopPicker.selectChannel": "Select channel to use", + "components.HopPicker.routeHintsMax": "route hints max", "components.SetFeesForm.setNew": "Set New Fees", "components.SetFeesForm.hide": "Hide Set New Fees Form", "components.SetFeesForm.setting": "Setting fees, please wait...", @@ -417,7 +421,6 @@ "views.EditFee.halfHourFee": "Half hour fee", "views.EditFee.hourFee": "Hour fee", "views.EditFee.minimumFee": "Minimum fee", - "views.EditFee.custom": "Custom", "views.EditFee.confirmFee": "Confirm Fee", "views.EditFee.error": "Error fetching fee rates", "views.Invoice.title": "Invoice", @@ -565,6 +568,7 @@ "views.Receive.getNewAddress": "Get New Address", "views.Receive.ampInvoice": "AMP Invoice", "views.Receive.routeHints": "Include route hints", + "views.Receive.customRouteHints": "Custom route hints", "views.Receive.youReceived": "You received", "views.Receive.addressType": "Choose address type", "views.Receive.p2wkhKey": "SegWit (P2WKH)", @@ -691,6 +695,7 @@ "views.Settings.Theme.mint": "Mint", "views.Settings.Theme.red-metallic": "Red Metallic", "views.Settings.Theme.watermelon": "Watermelon", + "views.Settings.Theme.radioactive": "Radioactive", "views.Settings.Display.title": "Display", "views.Settings.Display.defaultView": "Default view", "views.Settings.Display.DefaultView.balance": "Balance", @@ -971,8 +976,9 @@ "components.UTXOPicker.modal.description": "Select the UTXOs to be used in this operation. You may want to only use specific UTXOs to preserve your privacy.", "components.UTXOPicker.modal.set": "Set UTXOs", "components.ChannelPicker.modal.title": "Select Channel to use", - "components.ChannelPicker.modal.description": "Select the Channel to be used in this operation. You may want to only use specific channels to preserve your privacy.", - "components.ChannelPicker.modal.set": "Set Channel", + "components.ChannelPicker.modal.title.multiple": "Select Channel(s) to use", + "components.ChannelPicker.modal.description": "Select the channel to be used in this operation. You may want to only use specific channels to preserve your privacy.", + "components.ChannelPicker.modal.description.multiple": "Select the channel(s) to be used in this operation. You may want to only use specific channels to preserve your privacy.", "components.LayerBalances.moreAccounts": "More accounts", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Connection error", diff --git a/locales/es.json b/locales/es.json index f3d7aa8120..bd2c64457d 100644 --- a/locales/es.json +++ b/locales/es.json @@ -915,7 +915,6 @@ "components.UTXOPicker.modal.set": "Usar UTXOs", "components.ChannelPicker.modal.title": "Seleccionar Canal para usar", "components.ChannelPicker.modal.description": "Seleccione el canal que se utilizará en esta operación. Es posible que desee utilizar solamente canales específicos para preservar su privacidad.", - "components.ChannelPicker.modal.set": "Establecer Canal", "backends.LND.wsReq.warning": "Es posible que tenga que activar la verificación de certificados para realizar este tipo de llamadas", "backends.LND.restReq.connectionError": "Error de conexión", "utils.handleAnything.lightningAddressError": "Error en obtener datos de Dirección de Lightning", diff --git a/locales/fa.json b/locales/fa.json index d8cddedcc4..e169a09923 100644 --- a/locales/fa.json +++ b/locales/fa.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "کارمزد نیم ساعته", "views.EditFee.hourFee": "کارمزد یک ساعته", "views.EditFee.minimumFee": "حداقل کارمزد", - "views.EditFee.custom": "دلخواه", "views.EditFee.confirmFee": "تایید کارمزد", "views.EditFee.error": "خطا در دستیابی به نرخ کارمزد", "views.Invoice.title": "صورتحساب", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "تنظیم تراکنش های خروجی مصرف نشده", "components.ChannelPicker.modal.title": "انتخاب کانال برای استفاده", "components.ChannelPicker.modal.description": "کانالی را برای استفاده در این عملیات انتخاب کنید. ممکن است بخواهید برای حفظ حریم خصوصی خود از کانال های خاصی استفاده کنید.", - "components.ChannelPicker.modal.set": "تنظیم کانال", "backends.LND.wsReq.warning": "ممکن است لازم باشد تایید گواهی را فعال کنید تا بتوانید چنین تصمیماتی بگیرید.", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "خطا در دستیابی به داده های آدرس لایتنینگ", diff --git a/locales/fi.json b/locales/fi.json index 6d416f2a2b..41707cf66a 100644 --- a/locales/fi.json +++ b/locales/fi.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Puolen tunnin siirtomaksu", "views.EditFee.hourFee": "Tunnin siirtomaksu", "views.EditFee.minimumFee": "Minimi siirtomaksu", - "views.EditFee.custom": "Mukautettu", "views.EditFee.confirmFee": "Vahvista siirtomaksu", "views.EditFee.error": "Virhe siirtomaksujen hakemisessa", "views.Invoice.title": "Lasku", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Aseta UTXO:t", "components.ChannelPicker.modal.title": "Valitse käytettävä kanava", "components.ChannelPicker.modal.description": "Valitse tässä toiminnossa käytettävä kanava. Saatat haluta käyttää vain tiettyjä kanavia yksityisyytesi säilyttämiseksi.", - "components.ChannelPicker.modal.set": "Aseta kanava", "backends.LND.wsReq.warning": "Sinun on ehkä otettava varmenteen tarkistus käyttöön, jotta voit tehdä tällaisia kutsuja.", "backends.LND.restReq.connectionError": "Yhteysvirhe", "utils.handleAnything.lightningAddressError": "Virhe salamaosoitetietojen noutamisessa", diff --git a/locales/fr.json b/locales/fr.json index c4764e6345..dd72e1d5f6 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Tarif une demi-heure", "views.EditFee.hourFee": "Tarif une heure", "views.EditFee.minimumFee": "Frais minimum", - "views.EditFee.custom": "Personnalisé", "views.EditFee.confirmFee": "Confirmer les frais", "views.EditFee.error": "Erreur lors de la récupération du taux de frais", "views.Invoice.title": "Facture", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Définir les UTXO", "components.ChannelPicker.modal.title": "Sélectionnez le canal à utiliser", "components.ChannelPicker.modal.description": "Sélectionnez le canal à utiliser dans cette opération. Vous voudrez peut-être n'utiliser que des canaux spécifiques pour préserver votre vie privée.", - "components.ChannelPicker.modal.set": "Définir le canal", "backends.LND.wsReq.warning": "Vous devrez peut-être activer la vérification de certificat pour effectuer ce type d'opérations.", "backends.LND.restReq.connectionError": "Erreur de connexion", "utils.handleAnything.lightningAddressError": "Erreur lors de la récupération des données d'adresse Lightning", diff --git a/locales/he.json b/locales/he.json index 74a7673cee..a4c1a832bd 100644 --- a/locales/he.json +++ b/locales/he.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "עמלה עבור אישור תוך חצי שעה", "views.EditFee.hourFee": "עמלה עבור אישור תוך שעה", "views.EditFee.minimumFee": "עמלה מינימלית", - "views.EditFee.custom": "מותאם אישית", "views.EditFee.confirmFee": "אישור עמלה", "views.EditFee.error": "שגיאה במשיכת תעריפי עמלות", "views.Invoice.title": "חשבונית", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "בחירת מטבעות", "components.ChannelPicker.modal.title": "בחירת ערוץ לשימוש", "components.ChannelPicker.modal.description": "בחירת ערוץ שישמש לפעולה זו, בחירת ערוץ יכולה לשמש לשמירה על פרטיות.", - "components.ChannelPicker.modal.set": "קביעת ערוץ", "backends.LND.wsReq.warning": "יתכן ותחויבו לאפשר אימות תעודה כדי לבצע קריאות מסוג זה", "backends.LND.restReq.connectionError": "שגיאת חיבור", "utils.handleAnything.lightningAddressError": "שגיאה במשיכת נתוני כתובת ברק", diff --git a/locales/hr.json b/locales/hr.json index bb215997df..56a0da1716 100644 --- a/locales/hr.json +++ b/locales/hr.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Pola sata naknada", "views.EditFee.hourFee": "Sat naknada", "views.EditFee.minimumFee": "Minimalna naknada", - "views.EditFee.custom": "Prilagodi", "views.EditFee.confirmFee": "Potvrdi naknadu", "views.EditFee.error": "Pogreška pri dohvaćanju stopa naknada", "views.Invoice.title": "Faktura", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Postavi UTXO-e", "components.ChannelPicker.modal.title": "Odaberite kanal za upotrebu", "components.ChannelPicker.modal.description": "Odaberi kanal za upotrebu", - "components.ChannelPicker.modal.set": "Postavi kanal", "backends.LND.wsReq.warning": "Možda ćete morati omogućiti provjeru certifikata da biste obavili ove vrste poziva", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Pogreška u dohvaćanju podataka o lightning adresi", diff --git a/locales/hu.json b/locales/hu.json index 06fa2edc7d..e386f08d63 100644 --- a/locales/hu.json +++ b/locales/hu.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Félórásdíj", "views.EditFee.hourFee": "Óradíj", "views.EditFee.minimumFee": "Minimumdíj", - "views.EditFee.custom": "Egyéni", "views.EditFee.confirmFee": "Díj megerősítése", "views.EditFee.error": "Sikertelen a díj ráta lekérdezése", "views.Invoice.title": "Számla", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "UTXO-k beállítása", "components.ChannelPicker.modal.title": "Használni kívánt csatorna kijelölése", "components.ChannelPicker.modal.description": "Válassza ki a műveletben használni kívánt csatornát. Érdemes csak bizonyos csatornákat használni az adatvédelem megőrzése érdekében. ", - "components.ChannelPicker.modal.set": "Csatorna beállítás", "backends.LND.wsReq.warning": "Előfordulhat, hogy engedélyeznie kell a tanúsítvány-ellenőrzést az ilyen típusú hívások kezdeményezéséhez", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Hiba történt a Lightning Cím adat lekérésekor", diff --git a/locales/it.json b/locales/it.json index e392980209..cfc55ad109 100644 --- a/locales/it.json +++ b/locales/it.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Commissione di mezz'ora", "views.EditFee.hourFee": "Commissione per le ore", "views.EditFee.minimumFee": "Commissione minima", - "views.EditFee.custom": "Personalizzato", "views.EditFee.confirmFee": "Conferma la commissione", "views.EditFee.error": "Tassi di commissione di recupero degli errori", "views.Invoice.title": "Fattura", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Imposta UTXOs", "components.ChannelPicker.modal.title": "Seleziona Canale da usare", "components.ChannelPicker.modal.description": "Seleziona il canale da utilizzare in questa operazione. Potresti voler utilizzare solo canali specifici per preservare la tua privacy.", - "components.ChannelPicker.modal.set": "Imposta Canale", "backends.LND.wsReq.warning": "Potrebbe essere necessario abilitare la verifica del certificato per effettuare questo tipo di chiamate", "backends.LND.restReq.connectionError": "Errore di connessione", "utils.handleAnything.lightningAddressError": "Errore che recupera i dati dell'indirizzo Lightning", diff --git a/locales/ja.json b/locales/ja.json index 1d2530466c..940cec5c39 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Half hour fee", "views.EditFee.hourFee": "Hour fee", "views.EditFee.minimumFee": "Minimum fee", - "views.EditFee.custom": "Custom", "views.EditFee.confirmFee": "Confirm Fee", "views.EditFee.error": "手数料の取得に失敗しました", "views.Invoice.title": "Invoice", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "UXTOを設定", "components.ChannelPicker.modal.title": "使用するチャンネルを選択", "components.ChannelPicker.modal.description": "この操作で使用するチャンネルを選択します。プライバシーを守るために、特定のチャンネルだけを使用したい場合があります。", - "components.ChannelPicker.modal.set": "Set Channel", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Error fetching Lightning Address data", diff --git a/locales/ko.json b/locales/ko.json index 4aef7e9483..2e4309b883 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "30분 수수료", "views.EditFee.hourFee": "1시간 수수료", "views.EditFee.minimumFee": "최소 수수료", - "views.EditFee.custom": "사용자 정의", "views.EditFee.confirmFee": "수수료 확인", "views.EditFee.error": "수수료율 가져오기 오류", "views.Invoice.title": "인보이스", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "UTXO 설정", "components.ChannelPicker.modal.title": "사용할 채널 선택", "components.ChannelPicker.modal.description": "이 작업에 사용할 채널을 선택합니다. 개인정보 보호를 위해 특정 채널만 사용하도록 설정할 수 있습니다.", - "components.ChannelPicker.modal.set": "채널 설정", "backends.LND.wsReq.warning": "이러한 종류의 통화를 하려면 인증서 확인을 사용 설정해야 합니다.", "backends.LND.restReq.connectionError": "연결 오류", "utils.handleAnything.lightningAddressError": "라이트닝 주소 데이터 가져오기 오류", diff --git a/locales/nb.json b/locales/nb.json index f4f20854ec..21ab763012 100644 --- a/locales/nb.json +++ b/locales/nb.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Halvtimes avgift", "views.EditFee.hourFee": "Timesavgift", "views.EditFee.minimumFee": "Minimum avgift", - "views.EditFee.custom": "Tilpasset", "views.EditFee.confirmFee": "Bekreft avgift", "views.EditFee.error": "feil ved henting av avgiftsatser", "views.Invoice.title": "Faktura", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Sett UTXOer", "components.ChannelPicker.modal.title": "Velg kanal som skal brukes", "components.ChannelPicker.modal.description": "Velg kanalen som skal brukes i denne operasjonen. Det kan være lurt å bare bruke bestemte kanaler for å beskytte personvernet ditt.", - "components.ChannelPicker.modal.set": "Sett kanal", "backends.LND.wsReq.warning": "Du må kanskje aktivere sertifikatverifisering for å foreta denne typen anrop", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Feil under henting av lightning-adressedata", diff --git a/locales/nl.json b/locales/nl.json index fc24fa0772..f1428c0ff6 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Half uur fee", "views.EditFee.hourFee": "Uur fee", "views.EditFee.minimumFee": "Minimale fee", - "views.EditFee.custom": "Handmatig", "views.EditFee.confirmFee": "Bevestig Fee", "views.EditFee.error": "Fout bij ophalen fee tarieven", "views.Invoice.title": "Factuur", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Instellen UTXO's", "components.ChannelPicker.modal.title": "Selecteer Kanaal om te gebruiken", "components.ChannelPicker.modal.description": "Selecteer het Kanaal dat bij deze bewerking moet worden gebruikt. Misschien wilt u alleen specifieke kanalen gebruiken om uw privacy te beschermen.", - "components.ChannelPicker.modal.set": "Instellen Kanaal", "backends.LND.wsReq.warning": "Mogelijk moet u Certificaatverificatie inschakelen om dit soort oproepen te doen", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Fout bij ophalen Lightning Adres gegevens", diff --git a/locales/pl.json b/locales/pl.json index f5759be732..e64e5d84cf 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Opłata dla pół godziny", "views.EditFee.hourFee": "Opłata dla godziny", "views.EditFee.minimumFee": "Minimalna opłata", - "views.EditFee.custom": "Własna", "views.EditFee.confirmFee": "Potwierdź opłatę", "views.EditFee.error": "Błąd pobierania bieżącego poziomu opłat", "views.Invoice.title": "Faktura", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Ustaw UTXO", "components.ChannelPicker.modal.title": "Wybierz kanał do użycia", "components.ChannelPicker.modal.description": "Wybierz kanał, który ma być użyty w tej operacji. W celu zachowania prywatności może być konieczne korzystanie tylko z określonych kanałów.", - "components.ChannelPicker.modal.set": "Ustaw kanał", "backends.LND.wsReq.warning": "Może być konieczne włączenie weryfikacji certyfikatu, aby wykonywać tego typu połączenia", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Błąd pobierania danych adresu Lightning", diff --git a/locales/pt_BR.json b/locales/pt_BR.json index 12a168b20f..ab7d0fd21c 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Taxa de meia hora", "views.EditFee.hourFee": "Taxa de hora", "views.EditFee.minimumFee": "Taxa mínima", - "views.EditFee.custom": "Pesonalizar", "views.EditFee.confirmFee": "Confirme taxa", "views.EditFee.error": "Erro ao buscar taxas", "views.Invoice.title": "Conbrança", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Escolher UTXOs", "components.ChannelPicker.modal.title": "Selecione canal para usar", "components.ChannelPicker.modal.description": "Selecione o Canal a ser usado nesta operação. Você pode querer usar apenas canais específicos para preservar sua privacidade.", - "components.ChannelPicker.modal.set": "Ajustar canal", "backends.LND.wsReq.warning": "Talvez seja necessário habilitar a Verificação de certificado para fazer esse tipo de chamada", "backends.LND.restReq.connectionError": "Erro de conexão", "utils.handleAnything.lightningAddressError": "Erro ao buscar dados de endereço do Lightning", diff --git a/locales/ro.json b/locales/ro.json index e0f01d181c..345c4b18d5 100644 --- a/locales/ro.json +++ b/locales/ro.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Comision pentru o jumătate de oră", "views.EditFee.hourFee": "Comision pentru o oră", "views.EditFee.minimumFee": "Comision minim", - "views.EditFee.custom": "Valoare", "views.EditFee.confirmFee": "Confirmă Comision", "views.EditFee.error": "Eroare la obținerea comisioanelor", "views.Invoice.title": "Factură", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Setează UTXO-uri", "components.ChannelPicker.modal.title": "Selectează care Canal să fie folosit", "components.ChannelPicker.modal.description": "Selectează care canal să fie folosit în această operație. Ai posibilitatea să folosești doar anumite canale, astfel încât să-ți păstrezi intimitatea.", - "components.ChannelPicker.modal.set": "Setează Canal.", "backends.LND.wsReq.warning": "S-ar putea să fie nevoie să activezi Verificare Certificat pentru a putea face acest tip de operații.", "backends.LND.restReq.connectionError": "Eroare de conexiune", "utils.handleAnything.lightningAddressError": "Eroare obținere date despre Adresa Lightning", diff --git a/locales/ru.json b/locales/ru.json index b97b09ef2f..a72e14099e 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Комиссия в течении получаса", "views.EditFee.hourFee": "Комиссия в течении часа", "views.EditFee.minimumFee": "Минимальная комиссия", - "views.EditFee.custom": "Пользовательская", "views.EditFee.confirmFee": "Подтвердить Комиссию", "views.EditFee.error": "Не удалось получить ставки комиссий.", "views.Invoice.title": "Инвойс", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Установить UTXO", "components.ChannelPicker.modal.title": "Выберите используемый Канал", "components.ChannelPicker.modal.description": "Выберите Канал, который будет использоваться в этой операции. Возможно, вы захотите использовать только определенные каналы, чтобы сохранить свою конфиденциальность.", - "components.ChannelPicker.modal.set": "Установить Канал", "backends.LND.wsReq.warning": "Возможно, вам придется включить Проверку Сертификата, чтобы совершать такие запросы.", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Ошибка при получении данных адреса Lightning.", diff --git a/locales/sk.json b/locales/sk.json index 1eaea5d6c4..c2d3823c18 100644 --- a/locales/sk.json +++ b/locales/sk.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Half hour fee", "views.EditFee.hourFee": "Hour fee", "views.EditFee.minimumFee": "Minimum fee", - "views.EditFee.custom": "Custom", "views.EditFee.confirmFee": "Confirm Fee", "views.EditFee.error": "Error fetching fee rates", "views.Invoice.title": "Faktúra", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Set UTXOs", "components.ChannelPicker.modal.title": "Select Channel to use", "components.ChannelPicker.modal.description": "Select the Channel to be used in this operation. You may want to only use specific channels to preserve your privacy.", - "components.ChannelPicker.modal.set": "Nastaviť kanál", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Error fetching Lightning Address data", diff --git a/locales/sl.json b/locales/sl.json index 7be279b311..9e118e7cb3 100644 --- a/locales/sl.json +++ b/locales/sl.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Pol urna omrežnina", "views.EditFee.hourFee": "Urna omrežnina", "views.EditFee.minimumFee": "Minimalna omrežnina", - "views.EditFee.custom": "Po meri", "views.EditFee.confirmFee": "Potrdi omrežnino", "views.EditFee.error": "Napaka pri pridobivanju omrežnin", "views.Invoice.title": "Račun", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Izberi", "components.ChannelPicker.modal.title": "Izbira kanala", "components.ChannelPicker.modal.description": "Izberite kanal, ki ga želite uporabiti pri tem plačilu. Morda boste želeli uporabiti samo določene kanale, da ohranite svojo zasebnost.", - "components.ChannelPicker.modal.set": "Izberi kanal", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Error fetching Lightning Address data", diff --git a/locales/sv.json b/locales/sv.json index 13bff72963..7b3b2e78e6 100644 --- a/locales/sv.json +++ b/locales/sv.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Halvtimmesavgift", "views.EditFee.hourFee": "Timmesavgift", "views.EditFee.minimumFee": "Minimumavgift", - "views.EditFee.custom": "Anpassad", "views.EditFee.confirmFee": "Bekräfta avgift", "views.EditFee.error": "Fel vid hämtning av avgiftsnivåer", "views.Invoice.title": "Invoice", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Välj UTXOs", "components.ChannelPicker.modal.title": "Välj kanal att använda", "components.ChannelPicker.modal.description": "Välj kanalen att använda för denna operation. Du kanske vill använda en specifik kanal för att skydda din integritet.", - "components.ChannelPicker.modal.set": "Välj kanal", "backends.LND.wsReq.warning": "Du kanske måste aktivera certfikatverifiering för att göra dessa anrop", "backends.LND.restReq.connectionError": "Anslutningsfel", "utils.handleAnything.lightningAddressError": "Fel vid hämtning av Lightning Adress-data", diff --git a/locales/sw.json b/locales/sw.json index a25a75223b..23b616db80 100644 --- a/locales/sw.json +++ b/locales/sw.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Ada ya nusu saa", "views.EditFee.hourFee": "Ada ya saa", "views.EditFee.minimumFee": "Ada ya chini", - "views.EditFee.custom": "Desturi", "views.EditFee.confirmFee": "Thibitisha Ada", "views.EditFee.error": "Kosa la kupata viwango vya ada", "views.Invoice.title": "Invoice", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Wekea UTXOs", "components.ChannelPicker.modal.title": "Chagua Kituo cha kutumia", "components.ChannelPicker.modal.description": "Chagua Kituo cha kutumika kwenye operesheni hii. Unaweza kutaka kutumia vituo maalum kuhifadhi faragha yako.", - "components.ChannelPicker.modal.set": "Wekea Kituo", "backends.LND.wsReq.warning": "Huenda ikalazimu uweze Uhakiki wa Cheti kufanya simu kama hizi", "backends.LND.restReq.connectionError": "Kosa la kuunganisha", "utils.handleAnything.lightningAddressError": "Kosa la kupata data ya Anwani ya Umeme", diff --git a/locales/th.json b/locales/th.json index 90330f590c..8574ff478e 100644 --- a/locales/th.json +++ b/locales/th.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "ค่าธรรมเนียมครึ่งชั่วโมง", "views.EditFee.hourFee": "ค่าธรรมเนียมหนึ่งชั่วโมง", "views.EditFee.minimumFee": "ค่าธรรมเนียมขั้นต่ำ", - "views.EditFee.custom": "กำหนดเอง", "views.EditFee.confirmFee": "ยืนยันค่าธรรมเนียม", "views.EditFee.error": "เกิดข้อผิดพลาดในการดึงอัตราค่าธรรมเนียม", "views.Invoice.title": "ใบแจ้งหนี้", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "ตั้ง UTXOs", "components.ChannelPicker.modal.title": "เลือกแชลแนลที่จะใช้งาน", "components.ChannelPicker.modal.description": "เลือกแชลแนลที่จะใช้ในการดำเนินการนี้ คุณอาจจะต้องใช้แชลแนลเฉพาะเพื่อที่จะปกป้องความเป็นส่วนตัวของคุณ", - "components.ChannelPicker.modal.set": "ตั้งแชลแนล", "backends.LND.wsReq.warning": "คุณการจะต้องเปิดการยืนยันใบรับเพื่อที่จะทำกิจกรรมเหล่านี้ได้", "backends.LND.restReq.connectionError": "เชื่อมต่อผิดพลาด", "utils.handleAnything.lightningAddressError": "เกิดข้อผิดพลาดในการโหลดที่อยู่ lightning", diff --git a/locales/tr.json b/locales/tr.json index ec5bcbd607..8d4c3f0e8c 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Yarım saat için gönderi ücreti", "views.EditFee.hourFee": "Saatlik gönderi ücreti", "views.EditFee.minimumFee": "Minimum ücret", - "views.EditFee.custom": "Özel ", "views.EditFee.confirmFee": "Ücreti onayla", "views.EditFee.error": "Ücretleri çekerken sorun yaşandı", "views.Invoice.title": "Fatura", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "UTXO'ları ayarla", "components.ChannelPicker.modal.title": "Kullanılacak Kanalı seç", "components.ChannelPicker.modal.description": "Bu operasyonda kullanılacak kanalı seçin. Gizliliğinizi korumak adına spesifik kanallar seçebilirsiniz.", - "components.ChannelPicker.modal.set": "Kanal ayarla", "backends.LND.wsReq.warning": "Bu tarz istekler için Sertifika Onaylama'yı açmak zorunda kalabilirsiniz.", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Lightning Adres datası alırken Hata", diff --git a/locales/uk.json b/locales/uk.json index 4df3838b60..569d1bb17a 100644 --- a/locales/uk.json +++ b/locales/uk.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Півгодинна комісія", "views.EditFee.hourFee": "Годинна комісія", "views.EditFee.minimumFee": "Мінімальна комісія", - "views.EditFee.custom": "Редагувати", "views.EditFee.confirmFee": "Підтвердити комісію", "views.EditFee.error": "Не вдалося завантажити комісії", "views.Invoice.title": "Рахунок", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Встановити UTXO", "components.ChannelPicker.modal.title": "Оберіть який канал використовувати", "components.ChannelPicker.modal.description": "Оберіть канал, який буде використаний для цієї операції. Використовуйте лише певні канали, щоб зберегти вашу конфіденційність.", - "components.ChannelPicker.modal.set": "Встановити канал", "backends.LND.wsReq.warning": "Вам, можливо, необхідно ввімкнути перевірку сертифікату для таких запитів", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Не вдалося отримати дані Lightning адреси", diff --git a/locales/vi.json b/locales/vi.json index 21b2e93559..9d87c882dd 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Phí nửa tiếng", "views.EditFee.hourFee": "Phí theo giờ", "views.EditFee.minimumFee": "Phí tối thiểu", - "views.EditFee.custom": "Tuỳ chỉnh", "views.EditFee.confirmFee": "Phí Xác nhận", "views.EditFee.error": "Lỗi khi cập nhật tỷ lệ phí", "views.Invoice.title": "Hoá đơn", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Thiết lập các UTXO", "components.ChannelPicker.modal.title": "Chọn Kênh để sử dụng ", "components.ChannelPicker.modal.description": "Chọn Kênh sẽ được sử dụng trong thao tác này. Bạn có thể muốn chỉ sử dụng các kênh cụ thể để bảo vệ quyền riêng tư của mình. ", - "components.ChannelPicker.modal.set": "Đặt Kênh", "backends.LND.wsReq.warning": "Bạn có thể phải bật Xác minh chứng chỉ để thực hiện những cuộc gọi kiểu này ", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "Lỗi khi tìm nạp dữ liệu Địa chỉ Lightning ", diff --git a/locales/zh_CN.json b/locales/zh_CN.json index ec07a2bf5f..a1b4259b26 100644 --- a/locales/zh_CN.json +++ b/locales/zh_CN.json @@ -401,7 +401,6 @@ "views.EditFee.halfHourFee": "Half hour fee", "views.EditFee.hourFee": "Hour fee", "views.EditFee.minimumFee": "最低手续费", - "views.EditFee.custom": "自定义", "views.EditFee.confirmFee": "Confirm Fee", "views.EditFee.error": "Error fetching fee rates", "views.Invoice.title": "发票", @@ -915,7 +914,6 @@ "components.UTXOPicker.modal.set": "Set UTXOs", "components.ChannelPicker.modal.title": "选择要使用的通道", "components.ChannelPicker.modal.description": "选择要在此操作中使用的通道。你可能想只使用特定的通道以保护你的隐私。", - "components.ChannelPicker.modal.set": "设置通道", "backends.LND.wsReq.warning": "You may have to enable Certificate Verification to make these kind of calls", "backends.LND.restReq.connectionError": "Connection error", "utils.handleAnything.lightningAddressError": "获取闪电地址数据时出错", diff --git a/models/Channel.ts b/models/Channel.ts index d4af225732..92e44251ff 100644 --- a/models/Channel.ts +++ b/models/Channel.ts @@ -50,7 +50,7 @@ export default class Channel extends BaseModel { channel_id?: string; alias?: string; // pending - remote_node_pub: string; + remote_node_pub?: string; // enrichments displayName?: string; diff --git a/models/Payment.ts b/models/Payment.ts index cbb6371454..259306e8f3 100644 --- a/models/Payment.ts +++ b/models/Payment.ts @@ -110,8 +110,9 @@ export default class Payment extends BaseModel { @computed public get isIncomplete(): boolean { return ( + !this.getPreimage || this.getPreimage === - '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000' ); } diff --git a/package.json b/package.json index 01c124c420..1833e18476 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zeus", - "version": "0.9.0-alpha3", + "version": "0.9.0-alpha4", "private": true, "jest": { "preset": "react-native", @@ -36,12 +36,12 @@ "@ngraveio/bc-ur": "1.1.12", "@react-native-async-storage/async-storage": "1.22.0", "@react-native-clipboard/clipboard": "1.13.2", - "@react-native-community/masked-view": "0.1.11", "@react-native-community/netinfo": "11.3.0", - "@react-native-community/slider": "4.5.2", + "@react-native-masked-view/masked-view": "0.3.1", "@react-native-picker/picker": "2.6.1", - "@react-navigation/bottom-tabs": "5.11.11", - "@react-navigation/native": "6.1.10", + "@react-navigation/bottom-tabs": "7.0.0-alpha.22", + "@react-navigation/native": "7.0.0-alpha.18", + "@react-navigation/stack": "7.0.0-alpha.20", "@remobile/react-native-qrcode-local-image": "github:BlueWallet/react-native-qrcode-local-image#31b0113", "@scure/base": "1.1.6", "@tradle/react-native-http": "2.0.1", @@ -107,6 +107,7 @@ "react-native-fs": "2.20.0", "react-native-gesture-handler": "2.15.0", "react-native-get-random-values": "1.9.0", + "react-native-haptic-feedback": "2.2.0", "react-native-hce": "0.1.2", "react-native-image-picker": "5.0.1", "react-native-keychain": "8.1.1", @@ -123,7 +124,7 @@ "react-native-reanimated": "3.7.0", "react-native-reanimated-carousel": "3.5.1", "react-native-restart": "0.0.27", - "react-native-safe-area-context": "0.6.4", + "react-native-safe-area-context": "4.10.1", "react-native-screens": "3.29.0", "react-native-securerandom": "1.0.1", "react-native-snap-carousel": "meliorence/react-native-snap-carousel#962/head", @@ -135,8 +136,6 @@ "react-native-udp": "4.1.7", "react-native-v8": "0.61.5-patch.4", "react-native-vector-icons": "7.1.0", - "react-navigation": "4.4.4", - "react-navigation-stack": "2.0.16", "readable-stream": "1.0.33", "sha.js": "2.4.11", "socket.io-client": "4.7.2", @@ -252,4 +251,4 @@ "reactNativePermissionsIOS": [ "Camera" ] -} +} \ No newline at end of file diff --git a/stores/FeeStore.ts b/stores/FeeStore.ts index efa90a0320..81c86212a7 100644 --- a/stores/FeeStore.ts +++ b/stores/FeeStore.ts @@ -69,9 +69,11 @@ export default class FeeStore { this.error = true; } }) - .catch(() => { + .catch((error: any) => { + console.error('Error fetching fees:', error); this.recommendedFees = {}; this.loading = false; + this.error = true; }); }; diff --git a/stores/InvoicesStore.ts b/stores/InvoicesStore.ts index 0c5770e882..ea765d2a30 100644 --- a/stores/InvoicesStore.ts +++ b/stores/InvoicesStore.ts @@ -7,12 +7,15 @@ import { LNURLWithdrawParams } from 'js-lnurl'; import querystring from 'querystring-es3'; import Invoice from '../models/Invoice'; +import Channel from '../models/Channel'; +import ChannelInfo from '../models/ChannelInfo'; import SettingsStore from './SettingsStore'; import LSPStore from './LSPStore'; import BackendUtils from '../utils/BackendUtils'; import { localeString } from '../utils/LocaleUtils'; import { errorToUserFriendly } from '../utils/ErrorUtils'; import ChannelsStore from './ChannelsStore'; +import NodeInfoStore from './NodeInfoStore'; export default class InvoicesStore { @observable paymentRequest: string; @@ -34,6 +37,7 @@ export default class InvoicesStore { settingsStore: SettingsStore; lspStore: LSPStore; channelsStore: ChannelsStore; + nodeInfoStore: NodeInfoStore; // lnd @observable loadingFeeEstimate = false; @@ -43,11 +47,13 @@ export default class InvoicesStore { constructor( settingsStore: SettingsStore, lspStore: LSPStore, - channelsStore: ChannelsStore + channelsStore: ChannelsStore, + nodeInfoStore: NodeInfoStore ) { this.settingsStore = settingsStore; this.lspStore = lspStore; this.channelsStore = channelsStore; + this.nodeInfoStore = nodeInfoStore; reaction( () => this.pay_req, @@ -121,6 +127,7 @@ export default class InvoicesStore { lnurl?: LNURLWithdrawParams, ampInvoice?: boolean, routeHints?: boolean, + routeHintChannels?: Channel[], addressType?: string, customPreimage?: string, noLsp?: boolean @@ -133,6 +140,7 @@ export default class InvoicesStore { lnurl, ampInvoice, routeHints, + routeHintChannels, true, customPreimage, noLsp @@ -178,6 +186,7 @@ export default class InvoicesStore { lnurl?: LNURLWithdrawParams, ampInvoice?: boolean, routeHints?: boolean, + routeHintChannels?: Channel[], unified?: boolean, customPreimage?: string, noLsp?: boolean @@ -196,7 +205,58 @@ export default class InvoicesStore { }; if (ampInvoice) req.is_amp = true; - if (routeHints) req.private = true; + if (routeHints) { + if (routeHintChannels?.length) { + const routeHints = []; + for (const routeHintChannel of routeHintChannels) { + let channelInfo = + this.channelsStore.chanInfo[ + routeHintChannel.channelId! + ]; + if (!channelInfo) { + try { + channelInfo = new ChannelInfo( + await BackendUtils.getChannelInfo( + routeHintChannel.channelId + ) + ); + } catch (error: any) { + this.creatingInvoiceError = true; + this.creatingInvoice = false; + this.error_msg = + error.toString() || + localeString( + 'stores.InvoicesStore.errorCreatingInvoice' + ); + return; + } + } + const remotePolicy = + channelInfo.node1Pub === + this.nodeInfoStore.nodeInfo.nodeId + ? channelInfo.node2Policy + : channelInfo.node1Policy; + routeHints.push({ + hop_hints: [ + { + node_id: routeHintChannel.remotePubkey, + chan_id: routeHintChannel.channelId, // must not be converted to Number as this might lead to a loss of precision + fee_base_msat: Number( + remotePolicy?.fee_base_msat + ), + fee_proportional_millionths: Number( + remotePolicy?.fee_rate_milli_msat + ), + cltv_expiry_delta: remotePolicy?.time_lock_delta + } + ] + }); + } + req.route_hints = routeHints; + } else { + req.private = true; + } + } if (customPreimage) req.preimage = customPreimage; diff --git a/stores/SettingsStore.ts b/stores/SettingsStore.ts index 33c4379ccd..4b94bd0c52 100644 --- a/stores/SettingsStore.ts +++ b/stores/SettingsStore.ts @@ -849,6 +849,11 @@ export const THEME_KEYS = [ key: 'Watermelon', translateKey: 'views.Settings.Theme.watermelon', value: 'watermelon' + }, + { + key: 'Radioactive', + translateKey: 'views.Settings.Theme.radioactive', + value: 'radioactive' } ]; diff --git a/stores/Stores.ts b/stores/Stores.ts index cb5ec977d2..53a037d923 100644 --- a/stores/Stores.ts +++ b/stores/Stores.ts @@ -70,7 +70,8 @@ class Stores { this.invoicesStore = new InvoicesStore( this.settingsStore, this.lspStore, - this.channelsStore + this.channelsStore, + this.nodeInfoStore ); this.transactionsStore = new TransactionsStore( this.settingsStore, diff --git a/utils/ErrorUtils.ts b/utils/ErrorUtils.ts index 60f081d415..1dfa9ee274 100644 --- a/utils/ErrorUtils.ts +++ b/utils/ErrorUtils.ts @@ -21,8 +21,8 @@ const errorToUserFriendly = (error: Error, localize = true) => { try { errorObject = JSON.parse(errorMessage || error.toString()); - } catch (err) { - console.log(err); + } catch { + // ignore - using original error message } const userFriendlyErrorMessage = diff --git a/utils/LinkingUtils.ts b/utils/LinkingUtils.ts index 806accbd1f..8e1294bda3 100644 --- a/utils/LinkingUtils.ts +++ b/utils/LinkingUtils.ts @@ -1,9 +1,11 @@ import { Linking, Platform, NativeModules } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import { localeString } from './LocaleUtils'; import handleAnything from './handleAnything'; class LinkingUtils { - handleInitialUrl = (navigation: any) => + handleInitialUrl = (navigation: StackNavigationProp) => Linking.getInitialURL().then(async (url) => { if (url) { this.handleDeepLink(url, navigation); @@ -15,7 +17,10 @@ class LinkingUtils { if (nfcData) this.handleDeepLink(nfcData, navigation); } }); - handleDeepLink = (url: string, navigation: any) => { + handleDeepLink = ( + url: string, + navigation: StackNavigationProp + ) => { if (url.startsWith('nostr:')) { Linking.openURL(url); } else { diff --git a/utils/LndMobileUtils.ts b/utils/LndMobileUtils.ts index dcb3b702ea..0692d50829 100644 --- a/utils/LndMobileUtils.ts +++ b/utils/LndMobileUtils.ts @@ -15,7 +15,11 @@ import { sleep } from './SleepUtils'; import Base64Utils from './Base64Utils'; import lndMobile from '../lndmobile/LndMobileInjection'; -import { ELndMobileStatusCodes, gossipSync } from '../lndmobile/index'; +import { + ELndMobileStatusCodes, + gossipSync, + cancelGossipSync +} from '../lndmobile/index'; import stores from '../stores/Stores'; @@ -120,9 +124,11 @@ const writeLndConfig = async ( ? 'neutrino.assertfilterheader=660000:08312375fabc082b17fa8ee88443feb350c19a34bb7483f94f7478fa4ad33032' : '' } - neutrino.feeurl=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json neutrino.broadcasttimeout=11s neutrino.persistfilters=true + + [fee] + fee.url=https://nodes.lightning.computer/fees/v1/btc-fee-estimates.json [autopilot] autopilot.active=0 @@ -151,9 +157,25 @@ const writeLndConfig = async ( }; export async function expressGraphSync() { - if (stores.settingsStore.embeddedLndNetwork === 'Mainnet') { - const start = new Date(); + return await new Promise(async (resolve) => { stores.syncStore.setExpressGraphSyncStatus(true); + + const start = new Date(); + + const timer = setInterval(async () => { + console.log('Express graph sync is running...'); + // Check if the cancellation token is set + if (!stores.syncStore.isInExpressGraphSync) { + clearInterval(timer); + // call cancellation to LND here + console.log('Express graph sync cancelling...'); + cancelGossipSync(); + + console.log('Express graph sync cancelled...'); + resolve(true); + } + }, 1000); + if (stores.settingsStore?.settings?.resetExpressGraphSyncOnStartup) { log.d('Clearing speedloader files'); try { @@ -166,17 +188,24 @@ export async function expressGraphSync() { try { const connectionState = await NetInfo.fetch(); - const gossipStatus = await gossipSync(connectionState.type); + const gossipStatus = await gossipSync( + 'https://speedloader.lnolymp.us/', + connectionState.type + ); + + clearInterval(timer); + const completionTime = (new Date().getTime() - start.getTime()) / 1000 + 's'; console.log('gossipStatus', `${gossipStatus} - ${completionTime}`); + stores.syncStore.setExpressGraphSyncStatus(false); + resolve(true); } catch (e) { log.e('GossipSync exception!', [e]); + stores.syncStore.setExpressGraphSyncStatus(false); + resolve(true); } - - stores.syncStore.setExpressGraphSyncStatus(false); - } - return; + }); } export async function initializeLnd( diff --git a/utils/NavigationUtils.ts b/utils/NavigationUtils.ts index 6f978ee4ee..1c97f9d408 100644 --- a/utils/NavigationUtils.ts +++ b/utils/NavigationUtils.ts @@ -1,7 +1,9 @@ +import { StackNavigationProp } from '@react-navigation/stack'; + import stores from '../stores/Stores'; const protectedNavigation = async ( - navigation: any, + navigation: StackNavigationProp, route: string, disactivatePOS?: boolean ) => { diff --git a/utils/ThemeUtils.ts b/utils/ThemeUtils.ts index 4c0068a97b..97ca04189d 100644 --- a/utils/ThemeUtils.ts +++ b/utils/ThemeUtils.ts @@ -322,6 +322,35 @@ export function themeColor(themeString: string): any { secondaryText: 'lightgray' }; + const Radioactive: { [key: string]: any } = { + generalStyle: 'dark', + background: '#000', + gradientBackground: ['#191919', '#000000'], + secondary: '#31363F', + text: 'white', + secondaryText: '#A7A9AC', + highlight: '#b8ff0f', + error: '#992600', + separator: '#31363F', + outbound: '#b8ff0f', + inbound: '#547506', + success: '#46BE43', + warning: '#E14C4C', + bitcoin: '#FFB040', + delete: '#992600', + qr: '#b8ff0f', + qrBackground: '#000', + qrLogoBackground: '#b8ff0f', + invertQrIcons: false, + qrFrame: '#FFD93F', + bolt: '#FFF', + chain: '#FFF', + disabled: '#767577', + buttonBackground: '#b8ff0f', + buttonText: '#000', + action: '#FFF' + }; + switch (theme) { case 'kyriaki': return Kyriaki[themeString] || Dark[themeString]; @@ -365,6 +394,8 @@ export function themeColor(themeString: string): any { return RedMetallic[themeString] || Dark[themeString]; case 'watermelon': return Watermelon[themeString] || Dark[themeString]; + case 'radioactive': + return Radioactive[themeString] || Dark[themeString]; default: return Dark[themeString]; } diff --git a/views/Accounts/Accounts.tsx b/views/Accounts/Accounts.tsx index 7ffb554d87..9898492b24 100644 --- a/views/Accounts/Accounts.tsx +++ b/views/Accounts/Accounts.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { TouchableOpacity } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -22,11 +24,15 @@ import Add from '../../assets/images/SVG/Add.svg'; import Filter from '../../assets/images/SVG/Filter On.svg'; interface AccountsProps { - navigation: any; + navigation: StackNavigationProp; BalanceStore: BalanceStore; UTXOsStore: UTXOsStore; UnitsStore: UnitsStore; SettingsStore: SettingsStore; + route: Route< + 'Accounts', + { value: string; amount: string; lightning: string; locked: boolean } + >; } interface AccountsState { @@ -57,34 +63,23 @@ export default class Accounts extends React.Component< } componentDidMount() { - const { navigation } = this.props; - const value: string = navigation.getParam('value'); - const amount: string = navigation.getParam('amount'); - const lightning: string = navigation.getParam('lightning'); - const locked: boolean = navigation.getParam('locked'); + const { route } = this.props; + const { value, amount, lightning, locked } = route.params ?? {}; if (value) { - this.setState({ - value - }); + this.setState({ value }); } if (amount) { - this.setState({ - amount - }); + this.setState({ amount }); } if (lightning) { - this.setState({ - lightning - }); + this.setState({ lightning }); } if (locked) { - this.setState({ - locked - }); + this.setState({ locked }); } } diff --git a/views/Accounts/ImportAccount.tsx b/views/Accounts/ImportAccount.tsx index 91d94caaca..b247287f67 100644 --- a/views/Accounts/ImportAccount.tsx +++ b/views/Accounts/ImportAccount.tsx @@ -7,6 +7,8 @@ import { View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import DropdownSetting from '../../components/DropdownSetting'; @@ -38,8 +40,17 @@ const AddressTypes = [ interface ImportAccountProps { exitSetup: any; - navigation: any; + navigation: StackNavigationProp; UTXOsStore: UTXOsStore; + route: Route< + 'ImportAccount', + { + name: string; + extended_public_key: string; + master_key_fingerprint: string; + address_type: number; + } + >; } interface ImportAccountState { @@ -65,46 +76,36 @@ export default class ImportAccount extends React.Component< }; } - handleParams = (navigation: any) => { - const name = navigation.getParam('name'); + handleParams = (props: ImportAccountProps) => { + const { + name, + extended_public_key, + master_key_fingerprint, + address_type + } = props.route.params ?? {}; if (name) { - this.setState({ - name - }); + this.setState({ name }); } - const extended_public_key = navigation.getParam('extended_public_key'); if (extended_public_key) { - this.setState({ - extended_public_key - }); + this.setState({ extended_public_key }); } - const master_key_fingerprint = navigation.getParam( - 'master_key_fingerprint' - ); if (master_key_fingerprint) { - this.setState({ - master_key_fingerprint - }); + this.setState({ master_key_fingerprint }); } - const address_type = navigation.getParam('address_type'); if (address_type) { - this.setState({ - address_type - }); + this.setState({ address_type }); } }; UNSAFE_componentWillMount = () => { - const { navigation } = this.props; - this.handleParams(navigation); + this.handleParams(this.props); }; - UNSAFE_componentWillReceiveProps = (newProps: any) => { - const { navigation } = newProps; - this.handleParams(navigation); + UNSAFE_componentWillReceiveProps = (newProps: ImportAccountProps) => { + this.handleParams(newProps); }; render() { diff --git a/views/Accounts/ImportingAccount.tsx b/views/Accounts/ImportingAccount.tsx index ecd1600793..e8fb656d38 100644 --- a/views/Accounts/ImportingAccount.tsx +++ b/views/Accounts/ImportingAccount.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { ScrollView, StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from './../../components/Button'; import Header from '../../components/Header'; @@ -21,7 +22,7 @@ import { walletrpc } from '../../proto/lightning'; interface ImportingAccountProps { exitSetup: any; - navigation: any; + navigation: StackNavigationProp; UTXOsStore: UTXOsStore; } diff --git a/views/Activity/Activity.tsx b/views/Activity/Activity.tsx index 8a040d95c9..6fdb88e7b2 100644 --- a/views/Activity/Activity.tsx +++ b/views/Activity/Activity.tsx @@ -11,6 +11,8 @@ import { import { Button, Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import BigNumber from 'bignumber.js'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../../components/Amount'; import Header from '../../components/Header'; @@ -31,11 +33,12 @@ import Filter from '../../assets/images/SVG/Filter On.svg'; import Invoice from '../../models/Invoice'; interface ActivityProps { - navigation: any; + navigation: StackNavigationProp; ActivityStore: ActivityStore; FiatStore: FiatStore; PosStore: PosStore; SettingsStore: SettingsStore; + route: Route<'Activity', { order: any }>; } interface ActivityState { @@ -135,7 +138,8 @@ export default class Activity extends React.PureComponent< ActivityStore, FiatStore, PosStore, - SettingsStore + SettingsStore, + route } = this.props; const { selectedPaymentForOrder } = this.state; @@ -145,7 +149,7 @@ export default class Activity extends React.PureComponent< const { settings } = SettingsStore; const { fiat } = settings; - const order = navigation.getParam('order', null); + const order = route.params?.order; const MarkPaymentButton = () => ( ; ActivityStore: ActivityStore; SettingsStore: SettingsStore; } diff --git a/views/AddNotes.tsx b/views/AddNotes.tsx index edf4f1f084..b91cffe70c 100644 --- a/views/AddNotes.tsx +++ b/views/AddNotes.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { Keyboard, TouchableOpacity, View } from 'react-native'; import EncryptedStorage from 'react-native-encrypted-storage'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../components/Header'; import Screen from '../components/Screen'; @@ -16,8 +18,12 @@ import TextInput from '../components/TextInput'; import SaveIcon from '../assets/images/SVG/Save.svg'; interface AddNotesProps { - navigation: any; + navigation: StackNavigationProp; NotesStore: NotesStore; + route: Route< + 'AddNotes', + { payment_hash: string; txid: string; getRPreimage: string } + >; } interface AddNotesState { notes?: string; @@ -35,15 +41,8 @@ export default class AddNotes extends React.Component< > { constructor(props: any) { super(props); - const payment_hash: string = this.props.navigation.getParam( - 'payment_hash', - null - ); - const txid: string = this.props.navigation.getParam('txid', null); - const getRPreimage: string = this.props.navigation.getParam( - 'getRPreimage', - null - ); + const { payment_hash, txid, getRPreimage } = + this.props.route.params ?? {}; this.state = { notes: '', diff --git a/views/BumpFee.tsx b/views/BumpFee.tsx index c1b36351a7..ca7b8805b3 100644 --- a/views/BumpFee.tsx +++ b/views/BumpFee.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'; import { ButtonGroup } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../components/Button'; import Header from '../components/Header'; @@ -21,9 +23,16 @@ import { themeColor } from '../utils/ThemeUtils'; import { localeString } from '../utils/LocaleUtils'; interface BumpFeeProps { - navigation: any; + navigation: StackNavigationProp; FeeStore: FeeStore; SettingsStore: SettingsStore; + route: Route< + 'BumpFee', + { + outpoint: string; + channel: boolean; + } + >; } interface BumpFeeState { @@ -42,7 +51,7 @@ export default class BumpFee extends React.PureComponent< > { constructor(props: any) { super(props); - const outpoint: string = this.props.navigation.getParam('outpoint', ''); + const outpoint = this.props.route.params?.outpoint ?? ''; this.state = { outpoint, target_conf: '1', @@ -63,7 +72,7 @@ export default class BumpFee extends React.PureComponent< }; render() { - const { FeeStore, SettingsStore, navigation } = this.props; + const { FeeStore, SettingsStore, navigation, route } = this.props; const { outpoint, target_conf, sat_per_vbyte, force, target_type } = this.state; @@ -78,7 +87,7 @@ export default class BumpFee extends React.PureComponent< const { privacy } = settings; const enableMempoolRates = privacy && privacy.enableMempoolRates; - const isChannel = navigation.getParam('channel', false); + const isChannel = route.params?.channel; const feeRateButton = () => ( ; ChannelsStore: ChannelsStore; SettingsStore: SettingsStore; NodeInfoStore: NodeInfoStore; + route: Route<'Channel', { channel: Channel }>; } interface ChannelState { @@ -62,8 +66,8 @@ export default class ChannelView extends React.Component< listener: any; constructor(props: ChannelProps) { super(props); - const { navigation, ChannelsStore } = props; - const channel: Channel = navigation.getParam('channel', null); + const { route, ChannelsStore } = props; + const channel = route.params?.channel; this.state = { confirmCloseChannel: false, @@ -592,12 +596,6 @@ export default class ChannelView extends React.Component< }) } warning={!confirmCloseChannel} - titleStyle={{ - color: 'white' - }} - buttonStyle={{ - backgroundColor: themeColor('delete') - }} /> )} @@ -630,6 +628,7 @@ export default class ChannelView extends React.Component< satPerByte: text }); }} + navigation={navigation} /> <> diff --git a/views/Channels/ChannelsPane.tsx b/views/Channels/ChannelsPane.tsx index 46748fd323..5464c8683e 100644 --- a/views/Channels/ChannelsPane.tsx +++ b/views/Channels/ChannelsPane.tsx @@ -10,6 +10,7 @@ import { } from 'react-native'; import { inject, observer } from 'mobx-react'; import { duration } from 'moment'; +import { StackNavigationProp } from '@react-navigation/stack'; import { ChannelsHeader } from '../../components/Channels/ChannelsHeader'; import { ChannelItem } from '../../components/Channels/ChannelItem'; @@ -40,7 +41,7 @@ export enum Status { } interface ChannelsProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore?: ChannelsStore; SettingsStore?: SettingsStore; } diff --git a/views/ContactDetails.tsx b/views/ContactDetails.tsx index 7f937a88df..7823b2c22f 100644 --- a/views/ContactDetails.tsx +++ b/views/ContactDetails.tsx @@ -8,6 +8,9 @@ import { ScrollView } from 'react-native'; import EncryptedStorage from 'react-native-encrypted-storage'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import Screen from '../components/Screen'; import Button from '../components/Button'; import LoadingIndicator from '../components/LoadingIndicator'; @@ -29,7 +32,15 @@ import { localeString } from '../utils/LocaleUtils'; import Contact from '../models/Contact'; interface ContactDetailsProps { - navigation: any; + navigation: StackNavigationProp; + route: Route< + 'ContactDetails', + { + isNostrContact: boolean; + contactId: string; + nostrContact: any; + } + >; } interface ContactDetailsState { @@ -68,10 +79,7 @@ export default class ContactDetails extends React.Component< try { await this.fetchContact(); - const isNostrContact = this.props.navigation.getParam( - 'isNostrContact', - null - ); + const isNostrContact = this.props.route.params?.isNostrContact; this.setState({ isNostrContact }); } catch (error) { @@ -80,16 +88,10 @@ export default class ContactDetails extends React.Component< } fetchContact = async () => { - this.props.navigation.addListener('didFocus', async () => { + this.props.navigation.addListener('focus', async () => { try { - const contactId = this.props.navigation.getParam( - 'contactId', - null - ); - const nostrContact = this.props.navigation.getParam( - 'nostrContact', - null - ); + const { contactId, nostrContact } = + this.props.route.params ?? {}; const contactsString = await EncryptedStorage.getItem( 'zeus-contacts' ); @@ -203,10 +205,7 @@ export default class ContactDetails extends React.Component< const { navigation } = this.props; const contact = new Contact(this.state.contact); - const nostrContact = this.props.navigation.getParam( - 'nostrContact', - null - ); + const nostrContact = this.props.route.params?.nostrContact; const StarButton = () => ( ; + route: Route< + 'ContactQR', + { + contactData: string; + addressData: string[]; + } + >; } const ContactQR: React.FC = (props: ContactQRProps) => { const [addressData, setAddressData] = useState(['']); - const { navigation } = props; + const { navigation, route } = props; useEffect(() => { - const contactData = navigation.getParam('contactData', null); - const addressData = navigation.getParam('addressData', null); - + const { contactData, addressData } = route.params ?? {}; setAddressData([contactData, ...addressData]); - }, [navigation]); + }, [route]); let screenWidth: number; const progressValue = useSharedValue(0); diff --git a/views/EditFee.tsx b/views/EditFee.tsx index 9c52bc2e82..d2d35654f1 100644 --- a/views/EditFee.tsx +++ b/views/EditFee.tsx @@ -8,9 +8,12 @@ import { TextInput, View, TouchableOpacity, - TouchableWithoutFeedback + TouchableWithoutFeedback, + Keyboard } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../components/Button'; import Header from '../components/Header'; @@ -30,8 +33,16 @@ import SettingsStore from './../stores/SettingsStore'; interface EditFeeProps { FeeStore: FeeStore; SettingsStore: SettingsStore; - navigation: any; + navigation: StackNavigationProp; displayOnly?: boolean; + route: Route< + 'EditFee', + { + fee: any; + displayOnly: boolean; + onNavigateBack: (fee: any) => {}; + } + >; } interface EditFeeState { @@ -56,14 +67,14 @@ export default class EditFee extends React.Component< } async UNSAFE_componentWillMount() { - const { FeeStore, SettingsStore, navigation } = this.props; - const fee = navigation.getParam('fee', null); + const { FeeStore, SettingsStore, route } = this.props; + const fee = route.params?.fee; const { settings } = SettingsStore; const fees: any = await FeeStore.getOnchainFeesviaMempool(); const preferredMempoolRate = settings?.payments?.preferredMempoolRate || 'fastestFee'; - if (fee && fees[preferredMempoolRate] === fee) { + if (fee && fees?.[preferredMempoolRate] === fee) { this.setState({ selectedFee: preferredMempoolRate, fee @@ -72,9 +83,9 @@ export default class EditFee extends React.Component< } render() { - const { selectedFee } = this.state; - const { navigation, FeeStore } = this.props; - const displayOnly = navigation.getParam('displayOnly', null); + const { selectedFee, fee, customFee } = this.state; + const { navigation, FeeStore, route } = this.props; + const displayOnly = route.params?.displayOnly; const { recommendedFees, loading, error, getOnchainFeesviaMempool } = FeeStore; @@ -101,7 +112,7 @@ export default class EditFee extends React.Component< : localeString('views.EditFee.title'), style: { color: themeColor('text') } }} - rightComponent={ReloadButton} + rightComponent={ReloadButton()} navigation={navigation} /> - {loading && !error && ( + {loading && ( - + )} {recommendedFees['fastestFee'] && !loading && ( @@ -136,14 +147,15 @@ export default class EditFee extends React.Component< }} > + onPress={() => { this.setState({ selectedFee: 'fastestFee', fee: recommendedFees[ 'fastestFee' ].toString() - }) - } + }); + Keyboard.dismiss(); + }} > + onPress={() => { this.setState({ selectedFee: 'halfHourFee', fee: recommendedFees[ 'halfHourFee' ].toString() - }) - } + }); + Keyboard.dismiss(); + }} > - + onPress={() => { this.setState({ selectedFee: 'hourFee', fee: recommendedFees[ 'hourFee' ].toString() - }) - } + }); + Keyboard.dismiss(); + }} > + onPress={() => { this.setState({ selectedFee: 'minimumFee', fee: recommendedFees[ 'minimumFee' ].toString() - }) - } + }); + Keyboard.dismiss(); + }} > - - {!displayOnly && ( - <> - - {localeString( - 'views.EditFee.custom' - )} - - - - this.setState({ - customFee: text, - fee: text, - selectedFee: 'custom' - }) - } - onFocus={() => - this.setState({ - selectedFee: 'custom' - }) - } - > - - - - - - )} )} {error && !loading && ( - + {localeString('views.EditFee.error')} )} + {!displayOnly && !loading && ( + + + {localeString('general.custom')} + + + { + text = text.replace(/[^0-9]*/g, ''); + this.setState({ + customFee: text, + fee: text, + selectedFee: 'custom' + }); + }} + onFocus={() => + this.setState({ + selectedFee: 'custom' + }) + } + /> + + + + + + )} diff --git a/views/Explanations/LspExplanationFees.tsx b/views/Explanations/LspExplanationFees.tsx index 0bfc445800..c399968b3a 100644 --- a/views/Explanations/LspExplanationFees.tsx +++ b/views/Explanations/LspExplanationFees.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Text, View } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; import NavigationService from '../../NavigationService'; @@ -12,7 +13,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import UrlUtils from '../../utils/UrlUtils'; interface LspExplanationProps { - navigation: any; + navigation: StackNavigationProp; } const FONT_SIZE = 18; diff --git a/views/Explanations/LspExplanationOverview.tsx b/views/Explanations/LspExplanationOverview.tsx index 0610615989..72213ea87c 100644 --- a/views/Explanations/LspExplanationOverview.tsx +++ b/views/Explanations/LspExplanationOverview.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Text, ScrollView } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; import NavigationService from '../../NavigationService'; import Button from '../../components/Button'; @@ -10,7 +11,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface LspExplanationOverviewProps { - navigation: any; + navigation: StackNavigationProp; } const FONT_SIZE = 17; diff --git a/views/Explanations/LspExplanationRouting.tsx b/views/Explanations/LspExplanationRouting.tsx index fb212ac73a..090e13a1f4 100644 --- a/views/Explanations/LspExplanationRouting.tsx +++ b/views/Explanations/LspExplanationRouting.tsx @@ -1,5 +1,6 @@ import React from 'react'; import { Text, View } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; import NavigationService from '../../NavigationService'; @@ -11,7 +12,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface LspExplanationProps { - navigation: any; + navigation: StackNavigationProp; } const FONT_SIZE = 18; diff --git a/views/Explanations/LspExplanationWrappedInvoices.tsx b/views/Explanations/LspExplanationWrappedInvoices.tsx index c49a189fe7..7d66159dc0 100644 --- a/views/Explanations/LspExplanationWrappedInvoices.tsx +++ b/views/Explanations/LspExplanationWrappedInvoices.tsx @@ -1,5 +1,7 @@ import React from 'react'; import { Text, ScrollView } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import Screen from '../../components/Screen'; import Header from '../../components/Header'; @@ -7,7 +9,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface LspExplanationWrappedInvoicesProps { - navigation: any; + navigation: StackNavigationProp; } const FONT_SIZE = 18; diff --git a/views/handleAnythingQRScanner.tsx b/views/HandleAnythingQRScanner.tsx similarity index 93% rename from views/handleAnythingQRScanner.tsx rename to views/HandleAnythingQRScanner.tsx index e729b3bcd0..415b7b7e02 100644 --- a/views/handleAnythingQRScanner.tsx +++ b/views/HandleAnythingQRScanner.tsx @@ -3,6 +3,7 @@ import { Alert, View } from 'react-native'; import { Header } from 'react-native-elements'; import { observer } from 'mobx-react'; import { URDecoder } from '@ngraveio/bc-ur'; +import { StackNavigationProp } from '@react-navigation/stack'; import LoadingIndicator from '../components/LoadingIndicator'; import QRCodeScanner from '../components/QRCodeScanner'; @@ -13,11 +14,11 @@ import { joinQRs } from '../utils/BbqrUtils'; import { localeString } from '../utils/LocaleUtils'; import { themeColor } from '../utils/ThemeUtils'; -interface handleAnythingQRProps { - navigation: any; +interface HandleAnythingQRProps { + navigation: StackNavigationProp; } -interface handleAnythingQRState { +interface HandleAnythingQRState { loading: boolean; mode: string; totalParts: number; @@ -25,9 +26,9 @@ interface handleAnythingQRState { } @observer -export default class handleAnythingQRScanner extends React.Component< - handleAnythingQRProps, - handleAnythingQRState +export default class HandleAnythingQRScanner extends React.Component< + HandleAnythingQRProps, + HandleAnythingQRState > { decoder: any; constructor(props: any) { @@ -187,7 +188,9 @@ export default class handleAnythingQRScanner extends React.Component< return ( navigation.goBack()} + goBack={() => { + navigation.goBack(); + }} navigation={navigation} parts={parts.length} totalParts={totalParts} diff --git a/views/Intro.tsx b/views/Intro.tsx index 04ac7b4182..a0b8b077aa 100644 --- a/views/Intro.tsx +++ b/views/Intro.tsx @@ -9,6 +9,7 @@ import Animated, { useSharedValue } from 'react-native-reanimated'; import Carousel from 'react-native-reanimated-carousel'; +import { StackNavigationProp } from '@react-navigation/stack'; import stores from '../stores/Stores'; @@ -30,7 +31,7 @@ const Four = require('../assets/images/intro/4.png'); import Wordmark from '../assets/images/SVG/wordmark-black.svg'; interface IntroProps { - navigation: any; + navigation: StackNavigationProp; } const Intro: React.FC = (props) => { diff --git a/views/IntroSplash.tsx b/views/IntroSplash.tsx index 236e1468f7..464350d872 100644 --- a/views/IntroSplash.tsx +++ b/views/IntroSplash.tsx @@ -9,6 +9,7 @@ import { Text } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Globe from '../assets/images/SVG/Globe.svg'; import Wordmark from '../assets/images/SVG/wordmark-black.svg'; @@ -27,7 +28,7 @@ import { themeColor } from '../utils/ThemeUtils'; import TresArrows from '../assets/images/SVG/TresArrows.svg'; interface IntroSplashProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } @@ -52,7 +53,7 @@ export default class IntroSplash extends React.Component< componentDidMount() { // triggers when loaded from navigation or back action - this.props.navigation.addListener('didFocus', () => { + this.props.navigation.addListener('focus', () => { this.props.SettingsStore.getSettings(); }); diff --git a/views/Invoice.tsx b/views/Invoice.tsx index c20b8e8ecf..b5734b34d6 100644 --- a/views/Invoice.tsx +++ b/views/Invoice.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; import EncryptedStorage from 'react-native-encrypted-storage'; - import { StyleSheet, ScrollView, View, TouchableOpacity } from 'react-native'; import { inject } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import SettingsStore from '../stores/SettingsStore'; @@ -23,8 +24,9 @@ import EditNotes from '../assets/images/SVG/Pen.svg'; import QR from '../assets/images/SVG/QR.svg'; interface InvoiceProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore?: SettingsStore; + route: Route<'InvoiceView', { invoice: Invoice }>; } @inject('SettingsStore') @@ -33,9 +35,9 @@ export default class InvoiceView extends React.Component { storedNotes: '' }; async componentDidMount() { - const { navigation } = this.props; - const invoice: Invoice = navigation.getParam('invoice', null); - navigation.addListener('didFocus', () => { + const { navigation, route } = this.props; + const invoice = route.params?.invoice; + navigation.addListener('focus', () => { const noteKey = invoice.getRPreimage || invoice.payment_hash; EncryptedStorage.getItem('note-' + noteKey) .then((storedNotes) => { @@ -48,9 +50,9 @@ export default class InvoiceView extends React.Component { } render() { - const { navigation, SettingsStore } = this.props; + const { navigation, SettingsStore, route } = this.props; const { storedNotes } = this.state; - const invoice: Invoice = navigation.getParam('invoice', null); + const invoice = route.params?.invoice; const locale = SettingsStore?.settings.locale; invoice.determineFormattedOriginalTimeUntilExpiry(locale); invoice.determineFormattedRemainingTimeUntilExpiry(locale); diff --git a/views/LnurlAuth.tsx b/views/LnurlAuth.tsx index eb11400190..f28e263a19 100644 --- a/views/LnurlAuth.tsx +++ b/views/LnurlAuth.tsx @@ -5,6 +5,8 @@ import { inject, observer } from 'mobx-react'; import { Alert, StyleSheet, Text, View } from 'react-native'; import querystring from 'querystring-es3'; import { HMAC as sha256HMAC } from 'fast-sha256'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../components/Button'; import Header from '../components/Header'; @@ -29,8 +31,9 @@ const LNURLAUTH_CANONICAL_PHRASE = 'DO NOT EVER SIGN THIS TEXT WITH YOUR PRIVATE KEYS! IT IS ONLY USED FOR DERIVATION OF LNURL-AUTH HASHING-KEY, DISCLOSING ITS SIGNATURE WILL COMPROMISE YOUR LNURL-AUTH IDENTITY AND MAY LEAD TO LOSS OF FUNDS!'; interface LnurlAuthProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; + route: Route<'LnurlAuth', { lnurlParams: any }>; } interface LnurlAuthState { @@ -85,8 +88,8 @@ export default class LnurlAuth extends React.Component< } stateFromProps(props: LnurlAuthProps) { - const { navigation } = props; - const lnurl = navigation.getParam('lnurlParams'); + const { route } = props; + const lnurl = route.params?.lnurlParams; return { domain: lnurl.domain, @@ -164,9 +167,9 @@ export default class LnurlAuth extends React.Component< sendValues() { this.setState({ authenticating: true }); - const { navigation } = this.props; + const { route } = this.props; const { domain } = this.state; - const lnurl = navigation.getParam('lnurlParams'); + const lnurl = route.params?.lnurlParams; const u = url.parse(lnurl.callback); const qs = querystring.parse(u.query); qs.key = this.state.linkingKeyPub; diff --git a/views/LnurlChannel.tsx b/views/LnurlChannel.tsx index 131c9db77c..3d7c391ce9 100644 --- a/views/LnurlChannel.tsx +++ b/views/LnurlChannel.tsx @@ -4,6 +4,8 @@ import ReactNativeBlobUtil from 'react-native-blob-util'; import { Alert, StyleSheet, Switch, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; import querystring from 'querystring-es3'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../components/Button'; import Header from '../components/Header'; @@ -23,9 +25,10 @@ import NodeUriUtils from '../utils/NodeUriUtils'; import BackendUtils from '../utils/BackendUtils'; interface LnurlChannelProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; NodeInfoStore: NodeInfoStore; + route: Route<'LnurlChannel', { lnurlParams: any }>; } interface LnurlChannelState { @@ -74,8 +77,8 @@ export default class LnurlChannel extends React.Component< } stateFromProps(props: LnurlChannelProps) { - const { navigation } = props; - const lnurl = navigation.getParam('lnurlParams'); + const { route } = props; + const lnurl = route.params?.lnurlParams; const { pubkey, host } = NodeUriUtils.processNodeUri(lnurl.uri); return { @@ -126,9 +129,9 @@ export default class LnurlChannel extends React.Component< } sendValues() { - const { navigation, NodeInfoStore } = this.props; + const { route, NodeInfoStore } = this.props; const { domain, k1 } = this.state; - const lnurl = navigation.getParam('lnurlParams'); + const lnurl = route.params?.lnurlParams; const u = url.parse(lnurl.callback); const qs = querystring.parse(u.query); qs.k1 = k1; @@ -180,7 +183,7 @@ export default class LnurlChannel extends React.Component< } render() { - const { navigation } = this.props; + const { navigation, route } = this.props; const { domain, privateChannel, @@ -188,7 +191,7 @@ export default class LnurlChannel extends React.Component< lnurlChannelSuccess, errorMsgPeer } = this.state; - const lnurl = navigation.getParam('lnurlParams'); + const lnurl = route.params?.lnurlParams; return ( diff --git a/views/LnurlPay/Historical.tsx b/views/LnurlPay/Historical.tsx index de45c58c19..e48029e5a6 100644 --- a/views/LnurlPay/Historical.tsx +++ b/views/LnurlPay/Historical.tsx @@ -1,12 +1,14 @@ import * as React from 'react'; import { Text, View, TouchableOpacity } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import { LnurlPayTransaction } from './../../stores/LnurlPayStore'; import LnurlPayMetadata from './Metadata'; import LnurlPaySuccess from './Success'; import { themeColor } from './../../utils/ThemeUtils'; interface LnurlPayHistoricalProps { - navigation: any; + navigation: StackNavigationProp; lnurlpaytx: LnurlPayTransaction; preimage: string; } diff --git a/views/LnurlPay/LnurlPay.tsx b/views/LnurlPay/LnurlPay.tsx index 3a4a5cc7a0..2cb694f5fb 100644 --- a/views/LnurlPay/LnurlPay.tsx +++ b/views/LnurlPay/LnurlPay.tsx @@ -4,6 +4,8 @@ import ReactNativeBlobUtil from 'react-native-blob-util'; import { Alert, StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; import querystring from 'querystring-es3'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../../components/Amount'; import AmountInput from '../../components/AmountInput'; @@ -24,10 +26,11 @@ import { themeColor } from '../../utils/ThemeUtils'; import { ScrollView } from 'react-native-gesture-handler'; interface LnurlPayProps { - navigation: any; + navigation: StackNavigationProp; InvoicesStore: InvoicesStore; LnurlPayStore: LnurlPayStore; UnitsStore: UnitsStore; + route: Route<'LnurlPay', { lnurlParams: any; amount: any }>; } interface LnurlPayState { @@ -66,9 +69,8 @@ export default class LnurlPay extends React.Component< } stateFromProps(props: LnurlPayProps) { - const { UnitsStore, navigation } = props; - const lnurl = navigation.getParam('lnurlParams'); - const amount = navigation.getParam('amount'); + const { UnitsStore, route } = props; + const { lnurlParams: lnurl, amount } = route.params ?? {}; UnitsStore.resetUnits(); @@ -83,9 +85,9 @@ export default class LnurlPay extends React.Component< } sendValues(satAmount: string | number) { - const { navigation, InvoicesStore, LnurlPayStore } = this.props; + const { navigation, InvoicesStore, LnurlPayStore, route } = this.props; const { domain, comment } = this.state; - const lnurl = navigation.getParam('lnurlParams'); + const lnurl = route.params?.lnurlParams; const u = url.parse(lnurl.callback); const qs = querystring.parse(u.query); qs.amount = Number((parseFloat(satAmount) * 1000).toString()); @@ -180,10 +182,10 @@ export default class LnurlPay extends React.Component< } render() { - const { navigation } = this.props; + const { navigation, route } = this.props; const { amount, satAmount, domain, comment } = this.state; - const lnurl = navigation.getParam('lnurlParams'); + const lnurl = route.params?.lnurlParams; return ( diff --git a/views/Lockscreen.tsx b/views/Lockscreen.tsx index 27d63f93bc..76dcfa7c4b 100644 --- a/views/Lockscreen.tsx +++ b/views/Lockscreen.tsx @@ -9,6 +9,8 @@ import { Text, View } from 'react-native'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../components/Button'; import Header from '../components/Header'; @@ -26,8 +28,17 @@ import { localeString } from '../utils/LocaleUtils'; import { themeColor } from '../utils/ThemeUtils'; interface LockscreenProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; + route: Route< + 'Lockscreen', + { + modifySecurityScreen: string; + deletePin: boolean; + deleteDuressPin: boolean; + attemptAdminLogin: boolean; + } + >; } interface LockscreenState { @@ -89,15 +100,14 @@ export default class Lockscreen extends React.Component< }; async UNSAFE_componentWillMount() { - const { SettingsStore, navigation } = this.props; + const { SettingsStore, navigation, route } = this.props; const { settings } = SettingsStore; - const modifySecurityScreen: string = navigation.getParam( - 'modifySecurityScreen' - ); - const deletePin: boolean = navigation.getParam('deletePin'); - const deleteDuressPin: boolean = navigation.getParam('deleteDuressPin'); - const attemptAdminLogin: boolean = - navigation.getParam('attemptAdminLogin'); + const { + modifySecurityScreen, + deletePin, + deleteDuressPin, + attemptAdminLogin + } = route.params ?? {}; const posEnabled: PosEnabled = (settings && settings.pos && settings.pos.posEnabled) || diff --git a/views/NetworkInfo.tsx b/views/NetworkInfo.tsx index fc3a2a9575..2d6b482f98 100644 --- a/views/NetworkInfo.tsx +++ b/views/NetworkInfo.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { FlatList, StyleSheet } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../components/Header'; import KeyValue from '../components/KeyValue'; @@ -12,7 +13,7 @@ import { themeColor } from '../utils/ThemeUtils'; import NodeInfoStore from '../stores/NodeInfoStore'; interface NetworkInfoProps { - navigation: any; + navigation: StackNavigationProp; NodeInfoStore: NodeInfoStore; } diff --git a/views/NodeInfo.tsx b/views/NodeInfo.tsx index 9b03850122..3573b6d3e2 100644 --- a/views/NodeInfo.tsx +++ b/views/NodeInfo.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { RefreshControl, StyleSheet, ScrollView } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import CollapsedQR from '../components/CollapsedQR'; import Header from '../components/Header'; @@ -15,7 +16,7 @@ import NodeInfoStore from '../stores/NodeInfoStore'; import SettingsStore from '../stores/SettingsStore'; interface NodeInfoProps { - navigation: any; + navigation: StackNavigationProp; NodeInfoStore: NodeInfoStore; SettingsStore: SettingsStore; } diff --git a/views/NodeQRScanner.tsx b/views/NodeQRScanner.tsx index f2c153cc0e..cbbc942f19 100644 --- a/views/NodeQRScanner.tsx +++ b/views/NodeQRScanner.tsx @@ -1,11 +1,14 @@ import * as React from 'react'; import { Alert } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import QRCodeScanner from './../components/QRCodeScanner'; + import NodeUriUtils from './../utils/NodeUriUtils'; import { localeString } from './../utils/LocaleUtils'; interface NodeQRProps { - navigation: any; + navigation: StackNavigationProp; } function NodeQRScanner(props: NodeQRProps) { diff --git a/views/NostrContacts.tsx b/views/NostrContacts.tsx index e7abd0a192..bdc712c7bc 100644 --- a/views/NostrContacts.tsx +++ b/views/NostrContacts.tsx @@ -12,6 +12,7 @@ import { import { CheckBox, Icon } from 'react-native-elements'; import EncryptedStorage from 'react-native-encrypted-storage'; import { relayInit, nip05, nip19 } from 'nostr-tools'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../components/Button'; import Header from '../components/Header'; @@ -32,7 +33,7 @@ import SelectOff from '../assets/images/SVG/Select Off.svg'; import SelectOn from '../assets/images/SVG/Select On.svg'; interface NostrContactsProps { - navigation: any; + navigation: StackNavigationProp; } interface NostrContactsState { diff --git a/views/OpenChannel.tsx b/views/OpenChannel.tsx index ee146d32b7..c22dacefeb 100644 --- a/views/OpenChannel.tsx +++ b/views/OpenChannel.tsx @@ -10,6 +10,8 @@ import { import Clipboard from '@react-native-clipboard/clipboard'; import { inject, observer } from 'mobx-react'; import NfcManager, { NfcEvents, TagEvent } from 'react-native-nfc-manager'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../components/Amount'; import AmountInput from '../components/AmountInput'; @@ -50,13 +52,14 @@ import Scan from '../assets/images/SVG/Scan.svg'; interface OpenChannelProps { exitSetup: any; - navigation: any; + navigation: StackNavigationProp; BalanceStore: BalanceStore; ChannelsStore: ChannelsStore; ModalStore: ModalStore; NodeInfoStore: NodeInfoStore; SettingsStore: SettingsStore; UTXOsStore: UTXOsStore; + route: Route<'OpenChannel', { node_pubkey_string: string; host: string }>; } interface OpenChannelState { @@ -209,14 +212,11 @@ export default class OpenChannel extends React.Component< this.initFromProps(nextProps); } - initFromProps(props: any) { - const { navigation } = props; + initFromProps(props: OpenChannelProps) { + const { route } = props; - const node_pubkey_string = navigation.getParam( - 'node_pubkey_string', - '' - ); - const host = navigation.getParam('host', ''); + const node_pubkey_string = route.params?.node_pubkey_string ?? ''; + const host = route.params?.host ?? ''; this.setState({ node_pubkey_string, @@ -790,6 +790,7 @@ export default class OpenChannel extends React.Component< sat_per_vbyte: text }); }} + navigation={navigation} /> diff --git a/views/Order.tsx b/views/Order.tsx index 27a96399c9..493ba09877 100644 --- a/views/Order.tsx +++ b/views/Order.tsx @@ -10,6 +10,8 @@ import { import { ButtonGroup } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import BigNumber from 'bignumber.js'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../components/Amount'; import Button from '../components/Button'; @@ -30,11 +32,12 @@ import RNPrint from 'react-native-print'; import PosStore from '../stores/PosStore'; interface OrderProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; FiatStore: FiatStore; UnitsStore: UnitsStore; PosStore: PosStore; + route: Route<'Order', { orderId: string; order: any; print: boolean }>; } interface OrderState { @@ -50,11 +53,10 @@ interface OrderState { @inject('FiatStore', 'SettingsStore', 'UnitsStore', 'PosStore') @observer export default class OrderView extends React.Component { - constructor(props: any) { + constructor(props: OrderProps) { super(props); - const { SettingsStore, navigation } = props; - const order = navigation.getParam('order', null); - const print = navigation.getParam('print', false); + const { SettingsStore, route } = props; + const { order, print } = route.params ?? {}; const { settings } = SettingsStore; const disableTips: boolean = @@ -75,12 +77,8 @@ export default class OrderView extends React.Component { // print and order id are passed from the paid screen // we update the order so it includes payment details // which will enable the receipt printing - if ( - this.props.navigation.getParam('print', false) !== - prevProps.navigation.getParam('print', false) - ) { - const orderId = this.props.navigation.getParam('orderId', null); - const print = this.props.navigation.getParam('print', false); + if (this.props.route.params?.print !== prevProps.route.params?.print) { + const { orderId, print } = this.props.route.params ?? {}; const { PosStore } = this.props; if (orderId) { diff --git a/views/POS/Categories.tsx b/views/POS/Categories.tsx index 270073d2d2..836b7bf230 100644 --- a/views/POS/Categories.tsx +++ b/views/POS/Categories.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { FlatList, Text, TouchableOpacity, View } from 'react-native'; import { ListItem, SearchBar } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import LoadingIndicator from '../../components/LoadingIndicator'; @@ -17,7 +18,7 @@ import ProductCategory from '../../models/ProductCategory'; import AddIcon from '../../assets/images/SVG/Add.svg'; interface ProductCategoriesProps { - navigation: any; + navigation: StackNavigationProp; InventoryStore: InventoryStore; } @@ -40,7 +41,7 @@ export default class ProductCategories extends React.Component< }; async componentDidMount() { - this.props.navigation.addListener('didFocus', async () => { + this.props.navigation.addListener('focus', async () => { this.loadCategories(); }); } @@ -84,7 +85,11 @@ export default class ProductCategories extends React.Component< const { navigation } = this.props; const { categories, search, loading } = this.state; - const Add = ({ navigation }: { navigation: any }) => ( + const Add = ({ + navigation + }: { + navigation: StackNavigationProp; + }) => ( navigation.navigate('ProductCategoryDetails')} > diff --git a/views/POS/ProductCategoryDetails.tsx b/views/POS/ProductCategoryDetails.tsx index 503f1bbef0..400d3980d9 100644 --- a/views/POS/ProductCategoryDetails.tsx +++ b/views/POS/ProductCategoryDetails.tsx @@ -12,6 +12,8 @@ import InventoryStore from '../../stores/InventoryStore'; import { inject, observer } from 'mobx-react'; import { v4 as uuidv4 } from 'uuid'; import { Divider, Icon } from 'react-native-elements'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -26,9 +28,10 @@ import DeleteIcon from '../../assets/images/SVG/Delete.svg'; import PosStore from '../../stores/PosStore'; interface ProductCategoryProps { - navigation: any; + navigation: StackNavigationProp; InventoryStore: InventoryStore; PosStore: PosStore; + route: Route<'ProductCategoryDetails', { categoryId: string }>; } interface ProductCategoryState { @@ -59,12 +62,9 @@ export default class ProductCategoryDetails extends React.Component< } fetchCategory = async () => { - this.props.navigation.addListener('didFocus', async () => { + this.props.navigation.addListener('focus', async () => { try { - const categoryId = this.props.navigation.getParam( - 'categoryId', - null - ); + const categoryId = this.props.route.params?.categoryId; if (!categoryId) { this.setState({ @@ -159,9 +159,7 @@ export default class ProductCategoryDetails extends React.Component< const BackButton = () => ( { - navigation.goBack(); - }} + onPress={() => navigation.goBack()} color={themeColor('text')} underlayColor="transparent" size={35} diff --git a/views/POS/ProductDetails.tsx b/views/POS/ProductDetails.tsx index 328062957b..30dce59b2d 100644 --- a/views/POS/ProductDetails.tsx +++ b/views/POS/ProductDetails.tsx @@ -13,6 +13,8 @@ import UnitsStore from '../../stores/UnitsStore'; import { inject, observer } from 'mobx-react'; import { v4 as uuidv4 } from 'uuid'; import { Divider, ListItem } from 'react-native-elements'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -30,10 +32,11 @@ import DropdownSetting from '../../components/DropdownSetting'; import PosStore from '../../stores/PosStore'; interface ProductProps { - navigation: any; + navigation: StackNavigationProp; InventoryStore: InventoryStore; PosStore: PosStore; UnitsStore: UnitsStore; + route: Route<'ProductDetails', { productId: string }>; } interface ProductState { @@ -67,83 +70,82 @@ export default class ProductDetails extends React.Component< componentWillUnmount(): void { this.props.navigation.removeListener && - this.props.navigation.removeListener('didFocus'); + this.props.navigation.removeListener('focus', this.handleFocus); } fetchProduct = async () => { - this.props.navigation.addListener('didFocus', async () => { - try { - const { InventoryStore } = this.props; - const { getInventory } = InventoryStore; - const { products, categories } = await getInventory(); - - const mappedCategories = categories - ? categories.map((category: any) => ({ - key: category.name, - value: category.name - })) - : []; - let categoryOptions: any[] = [ - { - key: 'Uncategorized', - value: '', - translateKey: 'pos.views.Wallet.PosPane.uncategorized' - } - ]; - categoryOptions = categoryOptions.concat(...mappedCategories); + this.props.navigation.addListener('focus', this.handleFocus); + }; - const productId = this.props.navigation.getParam( - 'productId', - null - ); + handleFocus = async () => { + try { + const { InventoryStore } = this.props; + const { getInventory } = InventoryStore; + const { products, categories } = await getInventory(); - if (!productId) { - this.setState({ - categories: categoryOptions, - product: new Product({ - id: uuidv4(), - name: '', - sku: '', - pricedIn: PricedIn.Fiat, - price: 0, - category: '', - status: ProductStatus.Active - }), - isLoading: false, - isExisting: false - }); - return; + const mappedCategories = categories + ? categories.map((category: any) => ({ + key: category.name, + value: category.name + })) + : []; + let categoryOptions: any[] = [ + { + key: 'Uncategorized', + value: '', + translateKey: 'pos.views.Wallet.PosPane.uncategorized' } + ]; + categoryOptions = categoryOptions.concat(...mappedCategories); - if (products) { - const product = - products.find( - (product: Product) => product.id === productId - ) || null; + const productId = this.props.route.params?.productId; - if (product) { - if (this.props.UnitsStore.units !== product.pricedIn) { - // change unit to match product - while ( - this.props.UnitsStore.units !== product.pricedIn - ) { - this.props.UnitsStore.changeUnits(); - } - } + if (!productId) { + this.setState({ + categories: categoryOptions, + product: new Product({ + id: uuidv4(), + name: '', + sku: '', + pricedIn: PricedIn.Fiat, + price: 0, + category: '', + status: ProductStatus.Active + }), + isLoading: false, + isExisting: false + }); + return; + } + + if (products) { + const product = + products.find( + (product: Product) => product.id === productId + ) || null; - this.setState({ - categories: categoryOptions, - product, - isLoading: false, - isExisting: true - }); + if (product) { + if (this.props.UnitsStore.units !== product.pricedIn) { + // change unit to match product + while ( + this.props.UnitsStore.units !== product.pricedIn + ) { + this.props.UnitsStore.changeUnits(); + } } + + this.setState({ + categories: categoryOptions, + product, + isLoading: false, + isExisting: true + }); } - } catch (error) { - console.log('Error fetching product:', error); - this.setState({ isLoading: false }); } - }); + } catch (error) { + console.log('Error fetching product:', error); + this.setState({ isLoading: false }); + } }; setValue = (field: string, value: any) => { diff --git a/views/POS/Products.tsx b/views/POS/Products.tsx index 77e2835144..a3e8065024 100644 --- a/views/POS/Products.tsx +++ b/views/POS/Products.tsx @@ -3,6 +3,7 @@ import { FlatList, Text, TouchableOpacity, View } from 'react-native'; import { ListItem, SearchBar } from 'react-native-elements'; import AddIcon from '../../assets/images/SVG/Add.svg'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import LoadingIndicator from '../../components/LoadingIndicator'; @@ -15,7 +16,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import Product from '../../models/Product'; interface ProductsProps { - navigation: any; + navigation: StackNavigationProp; InventoryStore: InventoryStore; } @@ -38,9 +39,9 @@ export default class Products extends React.Component< }; async componentDidMount() { - this.props.navigation.addListener('didFocus', async () => { - this.loadProducts(); - }); + this.props.navigation.addListener('focus', async () => + this.loadProducts() + ); } async loadProducts() { @@ -82,7 +83,11 @@ export default class Products extends React.Component< const { navigation } = this.props; const { products, search, loading } = this.state; - const Add = ({ navigation }: { navigation: any }) => ( + const Add = ({ + navigation + }: { + navigation: StackNavigationProp; + }) => ( navigation.navigate('ProductDetails')} > diff --git a/views/PSBT.tsx b/views/PSBT.tsx index 18ff8f638b..c1e8cb7f0a 100644 --- a/views/PSBT.tsx +++ b/views/PSBT.tsx @@ -3,6 +3,8 @@ import { ScrollView, StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; import { ButtonGroup } from 'react-native-elements'; import { UR, UREncoder } from '@ngraveio/bc-ur'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; const bitcoin = require('bitcoinjs-lib'); @@ -23,9 +25,10 @@ import ChannelsStore from '../stores/ChannelsStore'; import TransactionsStore from '../stores/TransactionsStore'; interface PSBTProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; TransactionsStore: TransactionsStore; + route: Route<'PSBT', { psbt: string }>; } interface PSBTState { @@ -54,8 +57,8 @@ export default class PSBT extends React.Component { }; UNSAFE_componentWillMount(): void { - const { navigation } = this.props; - const psbt: string = navigation.getParam('psbt'); + const { route } = this.props; + const psbt = route.params?.psbt; this.setState( { fundedPsbt: psbt diff --git a/views/Payment.tsx b/views/Payment.tsx index ca5ee24254..ca6ff4d1d5 100644 --- a/views/Payment.tsx +++ b/views/Payment.tsx @@ -9,6 +9,8 @@ import { } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import { Row } from '../components/layout/Row'; import Amount from '../components/Amount'; @@ -32,10 +34,11 @@ import LnurlPayHistorical from './LnurlPay/Historical'; import EditNotes from '../assets/images/SVG/Pen.svg'; interface PaymentProps { - navigation: any; + navigation: StackNavigationProp; LnurlPayStore?: LnurlPayStore; NodeInfoStore?: NodeInfoStore; SettingsStore?: SettingsStore; + route: Route<'Payment', { payment: Payment }>; } @inject('LnurlPayStore', 'NodeInfoStore', 'SettingsStore') @@ -47,15 +50,15 @@ export default class PaymentView extends React.Component { }; async componentDidMount() { - const { navigation, LnurlPayStore } = this.props; - const payment: Payment = navigation.getParam('payment', null); + const { navigation, LnurlPayStore, route } = this.props; + const payment = route.params?.payment; const lnurlpaytx = payment.paymentHash ? await LnurlPayStore!.load(payment.paymentHash) : undefined; if (lnurlpaytx) { this.setState({ lnurlpaytx }); } - navigation.addListener('didFocus', () => { + navigation.addListener('focus', () => { const noteKey = payment.noteKey; EncryptedStorage.getItem('note-' + noteKey) @@ -69,11 +72,11 @@ export default class PaymentView extends React.Component { } render() { - const { navigation, SettingsStore, NodeInfoStore } = this.props; + const { navigation, SettingsStore, NodeInfoStore, route } = this.props; const { storedNotes, lnurlpaytx } = this.state; const { testnet } = NodeInfoStore; - const payment: Payment = navigation.getParam('payment', null); + const payment = route.params?.payment; const formattedOriginalTimeUntilExpiry = payment.getFormattedOriginalTimeUntilExpiry( SettingsStore!.settings.locale diff --git a/views/PaymentPaths.tsx b/views/PaymentPaths.tsx index b06e449b20..02cb902cb6 100644 --- a/views/PaymentPaths.tsx +++ b/views/PaymentPaths.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { ScrollView, StyleSheet, View } from 'react-native'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../components/Header'; import PaymentPath from '../components/PaymentPath'; @@ -11,14 +13,15 @@ import { localeString } from '../utils/LocaleUtils'; import { themeColor } from '../utils/ThemeUtils'; interface PaymentPathsViewProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; + route: Route<'PaymentPaths', { enhancedPath: any[] }>; } export default class PaymentPathsView extends React.Component { render() { - const { navigation } = this.props; - const enhancedPath = navigation.getParam('enhancedPath', null); + const { navigation, route } = this.props; + const enhancedPath = route.params?.enhancedPath; return ( diff --git a/views/PaymentRequest.tsx b/views/PaymentRequest.tsx index 4de0e16707..b02a9d9031 100644 --- a/views/PaymentRequest.tsx +++ b/views/PaymentRequest.tsx @@ -9,6 +9,7 @@ import { TouchableOpacity } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../components/Amount'; import AmountInput from '../components/AmountInput'; @@ -54,7 +55,7 @@ const zaplockerDestinations = [ interface InvoiceProps { exitSetup: any; - navigation: any; + navigation: StackNavigationProp; BalanceStore: BalanceStore; InvoicesStore: InvoicesStore; TransactionsStore: TransactionsStore; @@ -76,8 +77,8 @@ interface InvoiceState { feeOption: string; maxFeePercent: string; timeoutSeconds: string; - outgoingChanId: string | null; - lastHopPubkey: string | null; + outgoingChanId: string | undefined; + lastHopPubkey: string | undefined; settingsToggle: boolean; zaplockerToggle: boolean; lightningReadyToSend: boolean; @@ -775,13 +776,12 @@ export default class PaymentRequest extends React.Component< { this.setState({ outgoingChanId: - item - ? item.channelId - : null + channels[0] + ?.channelId }) } title={localeString( @@ -798,13 +798,12 @@ export default class PaymentRequest extends React.Component< { this.setState({ lastHopPubkey: - item - ? item.remote_pubkey - : null + channels[0] + ?.channelId }) } title={localeString( diff --git a/views/QR.tsx b/views/QR.tsx index ad4802b021..d71cd6c9bb 100644 --- a/views/QR.tsx +++ b/views/QR.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { Dimensions, View } from 'react-native'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import CollapsedQR from '../components/CollapsedQR'; import Header from '../components/Header'; @@ -9,7 +11,17 @@ import Text from '../components/Text'; import { themeColor } from '../utils/ThemeUtils'; interface QRProps { - navigation: any; + navigation: StackNavigationProp; + route: Route< + 'QR', + { + value: string; + label: string; + hideText: boolean; + jumboLabel: boolean; + logo: any; + } + >; } interface QRState { @@ -21,21 +33,12 @@ interface QRState { } export default class QR extends React.PureComponent { - constructor(props: any) { + constructor(props: QRProps) { super(props); - const value: string = this.props.navigation.getParam('value', ''); - const label: string = this.props.navigation.getParam('label', ''); - const hideText: boolean = this.props.navigation.getParam( - 'hideText', - false - ); - const jumboLabel: boolean = this.props.navigation.getParam( - 'jumboLabel', - false - ); - - const logo: any = this.props.navigation.getParam('logo', null); + const value = props.route.params?.value ?? ''; + const label = props.route.params?.label ?? ''; + const { hideText, jumboLabel, logo } = props.route.params ?? {}; this.state = { value, diff --git a/views/RawTxHex.tsx b/views/RawTxHex.tsx index 57a54dacc2..d14a82a2bb 100644 --- a/views/RawTxHex.tsx +++ b/views/RawTxHex.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { Dimensions, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import { SuccessMessage, @@ -21,8 +23,18 @@ import stores from '../stores/Stores'; import TransactionsStore from '../stores/TransactionsStore'; interface RawTxHexProps { - navigation: any; + navigation: StackNavigationProp; TransactionsStore: TransactionsStore; + route: Route< + 'RawTxHex', + { + value: string; + label: string; + hideText: boolean; + jumboLabel: boolean; + logo: any; + } + >; } interface RawTxHexState { @@ -39,21 +51,12 @@ export default class RawTxHex extends React.PureComponent< RawTxHexProps, RawTxHexState > { - constructor(props: any) { + constructor(props: RawTxHexProps) { super(props); - const value: string = this.props.navigation.getParam('value', ''); - const label: string = this.props.navigation.getParam('label', ''); - const hideText: boolean = this.props.navigation.getParam( - 'hideText', - false - ); - const jumboLabel: boolean = this.props.navigation.getParam( - 'jumboLabel', - false - ); - - const logo: any = this.props.navigation.getParam('logo', null); + const value = props.route.params?.value ?? ''; + const label = props.route.params?.label ?? ''; + const { hideText, jumboLabel, logo } = props.route.params ?? {}; this.state = { value, diff --git a/views/Receive.tsx b/views/Receive.tsx index 1550f3e337..e83806a0f1 100644 --- a/views/Receive.tsx +++ b/views/Receive.tsx @@ -14,12 +14,13 @@ import { LNURLWithdrawParams } from 'js-lnurl'; import { ButtonGroup, Icon } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import _map from 'lodash/map'; - import NfcManager, { NfcEvents, TagEvent, Ndef } from 'react-native-nfc-manager'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import handleAnything from '../utils/handleAnything'; @@ -55,6 +56,7 @@ import Text from '../components/Text'; import TextInput from '../components/TextInput'; import Invoice from '../models/Invoice'; +import Channel from '../models/Channel'; import ChannelsStore from '../stores/ChannelsStore'; import ModalStore from '../stores/ModalStore'; @@ -85,10 +87,11 @@ import OnChainSvg from '../assets/images/SVG/DynamicSVG/OnChainSvg'; import AddressSvg from '../assets/images/SVG/DynamicSVG/AddressSvg'; import Gear from '../assets/images/SVG/Gear.svg'; import DropdownSetting from '../components/DropdownSetting'; +import HopPicker from '../components/HopPicker'; interface ReceiveProps { exitSetup: any; - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; InvoicesStore: InvoicesStore; PosStore: PosStore; @@ -98,6 +101,23 @@ interface ReceiveProps { UnitsStore: UnitsStore; LSPStore: LSPStore; LightningAddressStore: LightningAddressStore; + route: Route< + 'Receive', + { + lnurlParams: LNURLWithdrawParams | undefined; + amount: string; + autoGenerate: boolean; + autoGenerateOnChain: boolean; + account: string; + selectedIndex: number; + memo: string; + orderId: string; + orderTotal: string; + orderTip: string; + exchangeRate: string; + rate: number; + } + >; } interface ReceiveState { @@ -125,6 +145,13 @@ interface ReceiveState { enableLSP: boolean; lspIsActive: boolean; lspNotConfigured: boolean; + routeHintMode: RouteHintMode; + selectedRouteHintChannels?: Channel[]; +} + +enum RouteHintMode { + Automatic = 0, + Custom = 1 } @inject( @@ -146,7 +173,8 @@ export default class Receive extends React.Component< listenerSecondary: any; lnInterval: any; onChainInterval: any; - state = { + hopPickerRef: HopPicker | null; + state: ReceiveState = { selectedIndex: 0, expirationIndex: 1, addressType: '0', @@ -170,16 +198,18 @@ export default class Receive extends React.Component< needInbound: false, enableLSP: true, lspIsActive: false, - lspNotConfigured: true + lspNotConfigured: true, + routeHintMode: RouteHintMode.Automatic, + selectedRouteHintChannels: undefined }; async UNSAFE_componentWillMount() { const { - navigation, InvoicesStore, SettingsStore, LightningAddressStore, - NodeInfoStore + NodeInfoStore, + route } = this.props; const { reset } = InvoicesStore; const { getSettings, posStatus } = SettingsStore; @@ -234,15 +264,15 @@ export default class Receive extends React.Component< settings.pos.confirmationPreference === 'lnOnly'; reset(); - const lnurl: LNURLWithdrawParams | undefined = - navigation.getParam('lnurlParams'); - const amount: string = navigation.getParam('amount'); - const autoGenerate: boolean = navigation.getParam('autoGenerate'); - const autoGenerateOnChain: boolean = navigation.getParam( - 'autoGenerateOnChain' - ); - const account: string = navigation.getParam('account'); + const { + lnurlParams: lnurl, + amount, + autoGenerate, + autoGenerateOnChain, + account, + selectedIndex + } = route.params ?? {}; if (account) { this.setState({ @@ -250,8 +280,6 @@ export default class Receive extends React.Component< }); } - const selectedIndex: number = navigation.getParam('selectedIndex'); - if (selectedIndex) { this.setState({ selectedIndex @@ -262,12 +290,9 @@ export default class Receive extends React.Component< this.state; // POS - const memo: string = navigation.getParam('memo', this.state.memo); - const orderId: string = navigation.getParam('orderId'); - const orderTotal: string = navigation.getParam('orderTotal'); - const orderTip: string = navigation.getParam('orderTip'); - const exchangeRate: string = navigation.getParam('exchangeRate'); - const rate: number = navigation.getParam('rate'); + const memo = route.params?.memo ?? this.state.memo; + const { orderId, orderTotal, orderTip, exchangeRate, rate } = + route.params ?? {}; if (orderId) { this.setState({ @@ -339,13 +364,11 @@ export default class Receive extends React.Component< } async UNSAFE_componentWillReceiveProps(nextProps: any) { - const { navigation, InvoicesStore } = nextProps; + const { route, InvoicesStore } = nextProps; const { reset } = InvoicesStore; reset(); - const amount: string = navigation.getParam('amount'); - const lnurl: LNURLWithdrawParams | undefined = - navigation.getParam('lnurlParams'); + const { amount, lnurlParams: lnurl } = route.params ?? {}; if (amount) { let needInbound = false; @@ -425,6 +448,7 @@ export default class Receive extends React.Component< undefined, lspIsActive ? false : ampInvoice || false, lspIsActive ? false : routeHints || false, + undefined, BackendUtils.supportsAddressTypeSelection() ? addressType || '1' : undefined, @@ -518,10 +542,10 @@ export default class Receive extends React.Component< }; validateAddress = (text: string) => { - const { navigation, InvoicesStore } = this.props; + const { navigation, InvoicesStore, route } = this.props; const { lspIsActive } = this.state; const { createUnifiedInvoice } = InvoicesStore; - const amount = getSatAmount(navigation.getParam('amount')); + const amount = getSatAmount(route.params?.amount); handleAnything(text, amount.toString()) .then((response) => { @@ -543,6 +567,7 @@ export default class Receive extends React.Component< undefined, undefined, undefined, + undefined, !lspIsActive ) .then( @@ -553,7 +578,6 @@ export default class Receive extends React.Component< rHash: string; onChainAddress?: string; }) => { - navigation.setParam; this.subscribeInvoice( rHash, onChainAddress @@ -952,7 +976,8 @@ export default class Receive extends React.Component< LightningAddressStore, LSPStore, NodeInfoStore, - navigation + navigation, + route } = this.props; const { selectedIndex, @@ -971,7 +996,9 @@ export default class Receive extends React.Component< needInbound, enableLSP, lspIsActive, - lspNotConfigured + lspNotConfigured, + routeHintMode, + selectedRouteHintChannels } = this.state; const { fontScale } = Dimensions.get('window'); @@ -1010,8 +1037,7 @@ export default class Receive extends React.Component< settings.pos.confirmationPreference && settings.pos.confirmationPreference === 'lnOnly'; - const lnurl: LNURLWithdrawParams | undefined = - navigation.getParam('lnurlParams'); + const lnurl = route.params?.lnurlParams; const ClearButton = () => ( ( + + {localeString('general.automatic')} + + ) + }, + { + element: () => ( + + {localeString('general.custom')} + + ) + } + ]; + + const setRouteHintMode = (mode: RouteHintMode) => { + if (this.state.routeHintMode === mode) { + return; + } + this.setState({ + routeHintMode: mode + }); + if ( + mode === RouteHintMode.Custom && + (!selectedRouteHintChannels || + selectedRouteHintChannels.length === 0) + ) { + this.hopPickerRef?.openPicker(); + } + }; + const enablePrinter: boolean = settings?.pos?.enablePrinter || false; return ( @@ -1847,7 +1922,11 @@ export default class Receive extends React.Component< onValueChange={async () => { this.setState({ enableLSP: - !enableLSP + !enableLSP, + lspIsActive: + !enableLSP && + BackendUtils.supportsLSPs() && + !lspNotConfigured }); await updateSettings( { @@ -2353,6 +2432,103 @@ export default class Receive extends React.Component< )} + {BackendUtils.isLNDBased() && + routeHints && ( + + + {localeString( + 'general.mode' + )} + + + + )} + + {BackendUtils.isLNDBased() && + routeHints && ( + + (this.hopPickerRef = + ref) + } + onValueChange={( + channels + ) => { + this.setState({ + selectedRouteHintChannels: + channels + }); + }} + onCancel={() => { + if ( + !selectedRouteHintChannels?.length + ) { + setRouteHintMode( + RouteHintMode.Automatic + ); + } + }} + title={localeString( + 'views.Receive.customRouteHints' + )} + ChannelsStore={ + this.props.ChannelsStore + } + UnitsStore={UnitsStore} + containerStyle={{ + display: + routeHintMode === + RouteHintMode.Automatic + ? 'none' + : 'flex' + }} + clearOnTap={false} + selectionMode={'multiple'} + selectedChannels={ + selectedRouteHintChannels + } + /> + )} + {BackendUtils.supportsAMP() && !lspIsActive && ( <> @@ -2414,6 +2590,10 @@ export default class Receive extends React.Component< : ampInvoice || false, routeHints, + routeHintMode === + RouteHintMode.Custom + ? selectedRouteHintChannels + : undefined, BackendUtils.supportsAddressTypeSelection() ? addressType : undefined, diff --git a/views/Routing/Routing.tsx b/views/Routing/Routing.tsx index dc9405aec4..0677176a8f 100644 --- a/views/Routing/Routing.tsx +++ b/views/Routing/Routing.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { FlatList, View, Text, TouchableOpacity } from 'react-native'; import { ButtonGroup } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import { ErrorMessage } from '../../components/SuccessErrorMessage'; @@ -21,7 +22,7 @@ import { RoutingListItem } from './RoutingListItem'; import { RoutingHeader } from './RoutingHeader'; interface RoutingProps { - navigation: any; + navigation: StackNavigationProp; FeeStore: FeeStore; } @@ -99,7 +100,11 @@ export default class Routing extends React.PureComponent< })` : localeString('general.routing'); - const FeeBadge = ({ navigation }: { navigation: any }) => ( + const FeeBadge = ({ + navigation + }: { + navigation: StackNavigationProp; + }) => ( navigation.navigate('SetFees')}> diff --git a/views/Routing/RoutingEvent.tsx b/views/Routing/RoutingEvent.tsx index 1df03ccbf8..d6fd0072db 100644 --- a/views/Routing/RoutingEvent.tsx +++ b/views/Routing/RoutingEvent.tsx @@ -7,6 +7,9 @@ import { View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import ForwardEvent from '../../models/ForwardEvent'; import Amount from '../../components/Amount'; @@ -21,8 +24,9 @@ import { themeColor } from '../../utils/ThemeUtils'; import ChannelsStore from '../../stores/ChannelsStore'; interface RoutingEventProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; + route: Route<'RoutingEvent', { routingEvent: ForwardEvent }>; } interface RoutingEventState { @@ -35,14 +39,11 @@ export default class RoutingEvent extends React.Component< RoutingEventProps, RoutingEventState > { - constructor(props: any) { + constructor(props: RoutingEventProps) { super(props); - const { navigation } = props; + const { route } = props; - const routingEvent: ForwardEvent = navigation.getParam( - 'routingEvent', - null - ); + const routingEvent = route.params?.routingEvent; const { chan_id_in, chan_id_out } = routingEvent; diff --git a/views/Routing/SetFees.tsx b/views/Routing/SetFees.tsx index 68016d2d34..0b5ae9daac 100644 --- a/views/Routing/SetFees.tsx +++ b/views/Routing/SetFees.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { ScrollView, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -17,17 +19,18 @@ import { themeColor } from '../../utils/ThemeUtils'; import { localeString } from '../../utils/LocaleUtils'; interface SetFeesProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; FeeStore: FeeStore; NodeInfoStore: NodeInfoStore; + route: Route<'SetFees', { channel: Channel }>; } @inject('ChannelsStore', 'FeeStore', 'NodeInfoStore') @observer export default class SetFees extends React.PureComponent { render() { - const { ChannelsStore, FeeStore, NodeInfoStore, navigation } = + const { ChannelsStore, FeeStore, NodeInfoStore, navigation, route } = this.props; const { chanInfo, nodes } = ChannelsStore; @@ -35,7 +38,7 @@ export default class SetFees extends React.PureComponent { const { nodeInfo } = NodeInfoStore; const { nodeId } = nodeInfo; - const channel: Channel = navigation.getParam('channel', null); + const channel = route.params?.channel; let peerName; if (channel) { diff --git a/views/Send.tsx b/views/Send.tsx index c13f7cb513..2e948cae2d 100644 --- a/views/Send.tsx +++ b/views/Send.tsx @@ -15,15 +15,15 @@ import { } from 'react-native'; import { Chip, Icon } from 'react-native-elements'; import EncryptedStorage from 'react-native-encrypted-storage'; - import Clipboard from '@react-native-clipboard/clipboard'; import { inject, observer } from 'mobx-react'; - import NfcManager, { NfcEvents, TagEvent, Ndef } from 'react-native-nfc-manager'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import handleAnything, { isClipboardValue } from '../utils/handleAnything'; @@ -66,7 +66,7 @@ import { AdditionalOutput } from '../models/TransactionRequest'; interface SendProps { exitSetup: any; - navigation: any; + navigation: StackNavigationProp; BalanceStore: BalanceStore; InvoicesStore: InvoicesStore; ModalStore: ModalStore; @@ -74,6 +74,17 @@ interface SendProps { TransactionsStore: TransactionsStore; SettingsStore: SettingsStore; UTXOsStore: UTXOsStore; + route: Route< + 'Send', + { + destination: string; + amount: string; + transactionType: string | null; + isValid: boolean; + contactName: string; + clearOnBackPress: boolean; + } + >; } interface SendState { @@ -118,16 +129,10 @@ export default class Send extends React.Component { constructor(props: SendProps) { super(props); - const { navigation } = props; - const destination = navigation.getParam('destination', null); - const amount = navigation.getParam('amount', null); - const transactionType = navigation.getParam('transactionType', null); - const isValid = navigation.getParam('isValid', false); - const contactName = navigation.getParam('contactName', null); - const clearOnBackPress = navigation.getParam( - 'clearOnBackPress', - !destination - ); + const { route } = props; + const { destination, amount, transactionType, isValid, contactName } = + route.params ?? {}; + const clearOnBackPress = route.params?.clearOnBackPress ?? !destination; if (transactionType === 'Lightning') { this.props.InvoicesStore.getPayReq(destination); @@ -178,11 +183,9 @@ export default class Send extends React.Component { } UNSAFE_componentWillReceiveProps(nextProps: any) { - const { navigation } = nextProps; - const destination = navigation.getParam('destination', null); - const amount = navigation.getParam('amount', null); - const transactionType = navigation.getParam('transactionType', null); - const contactName = navigation.getParam('contactName', null); + const { route } = nextProps; + const { destination, amount, transactionType, contactName } = + route.params ?? {}; if (transactionType === 'Lightning') { this.props.InvoicesStore.getPayReq(destination); @@ -220,7 +223,7 @@ export default class Send extends React.Component { } loadContacts = async () => { - this.props.navigation.addListener('didFocus', async () => { + this.props.navigation.addListener('focus', async () => { try { const contactsString = await EncryptedStorage.getItem( 'zeus-contacts' @@ -1088,6 +1091,7 @@ export default class Send extends React.Component { onChangeFee={(text: string) => this.setState({ fee: text }) } + navigation={navigation} /> ; TransactionsStore: TransactionsStore; LnurlPayStore: LnurlPayStore; } @@ -49,7 +50,7 @@ export default class SendingLightning extends React.Component< componentDidMount() { const { TransactionsStore, navigation } = this.props; - navigation.addListener('didFocus', () => { + navigation.addListener('focus', () => { const noteKey = typeof TransactionsStore.payment_hash === 'string' ? TransactionsStore.payment_hash @@ -263,13 +264,13 @@ export default class SendingLightning extends React.Component< {(!!error || !!payment_error) && !LnurlPayStore.isZaplocker && ( - ; NodeInfoStore: NodeInfoStore; TransactionsStore: TransactionsStore; } @@ -36,7 +37,7 @@ export default class SendingOnChain extends React.Component< }; async componentDidMount() { const { TransactionsStore, navigation } = this.props; - navigation.addListener('didFocus', () => { + navigation.addListener('focus', () => { EncryptedStorage.getItem('note-' + TransactionsStore.txid) .then((storedNotes) => { this.setState({ storedNotes }); @@ -135,13 +136,13 @@ export default class SendingOnChain extends React.Component< )} {(error || error_msg) && ( - ; + route: Route< + 'AddContact', + { isEdit: boolean; prefillContact: Contact; isNostrContact: boolean } + >; } interface Contact { @@ -112,7 +118,7 @@ export default class AddContact extends React.Component< }; saveContact = async () => { - const { navigation } = this.props; + const { navigation, route } = this.props; const { lnAddress, onchainAddress, @@ -125,9 +131,7 @@ export default class AddContact extends React.Component< isFavourite } = this.state; - const isEdit = !!navigation.getParam('isEdit', false); - const prefillContact = navigation.getParam('prefillContact', null); - const isNostrContact = navigation.getParam('isNostrContact', null); + const { isEdit, prefillContact, isNostrContact } = route.params ?? {}; try { // Retrieve existing contacts from storage @@ -217,8 +221,8 @@ export default class AddContact extends React.Component< }; deleteContact = async () => { - const { navigation } = this.props; - const prefillContact = navigation.getParam('prefillContact', null); + const { navigation, route } = this.props; + const prefillContact = route.params?.prefillContact; if (prefillContact) { try { @@ -335,15 +339,9 @@ export default class AddContact extends React.Component< this.handlePrefillContact(); } - componentDidUpdate(prevProps) { - const prefillContact = this.props.navigation.getParam( - 'prefillContact', - null - ); - const prevPrefillContact = prevProps.navigation.getParam( - 'prefillContact', - null - ); + componentDidUpdate(prevProps: AddContactProps) { + const prefillContact = this.props.route.params?.prefillContact; + const prevPrefillContact = prevProps.route.params?.prefillContact; // Check if the prefillContact prop has changed if (prefillContact !== prevPrefillContact) { @@ -352,10 +350,7 @@ export default class AddContact extends React.Component< } handlePrefillContact() { - const prefillContact = this.props.navigation.getParam( - 'prefillContact', - null - ); + const prefillContact = this.props.route.params?.prefillContact; if (prefillContact) { this.setState({ @@ -421,13 +416,13 @@ export default class AddContact extends React.Component< /> ); - const isEdit = !!this.props.navigation.getParam('isEdit', false); - const prefillContact = this.props.navigation.getParam( - 'prefillContact', - null - ); + const { isEdit, prefillContact } = this.props.route.params ?? {}; - const ScanBadge = ({ navigation }: { navigation: any }) => ( + const ScanBadge = ({ + navigation + }: { + navigation: StackNavigationProp; + }) => ( navigation.navigate('HandleAnythingQRScanner')} accessibilityLabel={localeString('general.scan')} @@ -450,27 +445,27 @@ export default class AddContact extends React.Component< }} behavior={Platform.OS === 'ios' ? 'padding' : undefined} > +
+ + + + } + containerStyle={{ + borderBottomWidth: 0 + }} + navigation={navigation} + /> -
- - - - } - containerStyle={{ - borderBottomWidth: 0 - }} - navigation={navigation} - /> )} diff --git a/views/Settings/CertInstallInstructions.tsx b/views/Settings/CertInstallInstructions.tsx index 987dd88c36..95e6b85beb 100644 --- a/views/Settings/CertInstallInstructions.tsx +++ b/views/Settings/CertInstallInstructions.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { Platform, StyleSheet, Text, View, ScrollView } from 'react-native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -8,7 +9,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface CertInstallInstructionsProps { - navigation: any; + navigation: StackNavigationProp; } export default class CertInstallInstructions extends React.Component< diff --git a/views/Settings/ChannelsSettings.tsx b/views/Settings/ChannelsSettings.tsx index 0933e4e292..c11b50af12 100644 --- a/views/Settings/ChannelsSettings.tsx +++ b/views/Settings/ChannelsSettings.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -14,7 +15,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface ChannelsSettingsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/Contacts.tsx b/views/Settings/Contacts.tsx index 7eb53c91ac..a86bfd4be7 100644 --- a/views/Settings/Contacts.tsx +++ b/views/Settings/Contacts.tsx @@ -9,6 +9,8 @@ import { } from 'react-native'; import { SearchBar, Divider } from 'react-native-elements'; import EncryptedStorage from 'react-native-encrypted-storage'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Screen from '../../components/Screen'; import Button from '../../components/Button'; @@ -24,7 +26,8 @@ import Add from '../../assets/images/SVG/Add.svg'; import NostrichIcon from '../../assets/images/SVG/Nostrich.svg'; interface ContactsSettingsProps { - navigation: any; + navigation: StackNavigationProp; + route: Route<'Contacts', { SendScreen: boolean; loading: boolean }>; } interface ContactsSettingsState { @@ -41,10 +44,7 @@ export default class Contacts extends React.Component< > { constructor(props: ContactsSettingsProps) { super(props); - const SendScreen: boolean = this.props.navigation.getParam( - 'SendScreen', - null - ); + const SendScreen = this.props.route.params?.SendScreen; this.state = { contacts: [], search: '', @@ -55,20 +55,16 @@ export default class Contacts extends React.Component< } componentDidMount() { - this.props.navigation.addListener('didFocus', async () => { - this.loadContacts(); - }); + this.props.navigation.addListener('focus', () => this.loadContacts()); } UNSAFE_componentWillReceiveProps( nextProps: Readonly ): void { - const loading: boolean = nextProps.navigation.getParam('loading', null); + const loading = nextProps.route.params?.loading; if (loading) { - this.setState({ - loading - }); + this.setState({ loading }); } } diff --git a/views/Settings/Currency.tsx b/views/Settings/Currency.tsx index c87763afec..e16bb8a0ef 100644 --- a/views/Settings/Currency.tsx +++ b/views/Settings/Currency.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Screen from '../../components/Screen'; import Header from '../../components/Header'; @@ -21,7 +22,7 @@ import DropdownSetting from '../../components/DropdownSetting'; import Switch from '../../components/Switch'; interface CurrencyProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; UnitsStore: UnitsStore; } diff --git a/views/Settings/CurrencyConverter.tsx b/views/Settings/CurrencyConverter.tsx index 1aebe15a30..e0c52102c3 100644 --- a/views/Settings/CurrencyConverter.tsx +++ b/views/Settings/CurrencyConverter.tsx @@ -12,6 +12,9 @@ import Svg, { Text } from 'react-native-svg'; import DragList, { DragListRenderItemInfo } from 'react-native-draglist'; import { Icon } from 'react-native-elements'; import EncryptedStorage from 'react-native-encrypted-storage'; +import { isEmpty } from 'lodash'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Screen from '../../components/Screen'; import Header from '../../components/Header'; @@ -29,12 +32,12 @@ import Add from '../../assets/images/SVG/Add.svg'; import Edit from '../../assets/images/SVG/Pen.svg'; import DragDots from '../../assets/images/SVG/DragDots.svg'; import BitcoinIcon from '../../assets/images/SVG/bitcoin-icon.svg'; -import { isEmpty } from 'lodash'; interface CurrencyConverterProps { - navigation: any; + navigation: StackNavigationProp; FiatStore?: FiatStore; SettingsStore?: SettingsStore; + route: Route<'CurrencyConverter', { selectedCurrency: string }>; } interface CurrencyConverterState { @@ -69,22 +72,17 @@ export default class CurrencyConverter extends React.Component< } componentDidMount() { - const { navigation } = this.props; this.retrieveInputValues(); this.addDefaultCurrenciesToStorage(); - const selectedCurrency = navigation.getParam('selectedCurrency', ''); + const selectedCurrency = this.props.route.params?.selectedCurrency; if (selectedCurrency) { this.handleCurrencySelect(selectedCurrency); } } - componentDidUpdate(prevProps) { - const { navigation } = this.props; - const selectedCurrency = navigation.getParam('selectedCurrency', ''); - const prevSelectedCurrency = prevProps.navigation.getParam( - 'selectedCurrency', - '' - ); + componentDidUpdate(prevProps: CurrencyConverterProps) { + const selectedCurrency = this.props.route.params?.selectedCurrency; + const prevSelectedCurrency = prevProps.route.params?.selectedCurrency; // Check if the selected currency prop has changed if (selectedCurrency !== prevSelectedCurrency) { diff --git a/views/Settings/CustodialWalletWarning.tsx b/views/Settings/CustodialWalletWarning.tsx index 287ecf85ba..b76fad7c10 100644 --- a/views/Settings/CustodialWalletWarning.tsx +++ b/views/Settings/CustodialWalletWarning.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, Text, View, ScrollView } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -13,7 +14,7 @@ import SettingsStore from '../../stores/SettingsStore'; interface CustodialWalletWarningProps { SettingsStore: SettingsStore; - navigation: any; + navigation: StackNavigationProp; } @inject('SettingsStore') diff --git a/views/Settings/Display.tsx b/views/Settings/Display.tsx index 38d799befb..8e5cca6ed7 100644 --- a/views/Settings/Display.tsx +++ b/views/Settings/Display.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { ScrollView, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; + import SettingsStore, { DEFAULT_VIEW_KEYS, THEME_KEYS @@ -15,7 +17,7 @@ import Screen from '../../components/Screen'; import Switch from '../../components/Switch'; interface DisplayProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/Advanced.tsx b/views/Settings/EmbeddedNode/Advanced.tsx index 9e05a9e93e..988f9693f1 100644 --- a/views/Settings/EmbeddedNode/Advanced.tsx +++ b/views/Settings/EmbeddedNode/Advanced.tsx @@ -3,6 +3,7 @@ import { Platform, NativeModules, ScrollView, Text, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import AsyncStorage from '@react-native-async-storage/async-storage'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import Header from '../../../components/Header'; @@ -19,7 +20,7 @@ import { themeColor } from '../../../utils/ThemeUtils'; import { stopLnd } from '../../../utils/LndMobileUtils'; interface EmbeddedNodeAdvancedSettingsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/DisasterRecovery.tsx b/views/Settings/EmbeddedNode/DisasterRecovery.tsx index dc1d06014d..cdc3f403f9 100644 --- a/views/Settings/EmbeddedNode/DisasterRecovery.tsx +++ b/views/Settings/EmbeddedNode/DisasterRecovery.tsx @@ -4,6 +4,7 @@ import { ListItem, Divider } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import Clipboard from '@react-native-clipboard/clipboard'; import EncryptedStorage from 'react-native-encrypted-storage'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import Screen from '../../../components/Screen'; @@ -22,7 +23,7 @@ import { themeColor } from '../../../utils/ThemeUtils'; import { exportAllChannelBackups } from '../../../lndmobile/channel'; interface DisasterRecoveryProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/DisasterRecoveryAdvanced.tsx b/views/Settings/EmbeddedNode/DisasterRecoveryAdvanced.tsx index e8d575d9ef..e1af4bd908 100644 --- a/views/Settings/EmbeddedNode/DisasterRecoveryAdvanced.tsx +++ b/views/Settings/EmbeddedNode/DisasterRecoveryAdvanced.tsx @@ -3,6 +3,7 @@ import { FlatList, Text, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import moment from 'moment'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import Screen from '../../../components/Screen'; @@ -15,7 +16,7 @@ import { themeColor } from '../../../utils/ThemeUtils'; import LoadingIndicator from '../../../components/LoadingIndicator'; interface DisasterRecoveryAdvancedProps { - navigation: any; + navigation: StackNavigationProp; ChannelBackupStore: ChannelBackupStore; } diff --git a/views/Settings/EmbeddedNode/ExpressGraphSync.tsx b/views/Settings/EmbeddedNode/ExpressGraphSync.tsx index 6e34ceb251..bb1e8aeb6e 100644 --- a/views/Settings/EmbeddedNode/ExpressGraphSync.tsx +++ b/views/Settings/EmbeddedNode/ExpressGraphSync.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { ScrollView, Text, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../../components/Header'; import Screen from '../../../components/Screen'; @@ -14,7 +15,7 @@ import { restartNeeded } from '../../../utils/RestartUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface ExpressGraphSyncProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/LNDLogs.tsx b/views/Settings/EmbeddedNode/LNDLogs.tsx index 210fbb7167..7e5ceb085d 100644 --- a/views/Settings/EmbeddedNode/LNDLogs.tsx +++ b/views/Settings/EmbeddedNode/LNDLogs.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { NativeModules, Platform, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import CopyButton from '../../../components/CopyButton'; import Screen from '../../../components/Screen'; @@ -14,7 +15,7 @@ import { themeColor } from '../../../utils/ThemeUtils'; import { LndMobileToolsEventEmitter } from '../../../utils/EventListenerUtils'; interface LNDLogsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/Pathfinding.tsx b/views/Settings/EmbeddedNode/Pathfinding.tsx index ed0813934c..e6b26f1011 100644 --- a/views/Settings/EmbeddedNode/Pathfinding.tsx +++ b/views/Settings/EmbeddedNode/Pathfinding.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { ScrollView, Text, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import Header from '../../../components/Header'; @@ -17,7 +18,7 @@ import { themeColor } from '../../../utils/ThemeUtils'; import { resetMissionControl } from '../../../lndmobile'; interface PathfindingProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/Peers/NeutrinoPeers.tsx b/views/Settings/EmbeddedNode/Peers/NeutrinoPeers.tsx index 83c73725be..399dcd09d1 100644 --- a/views/Settings/EmbeddedNode/Peers/NeutrinoPeers.tsx +++ b/views/Settings/EmbeddedNode/Peers/NeutrinoPeers.tsx @@ -3,6 +3,7 @@ import { FlatList, ScrollView, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import Ping from 'react-native-ping'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../../components/Button'; import Header from '../../../../components/Header'; @@ -28,7 +29,7 @@ import { themeColor } from '../../../../utils/ThemeUtils'; import LoadingIndicator from '../../../../components/LoadingIndicator'; interface NeutrinoPeersProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/Peers/ZeroConfPeers.tsx b/views/Settings/EmbeddedNode/Peers/ZeroConfPeers.tsx index 385a932a2f..7ccafb9c62 100644 --- a/views/Settings/EmbeddedNode/Peers/ZeroConfPeers.tsx +++ b/views/Settings/EmbeddedNode/Peers/ZeroConfPeers.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { FlatList, ScrollView, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import { Row } from '../../../../components/layout/Row'; import Button from '../../../../components/Button'; @@ -15,7 +16,7 @@ import { localeString } from '../../../../utils/LocaleUtils'; import { themeColor } from '../../../../utils/ThemeUtils'; interface ZeroConfPeersProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/Peers/index.tsx b/views/Settings/EmbeddedNode/Peers/index.tsx index 64a951235c..db02801641 100644 --- a/views/Settings/EmbeddedNode/Peers/index.tsx +++ b/views/Settings/EmbeddedNode/Peers/index.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { ScrollView, Text, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Screen from '../../../../components/Screen'; import Header from '../../../../components/Header'; @@ -11,7 +12,7 @@ import SettingsStore from '../../../../stores/SettingsStore'; import { localeString } from '../../../../utils/LocaleUtils'; import { themeColor } from '../../../../utils/ThemeUtils'; interface PeersProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/RestoreChannelBackups.tsx b/views/Settings/EmbeddedNode/RestoreChannelBackups.tsx index 53ee67411f..388d912042 100644 --- a/views/Settings/EmbeddedNode/RestoreChannelBackups.tsx +++ b/views/Settings/EmbeddedNode/RestoreChannelBackups.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, Text, View, ScrollView } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import Header from '../../../components/Header'; @@ -16,7 +17,7 @@ import SettingsStore from '../../../stores/SettingsStore'; import { restoreChannelBackups } from '../../../lndmobile/channel'; interface RestoreChannelBackupsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/EmbeddedNode/index.tsx b/views/Settings/EmbeddedNode/index.tsx index 56743fa03a..6f5612741d 100644 --- a/views/Settings/EmbeddedNode/index.tsx +++ b/views/Settings/EmbeddedNode/index.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { ScrollView, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../../components/Header'; import Screen from '../../../components/Screen'; @@ -12,7 +13,7 @@ import { localeString } from '../../../utils/LocaleUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface EmbeddedNodeProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/Gods.tsx b/views/Settings/Gods.tsx index 20fb48cb19..528ae1ffc4 100644 --- a/views/Settings/Gods.tsx +++ b/views/Settings/Gods.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Dimensions, FlatList, Text } from 'react-native'; import { Avatar, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -15,7 +16,7 @@ import UrlUtils from '../../utils/UrlUtils'; import SettingsStore from '../../stores/SettingsStore'; interface GodsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/Help.tsx b/views/Settings/Help.tsx index 162dc91bdf..04669e0e1b 100644 --- a/views/Settings/Help.tsx +++ b/views/Settings/Help.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { FlatList, Linking, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -10,7 +11,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import UrlUtils from '../../utils/UrlUtils'; interface HelpProps { - navigation: any; + navigation: StackNavigationProp; } function Help(props: HelpProps) { diff --git a/views/Settings/InvoicesSettings.tsx b/views/Settings/InvoicesSettings.tsx index f22f4e4d9d..0d6f121435 100644 --- a/views/Settings/InvoicesSettings.tsx +++ b/views/Settings/InvoicesSettings.tsx @@ -3,6 +3,7 @@ import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import { inject, observer } from 'mobx-react'; import BigNumber from 'bignumber.js'; import _map from 'lodash/map'; +import { StackNavigationProp } from '@react-navigation/stack'; import DropdownSetting from '../../components/DropdownSetting'; import Header from '../../components/Header'; @@ -21,7 +22,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import Gear from '../../assets/images/SVG/Gear.svg'; interface InvoicesSettingsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/LSP.tsx b/views/Settings/LSP.tsx index 7589329e9c..413625acae 100644 --- a/views/Settings/LSP.tsx +++ b/views/Settings/LSP.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { FlatList, StyleSheet, Text, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -20,7 +21,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import UrlUtils from '../../utils/UrlUtils'; interface LSPProps { - navigation: any; + navigation: StackNavigationProp; NodeInfoStore: NodeInfoStore; SettingsStore: SettingsStore; } diff --git a/views/Settings/Language.tsx b/views/Settings/Language.tsx index 6557b80138..113fef271c 100644 --- a/views/Settings/Language.tsx +++ b/views/Settings/Language.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { FlatList, View } from 'react-native'; import { Icon, ListItem, SearchBar } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -12,7 +13,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface LanguageProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/LightningAddress/Attestation.tsx b/views/Settings/LightningAddress/Attestation.tsx index f26e48919e..812964406f 100644 --- a/views/Settings/LightningAddress/Attestation.tsx +++ b/views/Settings/LightningAddress/Attestation.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { ScrollView, Text, View } from 'react-native'; import { nip19 } from 'nostr-tools'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../../../components/Amount'; import Button from '../../../components/Button'; @@ -14,12 +16,13 @@ import { localeString } from '../../../utils/LocaleUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface AttestationProps { - navigation: any; + navigation: StackNavigationProp; + route: Route<'Attestation', { attestation: any }>; } export default function Attestation(props: AttestationProps) { - const { navigation } = props; - const item = navigation.getParam('attestation', null); + const { navigation, route } = props; + const item = route.params?.attestation; const handleNostr = (value: string) => { const deepLink = `nostr:${value}`; diff --git a/views/Settings/LightningAddress/Attestations.tsx b/views/Settings/LightningAddress/Attestations.tsx index 456a1a90fb..4da360ee63 100644 --- a/views/Settings/LightningAddress/Attestations.tsx +++ b/views/Settings/LightningAddress/Attestations.tsx @@ -1,5 +1,7 @@ import * as React from 'react'; import { FlatList, Text, TouchableOpacity, View } from 'react-native'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from '../../../components/Amount'; import Screen from '../../../components/Screen'; @@ -12,12 +14,13 @@ import { localeString } from '../../../utils/LocaleUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface AttestationProps { - navigation: any; + navigation: StackNavigationProp; + route: Route<'Attestations', { attestations: any[] }>; } -export default function Attestation(props: AttestationProps) { - const { navigation } = props; - const attestations = navigation.getParam('attestations', null); +export default function Attestations(props: AttestationProps) { + const { navigation, route } = props; + const attestations = route.params?.attestations; return ( diff --git a/views/Settings/LightningAddress/ChangeAddress.tsx b/views/Settings/LightningAddress/ChangeAddress.tsx index 114fb58799..bcf4f42bae 100644 --- a/views/Settings/LightningAddress/ChangeAddress.tsx +++ b/views/Settings/LightningAddress/ChangeAddress.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import Screen from '../../../components/Screen'; @@ -16,7 +17,7 @@ import { localeString } from '../../../utils/LocaleUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface ChangeAddressProps { - navigation: any; + navigation: StackNavigationProp; LightningAddressStore: LightningAddressStore; } diff --git a/views/Settings/LightningAddress/LightningAddressInfo.tsx b/views/Settings/LightningAddress/LightningAddressInfo.tsx index d0c9b09cbf..1b34606b2b 100644 --- a/views/Settings/LightningAddress/LightningAddressInfo.tsx +++ b/views/Settings/LightningAddress/LightningAddressInfo.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { ScrollView, StyleSheet, Text, View } from 'react-native'; import { Divider, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import { Row } from '../../../components/layout/Row'; @@ -22,7 +23,7 @@ import NostrichNotFound from '../../../assets/images/SVG/Nostrich_not-found.svg' import Receive from '../../../assets/images/SVG/Receive.svg'; interface LightningAddressInfoProps { - navigation: any; + navigation: StackNavigationProp; LightningAddressStore: LightningAddressStore; } diff --git a/views/Settings/LightningAddress/LightningAddressSettings.tsx b/views/Settings/LightningAddress/LightningAddressSettings.tsx index 9002b63c8d..514a44aca8 100644 --- a/views/Settings/LightningAddress/LightningAddressSettings.tsx +++ b/views/Settings/LightningAddress/LightningAddressSettings.tsx @@ -11,6 +11,7 @@ import Switch from '../../../components/Switch'; import Header from '../../../components/Header'; import { ErrorMessage } from '../../../components/SuccessErrorMessage'; import LoadingIndicator from '../../../components/LoadingIndicator'; +import { StackNavigationProp } from '@react-navigation/stack'; import SettingsStore, { NOTIFICATIONS_PREF_KEYS, @@ -22,7 +23,7 @@ import { localeString } from '../../../utils/LocaleUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface LightningAddressSettingsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; LightningAddressStore: LightningAddressStore; } diff --git a/views/Settings/LightningAddress/NostrKeys.tsx b/views/Settings/LightningAddress/NostrKeys.tsx index bfffc4d049..2d6b71c5c8 100644 --- a/views/Settings/LightningAddress/NostrKeys.tsx +++ b/views/Settings/LightningAddress/NostrKeys.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { StyleSheet, TouchableOpacity, View } from 'react-native'; import { inject, observer } from 'mobx-react'; import { generatePrivateKey, getPublicKey, nip19 } from 'nostr-tools'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../../components/Button'; import KeyValue from '../../../components/KeyValue'; @@ -28,9 +30,10 @@ import VisibleSVG from '../../../assets/images/SVG/eye_opened.svg'; import Edit from '../../../assets/images/SVG/Pen.svg'; interface NostrKeyProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; LightningAddressStore: LightningAddressStore; + route: Route<'NostrKey', { setup: boolean; nostrPrivateKey: string }>; } interface NostrKeyState { @@ -76,14 +79,13 @@ export default class NostrKey extends React.Component< }; async UNSAFE_componentWillMount() { - const { SettingsStore, navigation } = this.props; + const { SettingsStore, route } = this.props; const { settings } = SettingsStore; - const setup = navigation.getParam('setup', false); - const nostrPrivateKey = navigation.getParam( - 'nostrPrivateKey', - settings?.lightningAddress?.nostrPrivateKey || '' - ); + const setup = route.params?.setup; + const nostrPrivateKey = + route.params?.nostrPrivateKey ?? + (settings?.lightningAddress?.nostrPrivateKey || ''); let nostrPublicKey, nostrNsec, nostrNpub; if (nostrPrivateKey) { diff --git a/views/Settings/LightningAddress/NostrRelays.tsx b/views/Settings/LightningAddress/NostrRelays.tsx index 553ca36436..762af6561b 100644 --- a/views/Settings/LightningAddress/NostrRelays.tsx +++ b/views/Settings/LightningAddress/NostrRelays.tsx @@ -5,6 +5,8 @@ import { inject, observer } from 'mobx-react'; import { schnorr } from '@noble/curves/secp256k1'; import { bytesToHex } from '@noble/hashes/utils'; import hashjs from 'hash.js'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import { Row } from '../../../components/layout/Row'; import { ErrorMessage } from '../../../components/SuccessErrorMessage'; @@ -23,9 +25,10 @@ import { localeString } from '../../../utils/LocaleUtils'; import { themeColor } from '../../../utils/ThemeUtils'; interface NostrRelaysProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; LightningAddressStore: LightningAddressStore; + route: Route<'NostrRelays', { setup: boolean; relays: string[] }>; } interface NostrRelaysState { @@ -53,11 +56,10 @@ export default class NostrRelays extends React.Component< }; async UNSAFE_componentWillMount() { - const { SettingsStore, navigation } = this.props; + const { SettingsStore, route } = this.props; const { settings, getSettings } = SettingsStore; - const setup = navigation.getParam('setup', false); - const relays = navigation.getParam('relays', null); + const { setup, relays } = route.params ?? {}; await getSettings(); diff --git a/views/Settings/LightningAddress/index.tsx b/views/Settings/LightningAddress/index.tsx index 37294c7b6b..ff79b72496 100644 --- a/views/Settings/LightningAddress/index.tsx +++ b/views/Settings/LightningAddress/index.tsx @@ -10,6 +10,8 @@ import { import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import { generatePrivateKey, getPublicKey, nip19 } from 'nostr-tools'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import LightningAddressPayment from './LightningAddressPayment'; @@ -41,11 +43,15 @@ import QR from '../../../assets/images/SVG/QR.svg'; import Gear from '../../../assets/images/SVG/Gear.svg'; interface LightningAddressProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; LightningAddressStore: LightningAddressStore; SettingsStore: SettingsStore; UnitsStore: UnitsStore; + route: Route< + 'LightningAddress', + { skipStatus: boolean; relays: string[]; nostrPrivateKey: string } + >; } interface LightningAddressState { @@ -85,10 +91,10 @@ export default class LightningAddress extends React.Component< }; async componentDidMount() { - const { LightningAddressStore, navigation } = this.props; + const { LightningAddressStore, navigation, route } = this.props; const { status } = LightningAddressStore; - const skipStatus: boolean = navigation.getParam('skipStatus', false); + const skipStatus = route.params?.skipStatus; this.generateNostrKeys(); @@ -99,7 +105,7 @@ export default class LightningAddress extends React.Component< if (!skipStatus) status(); // triggers when loaded from navigation or back action - navigation.addListener('didFocus', this.handleFocus); + navigation.addListener('focus', this.handleFocus); } handleFocus = () => { @@ -110,16 +116,14 @@ export default class LightningAddress extends React.Component< } }; - UNSAFE_componentWillReceiveProps = (newProps: any) => { - const { navigation } = newProps; - const nostrRelays = navigation.getParam('relays', null); + UNSAFE_componentWillReceiveProps = (newProps: LightningAddressProps) => { + const { route } = newProps; + const nostrRelays = route.params?.relays; if (nostrRelays) { - this.setState({ - nostrRelays - }); + this.setState({ nostrRelays }); } - const nostrPrivateKey = navigation.getParam('nostrPrivateKey', ''); + const nostrPrivateKey = route.params?.nostrPrivateKey ?? ''; if (nostrPrivateKey) { const nostrPublicKey = getPublicKey(nostrPrivateKey); const nostrNpub = nip19.npubEncode(nostrPublicKey); @@ -215,7 +219,9 @@ export default class LightningAddress extends React.Component< label: address, hideText: true, jumboLabel: true, - logo: require('../../../assets/images/pay-z-black.png') + logo: themeColor('invertQrIcons') + ? require('../../../assets/images/pay-z-white.png') + : require('../../../assets/images/pay-z-black.png') }) } style={{ marginTop: 10 }} diff --git a/views/Settings/Mortals.tsx b/views/Settings/Mortals.tsx index b361994e73..56ad535f6a 100644 --- a/views/Settings/Mortals.tsx +++ b/views/Settings/Mortals.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Dimensions, FlatList, Text } from 'react-native'; import { Avatar, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -15,7 +16,7 @@ import UrlUtils from '../../utils/UrlUtils'; import SettingsStore from '../../stores/SettingsStore'; interface MortalsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/NodeConfiguration.tsx b/views/Settings/NodeConfiguration.tsx index aabc9da923..517adfc728 100644 --- a/views/Settings/NodeConfiguration.tsx +++ b/views/Settings/NodeConfiguration.tsx @@ -12,6 +12,8 @@ import Clipboard from '@react-native-clipboard/clipboard'; import { inject, observer } from 'mobx-react'; import EncryptedStorage from 'react-native-encrypted-storage'; import cloneDeep from 'lodash/cloneDeep'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import { hash, STORAGE_KEY } from '../../backends/LNC/credentialStore'; @@ -50,8 +52,20 @@ import { getPhoto } from '../../utils/PhotoUtils'; import { createLndWallet } from '../../utils/LndMobileUtils'; interface NodeConfigurationProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; + route: Route< + 'NodeConfiguration', + { + node: any; + index: any; + active: any; + tor: any; + saved: any; + newEntry: any; + newPhoto: any; + } + >; } interface NodeConfigurationState { @@ -270,15 +284,10 @@ export default class NodeConfiguration extends React.Component< } async initFromProps(props: any) { - const { navigation } = props; + const { route } = props; - const node = navigation.getParam('node', null); - const index = navigation.getParam('index', null); - const active = navigation.getParam('active', null); - const tor = navigation.getParam('enableTor', false); - const saved = navigation.getParam('saved', null); - const newEntry = navigation.getParam('newEntry', null); - const newPhoto = navigation.getParam('photo', null); + const { node, index, active, tor, saved, newEntry, newPhoto } = + route.params ?? {}; if (node) { const { @@ -584,8 +593,8 @@ export default class NodeConfiguration extends React.Component< }; render() { - const { navigation, SettingsStore } = this.props; - const node = navigation.getParam('node', null); + const { route, navigation, SettingsStore } = this.props; + const node = route.params?.node; const { nickname, host, @@ -1737,13 +1746,7 @@ export default class NodeConfiguration extends React.Component< this.deleteNodeConfig(); } }} - containerStyle={{ - borderColor: themeColor('delete') - }} - titleStyle={{ - color: themeColor('delete') - }} - secondary + warning /> )} diff --git a/views/Settings/Nodes.tsx b/views/Settings/Nodes.tsx index 00956d1a79..c133337d9d 100644 --- a/views/Settings/Nodes.tsx +++ b/views/Settings/Nodes.tsx @@ -3,6 +3,7 @@ import { View, Text, TouchableOpacity, Image, StyleSheet } from 'react-native'; import DragList, { DragListRenderItemInfo } from 'react-native-draglist'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -22,10 +23,11 @@ import BackendUtils from '../../utils/BackendUtils'; import Add from '../../assets/images/SVG/Add.svg'; import DragDots from '../../assets/images/SVG/DragDots.svg'; import LoadingIndicator from '../../components/LoadingIndicator'; +import { cloneDeep } from 'lodash'; interface NodesProps { nodes: any[]; - navigation: any; + navigation: StackNavigationProp; edit?: boolean; loading?: boolean; selectedNode?: number; @@ -55,12 +57,12 @@ export default class Nodes extends React.Component { componentDidMount() { this.refreshSettings(); - this.props.navigation.addListener('didFocus', this.handleFocus); + this.props.navigation.addListener('focus', this.handleFocus); } componentWillUnmount() { this.props.navigation.removeListener && - this.props.navigation.removeListener('didFocus'); + this.props.navigation.removeListener('focus', this.handleFocus); } handleFocus = () => { @@ -310,7 +312,9 @@ export default class Nodes extends React.Component { navigation.navigate( 'NodeConfiguration', { - node: item, + node: cloneDeep( + item + ), index, active: selectedNode === diff --git a/views/Settings/Olympians.tsx b/views/Settings/Olympians.tsx index ba09153a80..513e5fdc01 100644 --- a/views/Settings/Olympians.tsx +++ b/views/Settings/Olympians.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Dimensions, FlatList, Text } from 'react-native'; import { Avatar, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -15,7 +16,7 @@ import UrlUtils from '../../utils/UrlUtils'; import SettingsStore from '../../stores/SettingsStore'; interface OlympiansProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/PaymentsSettings.tsx b/views/Settings/PaymentsSettings.tsx index 3e5c7f1fc7..866cc469f5 100644 --- a/views/Settings/PaymentsSettings.tsx +++ b/views/Settings/PaymentsSettings.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Text, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import DropdownSetting from '../../components/DropdownSetting'; import Header from '../../components/Header'; @@ -17,7 +18,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import TextInput from '../../components/TextInput'; interface PaymentsSettingsProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/PointOfSale.tsx b/views/Settings/PointOfSale.tsx index fc40b1fef6..70d8cf13cc 100644 --- a/views/Settings/PointOfSale.tsx +++ b/views/Settings/PointOfSale.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { Platform, ScrollView, Text, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import BackendUtils from '../../utils/BackendUtils'; import { localeString } from '../../utils/LocaleUtils'; @@ -24,7 +25,7 @@ import SettingsStore, { } from '../../stores/SettingsStore'; interface PointOfSaleProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/PointOfSaleRecon.tsx b/views/Settings/PointOfSaleRecon.tsx index 6810e17d57..97dbc68267 100644 --- a/views/Settings/PointOfSaleRecon.tsx +++ b/views/Settings/PointOfSaleRecon.tsx @@ -9,6 +9,7 @@ import { import { ButtonGroup } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import BigNumber from 'bignumber.js'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -31,7 +32,7 @@ import { ReconHeader } from './PointOfSaleReconHeader'; import OrderItem from '../../views/Wallet/OrderItem'; interface PointOfSaleReconProps { - navigation: any; + navigation: StackNavigationProp; FiatStore: FiatStore; PosStore: PosStore; } @@ -123,7 +124,11 @@ export default class PointOfSaleRecon extends React.PureComponent< })` : localeString('views.Settings.POS.recon'); - const ExportBadge = ({ navigation }: { navigation: any }) => ( + const ExportBadge = ({ + navigation + }: { + navigation: StackNavigationProp; + }) => ( navigation.navigate('PointOfSaleReconExport')} > diff --git a/views/Settings/PointOfSaleReconExport.tsx b/views/Settings/PointOfSaleReconExport.tsx index df16c5487c..ea512349e1 100644 --- a/views/Settings/PointOfSaleReconExport.tsx +++ b/views/Settings/PointOfSaleReconExport.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { View, ScrollView, Text, TouchableOpacity } from 'react-native'; import { inject, observer } from 'mobx-react'; import Clipboard from '@react-native-clipboard/clipboard'; +import { StackNavigationProp } from '@react-navigation/stack'; import ClipboardSVG from '../../assets/images/SVG/Clipboard.svg'; @@ -13,7 +14,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface PointOfSaleReconExportProps { - navigation: any; + navigation: StackNavigationProp; PosStore: PosStore; } diff --git a/views/Settings/Privacy.tsx b/views/Settings/Privacy.tsx index d49fdb3c51..067dedc74c 100644 --- a/views/Settings/Privacy.tsx +++ b/views/Settings/Privacy.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { ScrollView, View } from 'react-native'; import { ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; + import SettingsStore, { BLOCK_EXPLORER_KEYS } from '../../stores/SettingsStore'; import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; @@ -14,7 +16,7 @@ import Text from '../../components/Text'; import TextInput from '../../components/TextInput'; interface PrivacyProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/Security.tsx b/views/Settings/Security.tsx index c92f522cbd..6d2a63baad 100644 --- a/views/Settings/Security.tsx +++ b/views/Settings/Security.tsx @@ -3,6 +3,7 @@ import * as React from 'react'; import { FlatList, ScrollView, View } from 'react-native'; import { BiometryType } from 'react-native-biometrics'; import { Icon, ListItem } from 'react-native-elements'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -15,7 +16,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface SecurityProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/Seed.tsx b/views/Settings/Seed.tsx index 8368dc6264..4880dd9709 100644 --- a/views/Settings/Seed.tsx +++ b/views/Settings/Seed.tsx @@ -9,6 +9,7 @@ import { } from 'react-native'; import { inject, observer } from 'mobx-react'; import EncryptedStorage from 'react-native-encrypted-storage'; +import { StackNavigationProp } from '@react-navigation/stack'; import { ErrorMessage } from '../../components/SuccessErrorMessage'; @@ -25,7 +26,7 @@ import { localeString } from '../../utils/LocaleUtils'; import Skull from '../../assets/images/SVG/Skull.svg'; interface SeedProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/SeedRecovery.tsx b/views/Settings/SeedRecovery.tsx index 19ed993498..13570c500d 100644 --- a/views/Settings/SeedRecovery.tsx +++ b/views/Settings/SeedRecovery.tsx @@ -8,6 +8,8 @@ import { } from 'react-native'; import Clipboard from '@react-native-clipboard/clipboard'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import { ErrorMessage } from '../../components/SuccessErrorMessage'; @@ -27,8 +29,9 @@ import SettingsStore from '../../stores/SettingsStore'; import LoadingIndicator from '../../components/LoadingIndicator'; interface SeedRecoveryProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; + route: Route<'SeedRecovery', { network: string }>; } interface SeedRecoveryState { @@ -134,14 +137,9 @@ export default class SeedRecovery extends React.PureComponent< this.initFromProps(nextProps); } - async initFromProps(props: any) { - const { navigation } = props; - - const network = navigation.getParam('network', 'mainnet'); - - this.setState({ - network - }); + async initFromProps(props: SeedRecoveryProps) { + const network = props.route.params?.network ?? 'mainnet'; + this.setState({ network }); } async UNSAFE_componentWillMount() { diff --git a/views/Settings/SelectCurrency.tsx b/views/Settings/SelectCurrency.tsx index f1a0d6f2b6..d0227c589a 100644 --- a/views/Settings/SelectCurrency.tsx +++ b/views/Settings/SelectCurrency.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { FlatList, View } from 'react-native'; import { Icon, ListItem, SearchBar } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Screen from '../../components/Screen'; import Header from '../../components/Header'; @@ -16,8 +18,9 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface SelectCurrencyProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; + route: Route<'SelectCurrency', { currencyConverter: boolean }>; } interface SelectCurrencyState { @@ -71,7 +74,7 @@ export default class SelectCurrency extends React.Component< }; render() { - const { navigation, SettingsStore } = this.props; + const { navigation, SettingsStore, route } = this.props; const { selectedCurrency, search, fiatRatesSource } = this.state; const currencies = this.state.currencies .sort((a, b) => @@ -83,10 +86,7 @@ export default class SelectCurrency extends React.Component< const { updateSettings, getSettings }: any = SettingsStore; - const currencyConverter = navigation.getParam( - 'currencyConverter', - null - ); + const currencyConverter = route.params?.currencyConverter; return ( diff --git a/views/Settings/SetDuressPassword.tsx b/views/Settings/SetDuressPassword.tsx index d1c14f1189..9d143e12cf 100644 --- a/views/Settings/SetDuressPassword.tsx +++ b/views/Settings/SetDuressPassword.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Platform, StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -13,7 +14,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import SettingsStore from '../../stores/SettingsStore'; interface SetDuressPassphraseProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/SetDuressPin.tsx b/views/Settings/SetDuressPin.tsx index c49ad41b9d..e21a2486e0 100644 --- a/views/Settings/SetDuressPin.tsx +++ b/views/Settings/SetDuressPin.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Pin from '../../components/Pin'; @@ -12,7 +13,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import SettingsStore from '../../stores/SettingsStore'; interface SetDuressPinProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } diff --git a/views/Settings/SetNodePicture.tsx b/views/Settings/SetNodePicture.tsx index a99982a44d..cf5bb56f1c 100644 --- a/views/Settings/SetNodePicture.tsx +++ b/views/Settings/SetNodePicture.tsx @@ -11,6 +11,8 @@ import { import { Avatar } from 'react-native-elements'; import { launchImageLibrary } from 'react-native-image-picker'; import RNFS from 'react-native-fs'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import AddIcon from '../../assets/images/SVG/Add.svg'; @@ -24,7 +26,8 @@ import Button from '../../components/Button'; import { localeString } from '../../utils/LocaleUtils'; interface SetNodePictureProps { - navigation: any; + navigation: StackNavigationProp; + route: Route<'SetNodePicture', { implementation: string }>; } interface SetNodePictureState { @@ -38,10 +41,7 @@ export default class SetNodePicture extends React.Component< > { constructor(props: SetNodePictureProps) { super(props); - const implementation = this.props.navigation.getParam( - 'implementation', - null - ); + const implementation = this.props.route.params?.implementation; let images: string[] = [ require('../../assets/images/zeus-illustration-1a.jpg'), require('../../assets/images/zeus-illustration-1b.jpg'), diff --git a/views/Settings/SetPassword.tsx b/views/Settings/SetPassword.tsx index 70321b55b4..bae3a88592 100644 --- a/views/Settings/SetPassword.tsx +++ b/views/Settings/SetPassword.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, Text, View, Platform } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Header from '../../components/Header'; @@ -13,7 +14,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import SettingsStore from '../../stores/SettingsStore'; interface SetPassphraseProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } @@ -93,7 +94,7 @@ export default class SetPassphrase extends React.Component< } await updateSettings({ passphrase }).then(() => { - setLoginStatus(false); + setLoginStatus(true); getSettings(); navigation.navigate('Settings', { refresh: true @@ -254,10 +255,7 @@ export default class SetPassphrase extends React.Component< this.deletePassword(); } }} - titleStyle={{ - color: themeColor('delete') - }} - secondary + warning /> )} diff --git a/views/Settings/SetPin.tsx b/views/Settings/SetPin.tsx index 6b5da52e63..304431618b 100644 --- a/views/Settings/SetPin.tsx +++ b/views/Settings/SetPin.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Pin from '../../components/Pin'; @@ -13,7 +14,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface SetPinProps { - navigation: any; + navigation: StackNavigationProp; SettingsStore: SettingsStore; } @@ -92,7 +93,7 @@ export default class SetPin extends React.Component { } await updateSettings({ pin }).then(() => { - setLoginStatus(false); + setLoginStatus(true); getSettings(); navigation.navigate('Settings', { refresh: true diff --git a/views/Settings/Settings.tsx b/views/Settings/Settings.tsx index 0589f1d494..8eb40a4bd3 100644 --- a/views/Settings/Settings.tsx +++ b/views/Settings/Settings.tsx @@ -10,6 +10,7 @@ import { } from 'react-native'; import { Icon } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import AccountIcon from '../../assets/images/SVG/Account.svg'; import AddIcon from '../../assets/images/SVG/Add.svg'; @@ -54,7 +55,7 @@ import UnitsStore from '../../stores/UnitsStore'; import { version } from '../../package.json'; interface SettingsProps { - navigation: any; + navigation: StackNavigationProp; NodeInfoStore: NodeInfoStore; LightningAddressStore: LightningAddressStore; SettingsStore: SettingsStore; @@ -83,16 +84,16 @@ export default class Settings extends React.Component< SettingsStore.getSettings(); // triggers when loaded from navigation or back action - navigation.addListener('didFocus', () => { - SettingsStore.getSettings(); - }); + navigation.addListener('focus', this.handleFocus); } componentWillUnmount() { this.props.navigation.removeListener && - this.props.navigation.removeListener('didFocus'); + this.props.navigation.removeListener('focus', this.handleFocus); } + handleFocus = () => this.props.SettingsStore.getSettings(); + render() { const { navigation, diff --git a/views/Settings/SignVerifyMessage.tsx b/views/Settings/SignVerifyMessage.tsx index 022a3496a2..56ec9890c5 100644 --- a/views/Settings/SignVerifyMessage.tsx +++ b/views/Settings/SignVerifyMessage.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { StyleSheet, Text, View, ScrollView } from 'react-native'; import { ButtonGroup } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import CopyButton from '../../components/CopyButton'; @@ -20,7 +21,7 @@ import { localeString } from '../../utils/LocaleUtils'; import MessageSignStore from '../../stores/MessageSignStore'; interface SignVerifyMessageProps { - navigation: any; + navigation: StackNavigationProp; MessageSignStore: MessageSignStore; } diff --git a/views/Settings/SocialMedia.tsx b/views/Settings/SocialMedia.tsx index b885d27e9b..9f2c2748e1 100644 --- a/views/Settings/SocialMedia.tsx +++ b/views/Settings/SocialMedia.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { FlatList, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -10,7 +11,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import UrlUtils from '../../utils/UrlUtils'; interface HelpProps { - navigation: any; + navigation: StackNavigationProp; } function Help(props: HelpProps) { diff --git a/views/Settings/Sponsors.tsx b/views/Settings/Sponsors.tsx index a39246d395..1aa8c3044f 100644 --- a/views/Settings/Sponsors.tsx +++ b/views/Settings/Sponsors.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { FlatList, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -9,7 +10,7 @@ import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; interface SponsorsProps { - navigation: any; + navigation: StackNavigationProp; } function Sponsors(props: SponsorsProps) { diff --git a/views/Settings/Support.tsx b/views/Settings/Support.tsx index 5bfa6bb1be..b6cd22f9eb 100644 --- a/views/Settings/Support.tsx +++ b/views/Settings/Support.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { FlatList, View } from 'react-native'; import { Icon, ListItem } from 'react-native-elements'; +import { StackNavigationProp } from '@react-navigation/stack'; import Header from '../../components/Header'; import Screen from '../../components/Screen'; @@ -10,7 +11,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import UrlUtils from '../../utils/UrlUtils'; interface SupportProps { - navigation: any; + navigation: StackNavigationProp; } function Support(props: SupportProps) { diff --git a/views/SparkQRScanner.tsx b/views/SparkQRScanner.tsx index 113614e1a5..73089ac1ee 100644 --- a/views/SparkQRScanner.tsx +++ b/views/SparkQRScanner.tsx @@ -1,17 +1,22 @@ import * as React from 'react'; import { Alert } from 'react-native'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; + import QRCodeScanner from './../components/QRCodeScanner'; + import { localeString } from './../utils/LocaleUtils'; interface SparkQRProps { - navigation: any; + navigation: StackNavigationProp; + route: Route<'SparkQRScanner', { index: any }>; } export default class SparkQRScanner extends React.Component { handleSparkInvoiceScanned = (data: string) => { - const { navigation } = this.props; + const { navigation, route } = this.props; - const index = navigation.getParam('index', null); + const index = route.params?.index; const [url, accessKey] = data.split('?access-key='); @@ -34,9 +39,9 @@ export default class SparkQRScanner extends React.Component { }; render() { - const { navigation } = this.props; + const { navigation, route } = this.props; - const index = navigation.getParam('index', null); + const index = route.params?.index; return ( ; BalanceStore: BalanceStore; InvoicesStore: InvoicesStore; ModalStore: ModalStore; NodeInfoStore: NodeInfoStore; TransactionsStore: TransactionsStore; SettingsStore: SettingsStore; + route: Route<'Sweep', { destination: string }>; } interface SweepState { @@ -65,8 +67,8 @@ export default class Sweep extends React.Component { listener: any; constructor(props: SweepProps) { super(props); - const { navigation } = props; - const destination = navigation.getParam('destination', null); + const { route } = props; + const destination = route.params?.destination; this.state = { destination: destination || '', @@ -80,20 +82,8 @@ export default class Sweep extends React.Component { if (this.listener && this.listener.stop) this.listener.stop(); } - UNSAFE_componentWillReceiveProps(nextProps: any) { - const { navigation } = nextProps; - const destination = navigation.getParam('destination', null); - const amount = navigation.getParam('amount', null); - - this.setState({ - destination - }); - - if (amount) { - this.setState({ - amount - }); - } + UNSAFE_componentWillReceiveProps(nextProps: SweepProps) { + this.setState({ destination: nextProps.route.params?.destination }); } subscribePayment = (streamingCall: string) => { @@ -288,6 +278,7 @@ export default class Sweep extends React.Component { onChangeFee={(text: string) => this.setState({ fee: text }) } + navigation={navigation} /> ; SyncStore: SyncStore; } diff --git a/views/Transaction.tsx b/views/Transaction.tsx index 72391995c0..2ba2370f9d 100644 --- a/views/Transaction.tsx +++ b/views/Transaction.tsx @@ -10,6 +10,8 @@ import { View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import { Row } from '../components/layout/Row'; import Amount from '../components/Amount'; @@ -33,9 +35,10 @@ import CaretRight from '../assets/images/SVG/Caret Right.svg'; import EditNotes from '../assets/images/SVG/Pen.svg'; interface TransactionProps { - navigation: any; + navigation: StackNavigationProp; NodeInfoStore: NodeInfoStore; TransactionsStore: TransactionsStore; + route: Route<'Transaction', { transaction: Transaction }>; } interface TransactionState { @@ -52,12 +55,9 @@ export default class TransactionView extends React.Component< storedNotes: '' }; async componentDidMount() { - const { navigation } = this.props; - const transaction: Transaction = navigation.getParam( - 'transaction', - null - ); - navigation.addListener('didFocus', () => { + const { navigation, route } = this.props; + const transaction = route.params?.transaction; + navigation.addListener('focus', () => { this.props.TransactionsStore.resetBroadcast(); EncryptedStorage.getItem('note-' + transaction.tx) .then((storedNotes) => { @@ -69,11 +69,8 @@ export default class TransactionView extends React.Component< }); } render() { - const { NodeInfoStore, navigation } = this.props; - const transaction: Transaction = navigation.getParam( - 'transaction', - null - ); + const { NodeInfoStore, navigation, route } = this.props; + const transaction = route.params?.transaction; const { storedNotes } = this.state; const { testnet } = NodeInfoStore; diff --git a/views/TxHex.tsx b/views/TxHex.tsx index 231de972cd..ae42c6b530 100644 --- a/views/TxHex.tsx +++ b/views/TxHex.tsx @@ -10,6 +10,8 @@ import { inject, observer } from 'mobx-react'; import { ButtonGroup } from 'react-native-elements'; import { UR, UREncoder } from '@ngraveio/bc-ur'; import clone from 'lodash/clone'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; const bitcoin = require('bitcoinjs-lib'); @@ -34,10 +36,11 @@ import NodeInfoStore from '../stores/NodeInfoStore'; import TransactionsStore from '../stores/TransactionsStore'; interface TxHexProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; NodeInfoStore: NodeInfoStore; TransactionsStore: TransactionsStore; + route: Route<'TxHex', { txHex: string }>; } interface TxHexState { @@ -66,16 +69,9 @@ export default class TxHex extends React.Component { }; UNSAFE_componentWillMount(): void { - const { navigation } = this.props; - const txHex: string = navigation.getParam('txHex'); - this.setState( - { - txHex - }, - () => { - this.generateInfo(); - } - ); + const { route } = this.props; + const txHex = route.params?.txHex; + this.setState({ txHex }, () => this.generateInfo()); } generateInfo = () => { diff --git a/views/UTXOs/CoinControl.tsx b/views/UTXOs/CoinControl.tsx index 68845e2faf..fd2b15b0a6 100644 --- a/views/UTXOs/CoinControl.tsx +++ b/views/UTXOs/CoinControl.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { FlatList, View } from 'react-native'; import { Button, ListItem } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import AccountFilter from './../../components/AccountFilter'; import Amount from './../../components/Amount'; @@ -16,8 +18,9 @@ import { themeColor } from './../../utils/ThemeUtils'; import UTXOsStore from './../../stores/UTXOsStore'; interface CoinControlProps { - navigation: any; + navigation: StackNavigationProp; UTXOsStore: UTXOsStore; + route: Route<'CoinControl', { account: string }>; } interface CoinControlState { @@ -30,10 +33,10 @@ export default class CoinControl extends React.Component< CoinControlProps, CoinControlState > { - constructor(props: any) { + constructor(props: CoinControlProps) { super(props); - const accountParam = props.navigation.getParam('account'); + const accountParam = props.route.account; const account = accountParam && accountParam === 'On-chain' ? 'default' diff --git a/views/UTXOs/UTXO.tsx b/views/UTXOs/UTXO.tsx index 7c181c426f..4b24f249df 100644 --- a/views/UTXOs/UTXO.tsx +++ b/views/UTXOs/UTXO.tsx @@ -7,6 +7,8 @@ import { View } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { Route } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; import Amount from './../../components/Amount'; import Header from '../../components/Header'; @@ -22,16 +24,17 @@ import UrlUtils from './../../utils/UrlUtils'; import NodeInfoStore from './../../stores/NodeInfoStore'; interface UTXOProps { - navigation: any; + navigation: StackNavigationProp; NodeInfoStore: NodeInfoStore; + route: Route<'UTXO', { utxo: Utxo }>; } @inject('NodeInfoStore') @observer export default class UTXO extends React.Component { render() { - const { NodeInfoStore, navigation } = this.props; - const utxo: Utxo = navigation.getParam('utxo', null); + const { NodeInfoStore, navigation, route } = this.props; + const utxo = route.params?.utxo; const { testnet } = NodeInfoStore; const { getOutpoint, address, getConfs, isUnconfirmed, blockheight } = diff --git a/views/Wallet/BalancePane.tsx b/views/Wallet/BalancePane.tsx index 422f5df2bb..342f2642b1 100644 --- a/views/Wallet/BalancePane.tsx +++ b/views/Wallet/BalancePane.tsx @@ -4,6 +4,7 @@ import { inject, observer } from 'mobx-react'; import { LinearProgress } from 'react-native-elements'; import EncryptedStorage from 'react-native-encrypted-storage'; import BigNumber from 'bignumber.js'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import WalletHeader from '../../components/WalletHeader'; @@ -22,7 +23,7 @@ import { version, playStore } from '../../package.json'; import LockIcon from '../../assets/images/SVG/Lock.svg'; interface BalancePaneProps { - navigation: any; + navigation: StackNavigationProp; BalanceStore: BalanceStore; NodeInfoStore: NodeInfoStore; SettingsStore: SettingsStore; diff --git a/views/Wallet/KeypadPane.tsx b/views/Wallet/KeypadPane.tsx index 235181b63e..04bd63498d 100644 --- a/views/Wallet/KeypadPane.tsx +++ b/views/Wallet/KeypadPane.tsx @@ -1,6 +1,8 @@ import * as React from 'react'; import { Animated, View, Text, TouchableOpacity } from 'react-native'; import { inject, observer } from 'mobx-react'; +import BigNumber from 'bignumber.js'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Conversion from '../../components/Conversion'; @@ -19,10 +21,9 @@ import BackendUtils from '../../utils/BackendUtils'; import { localeString } from '../../utils/LocaleUtils'; import { themeColor } from '../../utils/ThemeUtils'; import { getDecimalPlaceholder } from '../../utils/UnitsUtils'; -import BigNumber from 'bignumber.js'; interface KeypadPaneProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore: ChannelsStore; FiatStore: FiatStore; NodeInfoStore: NodeInfoStore; @@ -65,7 +66,7 @@ export default class KeypadPane extends React.PureComponent< async UNSAFE_componentWillMount() { this.handleLsp(); - this.props.navigation.addListener('didFocus', async () => { + this.props.navigation.addListener('focus', async () => { this.handleLsp(); }); } diff --git a/views/Wallet/SquarePosPane.tsx b/views/Wallet/SquarePosPane.tsx index d174a8175b..a8413d4eee 100644 --- a/views/Wallet/SquarePosPane.tsx +++ b/views/Wallet/SquarePosPane.tsx @@ -11,6 +11,7 @@ import BigNumber from 'bignumber.js'; import { ButtonGroup, SearchBar } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import Swipeable from 'react-native-gesture-handler/Swipeable'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import LoadingIndicator from '../../components/LoadingIndicator'; @@ -34,7 +35,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import { version } from './../../package.json'; interface SquarePosPaneProps { - navigation: any; + navigation: StackNavigationProp; ActivityStore?: ActivityStore; FiatStore?: FiatStore; NodeInfoStore?: NodeInfoStore; diff --git a/views/Wallet/StandalonePosKeypadPane.tsx b/views/Wallet/StandalonePosKeypadPane.tsx index 80bf94f1e0..763472ee54 100644 --- a/views/Wallet/StandalonePosKeypadPane.tsx +++ b/views/Wallet/StandalonePosKeypadPane.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { Animated, View, Text } from 'react-native'; import { inject, observer } from 'mobx-react'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import Conversion from '../../components/Conversion'; @@ -21,7 +22,7 @@ import { getDecimalPlaceholder } from '../../utils/UnitsUtils'; import { PricedIn } from '../../models/Product'; interface PosKeypadPaneProps { - navigation: any; + navigation: StackNavigationProp; ChannelsStore?: ChannelsStore; FiatStore?: FiatStore; UnitsStore?: UnitsStore; diff --git a/views/Wallet/StandalonePosPane.tsx b/views/Wallet/StandalonePosPane.tsx index dce46960b0..db310ff6dc 100644 --- a/views/Wallet/StandalonePosPane.tsx +++ b/views/Wallet/StandalonePosPane.tsx @@ -13,6 +13,7 @@ import { ButtonGroup, SearchBar } from 'react-native-elements'; import { inject, observer } from 'mobx-react'; import Swipeable from 'react-native-gesture-handler/Swipeable'; import moment from 'moment'; +import { StackNavigationProp } from '@react-navigation/stack'; import Button from '../../components/Button'; import LoadingIndicator from '../../components/LoadingIndicator'; @@ -38,7 +39,7 @@ import { themeColor } from '../../utils/ThemeUtils'; import { version } from './../../package.json'; interface StandalonePosPaneProps { - navigation: any; + navigation: StackNavigationProp; ActivityStore: ActivityStore; FiatStore: FiatStore; NodeInfoStore: NodeInfoStore; diff --git a/views/Wallet/Wallet.tsx b/views/Wallet/Wallet.tsx index 73d415be2e..c9d715cf6b 100644 --- a/views/Wallet/Wallet.tsx +++ b/views/Wallet/Wallet.tsx @@ -17,7 +17,8 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { DefaultTheme, NavigationContainer, - NavigationContainerRef + NavigationContainerRef, + NavigationIndependentTree } from '@react-navigation/native'; import { inject, observer } from 'mobx-react'; import RNRestart from 'react-native-restart'; @@ -70,11 +71,14 @@ import CaretUp from '../../assets/images/SVG/Caret Up.svg'; import ChannelsIcon from '../../assets/images/SVG/Channels.svg'; import POS from '../../assets/images/SVG/POS.svg'; import Temple from '../../assets/images/SVG/Temple.svg'; +import Scan from '../../assets/images/SVG/Scan.svg'; + +import { StackNavigationProp } from '@react-navigation/stack'; interface WalletProps { enterSetup: any; exitTransaction: any; - navigation: any; + navigation: StackNavigationProp; BalanceStore: BalanceStore; ChannelsStore: ChannelsStore; NodeInfoStore: NodeInfoStore; @@ -120,7 +124,7 @@ export default class Wallet extends React.Component { private handleAppStateChangeSubscription: NativeEventSubscription; private backPressSubscription: NativeEventSubscription; - constructor(props) { + constructor(props: WalletProps) { super(props); this.state = { unlocked: false, @@ -154,22 +158,6 @@ export default class Wallet extends React.Component { } private handleBackButton() { - const dialogHasBeenClosed = - this.props.ModalStore.closeVisibleModalDialog(); - if (dialogHasBeenClosed) { - return true; - } - - if (this.props.SettingsStore.loginRequired()) { - // pop to close lock screen and return false to close the app - this.props.navigation.pop(); - return false; - } - - if (this.props.navigation.pop()) { - return true; - } - const tabNavigator = this.tabNavigationRef.current; if (!tabNavigator) { return false; @@ -192,25 +180,31 @@ export default class Wallet extends React.Component { return false; } + private handleFocus = () => { + this.backPressSubscription?.remove(); + this.backPressSubscription = BackHandler.addEventListener( + 'hardwareBackPress', + this.handleBackButton.bind(this) + ); + this.getSettingsAndNavigate(); + }; + + private handleBlur = () => this.backPressSubscription?.remove(); + async componentDidMount() { // triggers when loaded from navigation or back action - this.props.navigation.addListener('didFocus', () => { - this.getSettingsAndNavigate(); - }); + this.props.navigation.addListener('focus', this.handleFocus); + this.props.navigation.addListener('blur', this.handleBlur); this.handleAppStateChangeSubscription = AppState.addEventListener( 'change', this.handleAppStateChange ); - this.backPressSubscription = BackHandler.addEventListener( - 'hardwareBackPress', - this.handleBackButton.bind(this) - ); } componentWillUnmount() { this.props.navigation.removeListener && - this.props.navigation.removeListener('didFocus'); + this.props.navigation.removeListener('focus', this.handleFocus); this.handleAppStateChangeSubscription?.remove(); this.backPressSubscription?.remove(); } @@ -320,9 +314,12 @@ export default class Wallet extends React.Component { embeddedTor, initialLoad } = settings; - const expressGraphSyncEnabled = settings.expressGraphSync; + const expressGraphSyncEnabled = + settings.expressGraphSync && embeddedLndNetwork === 'Mainnet'; + let start; if (connecting) { + start = new Date().getTime(); NodeInfoStore.reset(); BalanceStore.reset(); ChannelsStore.reset(); @@ -391,7 +388,7 @@ export default class Wallet extends React.Component { if (SettingsStore.settings.automaticDisasterRecoveryBackup) ChannelBackupStore.initSubscribeChannelEvents(); } catch (e) { - console.log('recover error', e); + console.error('recover error', e); } } else { if (SettingsStore.settings.automaticDisasterRecoveryBackup) @@ -456,6 +453,9 @@ export default class Wallet extends React.Component { } if (connecting) { + console.log( + 'connect time: ' + (new Date().getTime() - start) / 1000 + 's' + ); setConnectingStatus(false); } @@ -621,6 +621,8 @@ export default class Wallet extends React.Component { ); }; + const CameraScreen = () => {}; + const ChannelsScreen = () => { return ( @@ -642,107 +644,134 @@ export default class Wallet extends React.Component { {!connecting && (!loginRequired || posEnabled !== PosEnabled.Disabled) && ( - - ({ - tabBarIcon: ({ color }) => { - if ( - isSyncing && - route.name === 'Keypad' - ) { - return; - } - if (route.name === 'Keypad') { - return ; - } - if (route.name === 'Balance') { - return ; - } - if (route.name === 'POS') { - return ; - } - if (route.name === 'POS Keypad') { - return ; - } - if ( - BackendUtils.supportsChannelManagement() - ) { - return ( - - ); - } - } - })} - tabBarOptions={{ - activeTintColor: error - ? themeColor('error') - : themeColor('text'), - inactiveTintColor: error - ? themeColor('error') - : 'gray', - showLabel: false - }} + + - {posEnabled !== PosEnabled.Disabled && - posStatus === 'active' ? ( - - ) : ( - - )} - {posEnabled === PosEnabled.Standalone && - posStatus === 'active' && - showKeypad && ( + ({ + tabBarIcon: ({ color }) => { + if ( + isSyncing && + route.name === 'Keypad' + ) { + return; + } + if (route.name === 'Keypad') { + return ; + } + if (route.name === 'Balance') { + return ; + } + if (route.name === 'POS') { + return ; + } + if (route.name === 'POS Keypad') { + return ; + } + if (route.name === 'Camera') { + return ( + + ); + } + if ( + BackendUtils.supportsChannelManagement() + ) { + return ( + + ); + } + }, + headerShown: false, + tabBarActiveTintColor: error + ? themeColor('error') + : themeColor('text'), + tabBarInactiveTintColor: error + ? themeColor('error') + : 'gray', + tabBarShowLabel: false, + tabBarStyle: { display: 'flex' } + })} + > + {posEnabled !== PosEnabled.Disabled && + posStatus === 'active' ? ( + + ) : ( )} - {posStatus !== 'active' && ( - <> - {!error && !isSyncing && ( + {posEnabled === PosEnabled.Standalone && + posStatus === 'active' && + showKeypad && ( )} - {BackendUtils.supportsChannelManagement() && - !error && - !isSyncing && ( + {posStatus !== 'active' && ( + <> + {!error && !isSyncing && ( )} - - )} - - + {BackendUtils.supportsChannelManagement() && + !error && + !isSyncing && ( + + )} + + )} + { + // Prevent default action + e.preventDefault(); + navigation.navigate( + 'HandleAnythingQRScanner' + ); + } + }} + /> + + + )} {connecting && (!loginRequired || posEnabled !== PosEnabled.Disabled) && ( @@ -797,9 +826,35 @@ export default class Wallet extends React.Component { + {isInExpressGraphSync && ( + + + )}