mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 01:40:12 +01:00
DEL: Lapp Browser
This commit is contained in:
parent
440e4d407e
commit
a651b66c64
@ -71,7 +71,6 @@ import { isDesktop, isHandset, isTablet } from './blue_modules/environment';
|
||||
import navigationStyle from './components/navigationStyle';
|
||||
import { useTheme } from './components/themes';
|
||||
import loc from './loc';
|
||||
import LappBrowser from './screen/lnd/browser';
|
||||
import LdkInfo from './screen/lnd/ldkInfo';
|
||||
import LdkOpenChannel from './screen/lnd/ldkOpenChannel';
|
||||
import LNDCreateInvoice from './screen/lnd/lndCreateInvoice';
|
||||
@ -492,17 +491,6 @@ const WalletExportStackRoot = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const LappBrowserStack = createNativeStackNavigator();
|
||||
const LappBrowserStackRoot = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<LappBrowserStack.Navigator id="LappBrowserRoot" screenOptions={{ headerShadowVisible: false }} initialRouteName="LappBrowser">
|
||||
<LappBrowserStack.Screen name="LappBrowser" component={LappBrowser} options={LappBrowser.navigationOptions(theme)} />
|
||||
</LappBrowserStack.Navigator>
|
||||
);
|
||||
};
|
||||
|
||||
const InitStack = createNativeStackNavigator();
|
||||
const InitRoot = () => {
|
||||
const { walletsInitialized } = useContext(BlueStorageContext);
|
||||
@ -638,7 +626,6 @@ const Navigation = () => {
|
||||
/>
|
||||
<RootStack.Screen name="SelectWallet" component={SelectWallet} />
|
||||
<RootStack.Screen name="ReceiveDetailsRoot" component={ReceiveDetailsStackRoot} options={NavigationDefaultOptions} />
|
||||
<RootStack.Screen name="LappBrowserRoot" component={LappBrowserStackRoot} options={NavigationDefaultOptions} />
|
||||
<RootStack.Screen name="LDKOpenChannelRoot" component={LDKOpenChannelRoot} options={NavigationDefaultOptions} />
|
||||
|
||||
<RootStack.Screen
|
||||
|
@ -1,11 +1,10 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import bip21, { TOptions } from 'bip21';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import URL from 'url';
|
||||
|
||||
import { readFileOutsideSandbox } from '../blue_modules/fs';
|
||||
import { Chain } from '../models/bitcoinUnits';
|
||||
import { BlueApp, LightningCustodianWallet, WatchOnlyWallet } from './';
|
||||
import { WatchOnlyWallet } from './';
|
||||
import Azteco from './azteco';
|
||||
import Lnurl from './lnurl';
|
||||
import type { TWallet } from './wallets/types';
|
||||
@ -215,64 +214,6 @@ class DeeplinkSchemaMatch {
|
||||
(async () => {
|
||||
if (urlObject.protocol === 'bluewallet:' || urlObject.protocol === 'lapp:' || urlObject.protocol === 'blue:') {
|
||||
switch (urlObject.host) {
|
||||
case 'openlappbrowser': {
|
||||
console.log('opening LAPP', urlObject.query.url);
|
||||
// searching for LN wallet:
|
||||
let haveLnWallet = false;
|
||||
for (const w of context.wallets) {
|
||||
if (w.type === LightningCustodianWallet.type) {
|
||||
haveLnWallet = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveLnWallet) {
|
||||
// need to create one
|
||||
const w = new LightningCustodianWallet();
|
||||
w.setLabel(w.typeReadable);
|
||||
|
||||
try {
|
||||
const lndhub = await AsyncStorage.getItem(BlueApp.LNDHUB);
|
||||
if (lndhub) {
|
||||
w.setBaseURI(lndhub);
|
||||
w.init();
|
||||
}
|
||||
await w.createAccount();
|
||||
await w.authorize();
|
||||
} catch (Err) {
|
||||
// giving up, not doing anything
|
||||
return;
|
||||
}
|
||||
context.addWallet(w);
|
||||
context.saveToDisk();
|
||||
}
|
||||
|
||||
// now, opening lapp browser and navigating it to URL.
|
||||
// looking for a LN wallet:
|
||||
let lnWallet;
|
||||
for (const w of context.wallets) {
|
||||
if (w.type === LightningCustodianWallet.type) {
|
||||
lnWallet = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lnWallet) {
|
||||
// something went wrong
|
||||
return;
|
||||
}
|
||||
|
||||
completionHandler([
|
||||
'LappBrowserRoot',
|
||||
{
|
||||
screen: 'LappBrowser',
|
||||
params: {
|
||||
walletID: lnWallet.getID(),
|
||||
url: urlObject.query.url,
|
||||
},
|
||||
},
|
||||
]);
|
||||
break;
|
||||
}
|
||||
case 'setelectrumserver':
|
||||
completionHandler([
|
||||
'ElectrumSettings',
|
||||
|
@ -352,9 +352,6 @@ PODS:
|
||||
- react-native-tcp-socket (6.0.6):
|
||||
- CocoaAsyncSocket
|
||||
- React-Core
|
||||
- react-native-webview (13.8.6):
|
||||
- RCT-Folly (= 2021.07.22.00)
|
||||
- React-Core
|
||||
- react-native-widget-center (0.0.9):
|
||||
- React
|
||||
- React-NativeModulesApple (0.72.12):
|
||||
@ -563,7 +560,6 @@ DEPENDENCIES:
|
||||
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
|
||||
- react-native-secure-key-store (from `../node_modules/react-native-secure-key-store`)
|
||||
- react-native-tcp-socket (from `../node_modules/react-native-tcp-socket`)
|
||||
- react-native-webview (from `../node_modules/react-native-webview`)
|
||||
- react-native-widget-center (from `../node_modules/react-native-widget-center`)
|
||||
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
|
||||
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
|
||||
@ -691,8 +687,6 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-secure-key-store"
|
||||
react-native-tcp-socket:
|
||||
:path: "../node_modules/react-native-tcp-socket"
|
||||
react-native-webview:
|
||||
:path: "../node_modules/react-native-webview"
|
||||
react-native-widget-center:
|
||||
:path: "../node_modules/react-native-widget-center"
|
||||
React-NativeModulesApple:
|
||||
@ -822,7 +816,6 @@ SPEC CHECKSUMS:
|
||||
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b
|
||||
react-native-secure-key-store: 910e6df6bc33cb790aba6ee24bc7818df1fe5898
|
||||
react-native-tcp-socket: e724380c910c2e704816ec817ed28f1342246ff7
|
||||
react-native-webview: 2ce07db2190ee7b3af77e8fac75ff47abe47089f
|
||||
react-native-widget-center: 12dfba20a4fa995850b52cf0afecf734397f4b9c
|
||||
React-NativeModulesApple: 694679e4193a49c09f0a76ee27ec09b2c466d59c
|
||||
React-perflogger: 63606aeab27683112e1bd4ef25bd099ec1cb03f8
|
||||
|
@ -449,7 +449,6 @@
|
||||
"list_empty_txs2": "Start with your wallet.",
|
||||
"list_empty_txs2_lightning": "\nTo start using it, tap on Manage Funds and topup your balance.",
|
||||
"list_latest_transaction": "Latest Transaction",
|
||||
"list_ln_browser": "LApp Browser",
|
||||
"list_long_choose": "Choose Photo",
|
||||
"list_long_clipboard": "Copy from Clipboard",
|
||||
"list_long_scan": "Scan QR Code",
|
||||
|
38
package-lock.json
generated
38
package-lock.json
generated
@ -97,7 +97,6 @@
|
||||
"react-native-tcp-socket": "6.0.6",
|
||||
"react-native-vector-icons": "10.0.3",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webview": "13.8.6",
|
||||
"react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38",
|
||||
"readable-stream": "3.6.2",
|
||||
"realm": "12.7.0",
|
||||
@ -19827,27 +19826,6 @@
|
||||
"react-native": ">=0.40"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-webview": {
|
||||
"version": "13.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.6.tgz",
|
||||
"integrity": "sha512-jtZ9OgB2AN6rhDwto6dNL3PtOtl/SI4VN93pZEPbMLvRjqHfxiUrilGllL5fKAXq5Ry5FJyfUi82A4Ii8olZ7A==",
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "2.0.0",
|
||||
"invariant": "2.2.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-webview/node_modules/escape-string-regexp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
|
||||
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-widget-center": {
|
||||
"version": "0.0.9",
|
||||
"resolved": "git+ssh://git@github.com/BlueWallet/react-native-widget-center.git#a128c389526d55afdd67937494f2fec224dd0009",
|
||||
@ -37368,22 +37346,6 @@
|
||||
"lodash.sortby": "^4.7.0"
|
||||
}
|
||||
},
|
||||
"react-native-webview": {
|
||||
"version": "13.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.8.6.tgz",
|
||||
"integrity": "sha512-jtZ9OgB2AN6rhDwto6dNL3PtOtl/SI4VN93pZEPbMLvRjqHfxiUrilGllL5fKAXq5Ry5FJyfUi82A4Ii8olZ7A==",
|
||||
"requires": {
|
||||
"escape-string-regexp": "2.0.0",
|
||||
"invariant": "2.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"escape-string-regexp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
|
||||
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-native-widget-center": {
|
||||
"version": "git+ssh://git@github.com/BlueWallet/react-native-widget-center.git#a128c389526d55afdd67937494f2fec224dd0009",
|
||||
"from": "react-native-widget-center@https://github.com/BlueWallet/react-native-widget-center#a128c38"
|
||||
|
@ -184,7 +184,6 @@
|
||||
"react-native-tcp-socket": "6.0.6",
|
||||
"react-native-vector-icons": "10.0.3",
|
||||
"react-native-watch-connectivity": "1.1.0",
|
||||
"react-native-webview": "13.8.6",
|
||||
"react-native-widget-center": "https://github.com/BlueWallet/react-native-widget-center#a128c38",
|
||||
"readable-stream": "3.6.2",
|
||||
"realm": "12.7.0",
|
||||
|
@ -1,527 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { ActivityIndicator, Alert, BackHandler, Keyboard, Platform, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
|
||||
import { WebView } from 'react-native-webview';
|
||||
|
||||
import navigationStyle from '../../components/navigationStyle';
|
||||
import Notifications from '../../blue_modules/notifications';
|
||||
import loc from '../../loc';
|
||||
import { Button } from 'react-native-elements';
|
||||
import { BlueStorageContext } from '../../blue_modules/storage-context';
|
||||
import SafeArea from '../../components/SafeArea';
|
||||
|
||||
let processedInvoices = {};
|
||||
let lastTimeTriedToPay = 0;
|
||||
|
||||
/// ///////////////////////////////////////////////////////////////////////
|
||||
// this code has no use in RN, it gets copypasted in webview injected code
|
||||
//
|
||||
const bluewalletResponses = {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-var
|
||||
var webln = {
|
||||
enable: function () {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({ enable: true }));
|
||||
return new Promise(function (resolve, reject) {
|
||||
resolve(true);
|
||||
});
|
||||
},
|
||||
getInfo: function () {
|
||||
window.ReactNativeWebView.postMessage('getInfo');
|
||||
return new Promise(function (resolve, reject) {
|
||||
reject(new Error('not implemented'));
|
||||
});
|
||||
},
|
||||
sendPayment: function (paymentRequest) {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
|
||||
return new Promise(function (resolve, reject) {
|
||||
/* nop. intentionally, forever hang promise.
|
||||
lapp page usually asynchroniously checks payment itself, via ajax,
|
||||
so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
|
||||
might change in future */
|
||||
});
|
||||
},
|
||||
makeInvoice: function (RequestInvoiceArgs) {
|
||||
var id = Math.random(); // eslint-disable-line no-var
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({ makeInvoice: RequestInvoiceArgs, id }));
|
||||
return new Promise(function (resolve, reject) {
|
||||
// eslint-disable-next-line no-var
|
||||
var interval = setInterval(function () {
|
||||
if (bluewalletResponses[id]) {
|
||||
clearInterval(interval);
|
||||
resolve(bluewalletResponses[id]);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
signMessage: function () {
|
||||
window.ReactNativeWebView.postMessage('signMessage');
|
||||
return new Promise(function (resolve, reject) {
|
||||
reject(new Error('not implemented'));
|
||||
});
|
||||
},
|
||||
verifyMessage: function () {
|
||||
window.ReactNativeWebView.postMessage('verifyMessage');
|
||||
return new Promise(function (resolve, reject) {
|
||||
reject(new Error('not implemented'));
|
||||
});
|
||||
},
|
||||
};
|
||||
// end injected code
|
||||
/// /////////////////
|
||||
/// /////////////////
|
||||
|
||||
let alreadyInjected = false;
|
||||
const injectedParadise = `
|
||||
|
||||
/* rules:
|
||||
no 'let', only 'var'
|
||||
no arrow functions
|
||||
globals without 'var'
|
||||
should work if compressed to single line
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* this is a storage of responses from OUTER code (react native)
|
||||
it gets written by message bus handler callback:
|
||||
webview makes a call through bus to RN, each request with a unique ID.
|
||||
RN processes the request from the bus, and posts response to the bus, with the same ID.
|
||||
webview callback handler writes it in this hashmap. Then, some other code that patiently
|
||||
waits for a response will see that the answer with such ID is present, and will fulfill a promise */
|
||||
|
||||
bluewalletResponses = {};
|
||||
|
||||
|
||||
/* this is injected WEBLN provider */
|
||||
|
||||
|
||||
webln = {
|
||||
enable : function () {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({'enable': true}));
|
||||
return new Promise(function(resolve, reject){
|
||||
resolve(true);
|
||||
})
|
||||
},
|
||||
getInfo : function () {
|
||||
window.ReactNativeWebView.postMessage('getInfo');
|
||||
return new Promise(function(resolve, reject){
|
||||
reject('not implemented');
|
||||
})
|
||||
},
|
||||
sendPayment: function(paymentRequest) {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
|
||||
return new Promise(function(resolve, reject) {
|
||||
/* nop. intentionally, forever hang promise.
|
||||
lapp page usually asynchroniously checks payment itself, via ajax,
|
||||
so atm there's no need to pass payment preimage from RN to webview and fullfill promise.
|
||||
might change in future */
|
||||
});
|
||||
},
|
||||
makeInvoice: function (RequestInvoiceArgs) {
|
||||
var id = Math.random();
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({makeInvoice: RequestInvoiceArgs, id: id}));
|
||||
return new Promise(function(resolve, reject) {
|
||||
var interval = setInterval(function () {
|
||||
if (bluewalletResponses[id]) {
|
||||
clearInterval(interval);
|
||||
resolve(bluewalletResponses[id]);
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
signMessage: function () {
|
||||
window.ReactNativeWebView.postMessage('signMessage');
|
||||
return new Promise(function(resolve, reject){
|
||||
reject('not implemented');
|
||||
})
|
||||
},
|
||||
verifyMessage: function () {
|
||||
window.ReactNativeWebView.postMessage('verifyMessage');
|
||||
return new Promise(function(resolve, reject){
|
||||
reject('not implemented');
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/* end WEBLN */
|
||||
|
||||
/* listening to events that might come from RN: */
|
||||
document.addEventListener("message", function(event) {
|
||||
window.ReactNativeWebView.postMessage("inside webview, received post message: " + event.detail);
|
||||
var json;
|
||||
try {
|
||||
json = JSON.parse(event.detail);
|
||||
} catch (_) {}
|
||||
|
||||
if (json && json.bluewalletResponse) {
|
||||
/* this is an answer to one of our inside-webview calls.
|
||||
we store it in answers hashmap for someone who cares about it */
|
||||
bluewalletResponses[json.id] = json.bluewalletResponse
|
||||
}
|
||||
|
||||
}, false);
|
||||
|
||||
|
||||
|
||||
|
||||
function tryToPay(invoice) {
|
||||
window.ReactNativeWebView.postMessage(JSON.stringify({sendPayment:invoice}));
|
||||
}
|
||||
|
||||
/* for non-webln compatible pages we do it oldschool,
|
||||
searching for all bolt11 manually */
|
||||
|
||||
setInterval(function() {
|
||||
window.ReactNativeWebView.postMessage('interval');
|
||||
|
||||
var searchText = "lnbc";
|
||||
|
||||
var aTags = document.getElementsByTagName("span");
|
||||
var i;
|
||||
for (i = 0; i < aTags.length; i++) {
|
||||
if (aTags[i].textContent.indexOf(searchText) === 0) {
|
||||
tryToPay(aTags[i].textContent);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------- */
|
||||
|
||||
aTags = document.getElementsByTagName("input");
|
||||
for (i = 0; i < aTags.length; i++) {
|
||||
if (aTags[i].value.indexOf(searchText) === 0) {
|
||||
tryToPay(aTags[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------- */
|
||||
|
||||
aTags = document.getElementsByTagName("a");
|
||||
searchText = "lightning:lnbc";
|
||||
|
||||
|
||||
for (i = 0; i < aTags.length; i++) {
|
||||
var href = aTags[i].getAttribute('href') + '';
|
||||
if (href.indexOf(searchText) === 0) {
|
||||
tryToPay(href.replace('lightning:', ''));
|
||||
}
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
|
||||
`;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safeRoot: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
minHeight: 44,
|
||||
},
|
||||
safeURL: {
|
||||
flex: 1,
|
||||
marginHorizontal: 8,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
safeURLTextWrap: {
|
||||
flexDirection: 'row',
|
||||
borderColor: '#d2d2d2',
|
||||
borderBottomColor: '#d2d2d2',
|
||||
borderWidth: 1.0,
|
||||
borderBottomWidth: 0.5,
|
||||
backgroundColor: '#f5f5f5',
|
||||
minHeight: 44,
|
||||
height: 44,
|
||||
alignItems: 'center',
|
||||
marginVertical: 8,
|
||||
borderRadius: 4,
|
||||
},
|
||||
safeURLText: {
|
||||
flex: 1,
|
||||
marginLeft: 4,
|
||||
minHeight: 33,
|
||||
color: '#81868e',
|
||||
},
|
||||
safeURLHome: {
|
||||
alignContent: 'flex-end',
|
||||
height: 44,
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: 8,
|
||||
},
|
||||
sync: {
|
||||
color: 'red',
|
||||
backgroundColor: 'transparent',
|
||||
paddingLeft: 15,
|
||||
},
|
||||
activity: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
paddingLeft: 20,
|
||||
alignContent: 'center',
|
||||
},
|
||||
goBack: {
|
||||
backgroundColor: 'transparent',
|
||||
paddingLeft: 10,
|
||||
},
|
||||
colorRed: {
|
||||
color: 'red',
|
||||
},
|
||||
// eslint-disable-next-line react-native/no-unused-styles
|
||||
colorGray: {
|
||||
color: 'gray',
|
||||
},
|
||||
transparent: {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
colorGreen: {
|
||||
color: 'green',
|
||||
},
|
||||
});
|
||||
|
||||
export default class Browser extends Component {
|
||||
webView = React.createRef();
|
||||
constructor(props, context) {
|
||||
super(props);
|
||||
if (!props.route.params.walletID) throw new Error('Missing walletID param');
|
||||
let url;
|
||||
if (props.route.params.url) url = props.route.params.url;
|
||||
|
||||
this.state = {
|
||||
url: url || 'https://www.duckduckgo.com/',
|
||||
fromWallet: context.wallets.find(w => w.getID() === props.route.params.walletID),
|
||||
canGoBack: false,
|
||||
pageIsLoading: false,
|
||||
stateURL: url || 'https://www.duckduckgo.com/',
|
||||
};
|
||||
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton.bind(this));
|
||||
}
|
||||
|
||||
componentWillUnmount = () => {
|
||||
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton.bind(this));
|
||||
};
|
||||
|
||||
handleBackButton() {
|
||||
this.state.canGoBack ? this.webView.current?.goBack() : this.props.navigation.goBack(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
_onNavigationStateChange = webViewState => {
|
||||
this.setState({ canGoBack: webViewState.canGoBack, stateURL: webViewState.url });
|
||||
};
|
||||
|
||||
renderWebView = () => {
|
||||
return (
|
||||
<WebView
|
||||
onNavigationStateChange={this._onNavigationStateChange}
|
||||
ref={this.webView}
|
||||
source={{ uri: this.state.url }}
|
||||
onMessage={e => {
|
||||
// this is a handler which receives messages sent from within the browser
|
||||
console.log('---- message from the bus:', e.nativeEvent.data);
|
||||
let json = false;
|
||||
try {
|
||||
json = JSON.parse(e.nativeEvent.data);
|
||||
} catch (_) {}
|
||||
// message from browser has ln invoice
|
||||
if (json && json.sendPayment) {
|
||||
// checking that already asked about this invoice:
|
||||
if (processedInvoices[json.sendPayment]) {
|
||||
return;
|
||||
} else {
|
||||
// checking that we do not trigger alert too often:
|
||||
if (+new Date() - lastTimeTriedToPay < 3000) {
|
||||
return;
|
||||
}
|
||||
lastTimeTriedToPay = +new Date();
|
||||
//
|
||||
processedInvoices[json.sendPayment] = 1;
|
||||
}
|
||||
|
||||
Alert.alert(
|
||||
'Page',
|
||||
'This page asks for permission to pay an invoice',
|
||||
[
|
||||
{ text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel' },
|
||||
{
|
||||
text: 'Pay',
|
||||
onPress: () => {
|
||||
console.log('OK Pressed');
|
||||
this.props.navigation.navigate('ScanLndInvoiceRoot', {
|
||||
screen: 'ScanLndInvoice',
|
||||
params: {
|
||||
uri: json.sendPayment,
|
||||
walletID: this.state.fromWallet.getID(),
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
}
|
||||
|
||||
if (json && json.makeInvoice) {
|
||||
const amount = Math.max(
|
||||
json.makeInvoice.minimumAmount || 0,
|
||||
json.makeInvoice.maximumAmount || 0,
|
||||
json.makeInvoice.defaultAmount || 0,
|
||||
json.makeInvoice.amount || 0,
|
||||
);
|
||||
Alert.alert(
|
||||
'Page',
|
||||
'This page wants to pay you ' + amount + ' sats (' + json.makeInvoice.defaultMemo + ')',
|
||||
[
|
||||
{ text: 'No thanks', onPress: () => console.log('Cancel Pressed'), style: 'cancel' },
|
||||
{
|
||||
text: 'Accept',
|
||||
onPress: async () => {
|
||||
/** @type {LightningCustodianWallet} */
|
||||
const fromWallet = this.state.fromWallet;
|
||||
const payreq = await fromWallet.addInvoice(amount, json.makeInvoice.defaultMemo || ' ');
|
||||
// this.webView.postMessage(JSON.stringify({ bluewalletResponse: { paymentRequest: payreq }, id: json.id }));
|
||||
// Since webview.postMessage is removed from webview, we inject javascript that will manually triger document
|
||||
// event; note how data is passed in 'detail', not 'data'
|
||||
const jsonstr = JSON.stringify({ bluewalletResponse: { paymentRequest: payreq }, id: json.id });
|
||||
this.webView.current?.injectJavaScript(
|
||||
"document.dispatchEvent( new CustomEvent('message', { detail: '" + jsonstr + "' }) );",
|
||||
);
|
||||
|
||||
// lets decode payreq and subscribe groundcontrol so we can receive push notification when our invoice is paid
|
||||
const decoded = await fromWallet.decodeInvoice(payreq);
|
||||
await Notifications.tryToObtainPermissions();
|
||||
Notifications.majorTomToGroundControl([], [decoded.payment_hash], []);
|
||||
},
|
||||
},
|
||||
],
|
||||
{ cancelable: false },
|
||||
);
|
||||
}
|
||||
|
||||
if (json && json.enable) {
|
||||
console.log('webln enabled');
|
||||
this.setState({ weblnEnabled: true });
|
||||
}
|
||||
}}
|
||||
onLoadStart={e => {
|
||||
alreadyInjected = false;
|
||||
console.log('load start');
|
||||
this.setState({ pageIsLoading: true, weblnEnabled: false });
|
||||
}}
|
||||
onLoadEnd={e => {
|
||||
console.log('load end');
|
||||
this.setState({ url: e.nativeEvent.url, pageIsLoading: false });
|
||||
}}
|
||||
onLoadProgress={e => {
|
||||
console.log('progress:', e.nativeEvent.progress);
|
||||
if (!alreadyInjected && e.nativeEvent.progress > 0.5) {
|
||||
this.webView.current?.injectJavaScript(injectedParadise);
|
||||
alreadyInjected = true;
|
||||
console.log('injected');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SafeArea>
|
||||
<View style={styles.safeRoot}>
|
||||
<Button
|
||||
icon={{
|
||||
type: 'ionicon',
|
||||
name: 'arrow-back-outline',
|
||||
size: 36,
|
||||
color: this.state.canGoBack ? styles.colorRed.color : styles.colorGray.color,
|
||||
}}
|
||||
type="clear"
|
||||
disabled={!this.state.canGoBack}
|
||||
style={styles.goBack}
|
||||
onPress={() => this.webView.current?.goBack()}
|
||||
/>
|
||||
|
||||
<View style={styles.safeURL}>
|
||||
<View style={styles.safeURLTextWrap}>
|
||||
<TextInput
|
||||
onChangeText={text => this.setState({ stateURL: text })}
|
||||
value={this.state.stateURL}
|
||||
numberOfLines={1}
|
||||
placeholderTextColor="#81868e"
|
||||
style={styles.safeURLText}
|
||||
editable
|
||||
textContentType="URL"
|
||||
keyboardType="url"
|
||||
autoCorrect={false}
|
||||
autoCapitalize="none"
|
||||
onSubmitEditing={() => {
|
||||
Keyboard.dismiss();
|
||||
let url = this.state.stateURL;
|
||||
if (!url.toLowerCase().startsWith('http://') && !url.toLowerCase().startsWith('https://')) {
|
||||
url = 'https://' + url;
|
||||
}
|
||||
this.setState({ url });
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.safeURLHome}>
|
||||
{Platform.OS !== 'ios' && ( // on iOS lappbrowser opens blank page, thus, no HOME button
|
||||
<TouchableOpacity
|
||||
accessibilityRole="button"
|
||||
onPress={() => {
|
||||
processedInvoices = {};
|
||||
this.setState({ url: 'https://www.duckduckgo.com/' });
|
||||
}}
|
||||
>
|
||||
<Ionicons
|
||||
name="ios-home"
|
||||
size={36}
|
||||
style={[styles.transparent, this.state.weblnEnabled ? styles.colorGreen : styles.colorRed]}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
<TouchableOpacity
|
||||
accessibilityRole="button"
|
||||
onPress={() => {
|
||||
this.webView.current?.reload();
|
||||
}}
|
||||
>
|
||||
{!this.state.pageIsLoading ? (
|
||||
<Ionicons name="ios-sync" size={36} style={styles.sync} />
|
||||
) : (
|
||||
<View style={styles.activity}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
{this.renderWebView()}
|
||||
</SafeArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Browser.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func,
|
||||
goBack: PropTypes.func,
|
||||
}),
|
||||
route: PropTypes.shape({
|
||||
params: PropTypes.object,
|
||||
}),
|
||||
};
|
||||
|
||||
Browser.contextType = BlueStorageContext;
|
||||
|
||||
Browser.navigationOptions = navigationStyle(
|
||||
{
|
||||
headerBackVisible: false,
|
||||
closeButton: true,
|
||||
statusBarStyle: 'auto',
|
||||
},
|
||||
opts => ({ ...opts, title: loc.wallets.list_ln_browser }),
|
||||
);
|
@ -277,7 +277,6 @@ const WalletTransactions = ({ navigation }) => {
|
||||
|
||||
return (
|
||||
<View style={styles.flex}>
|
||||
<View style={styles.listHeader}>{wallet.chain === Chain.OFFCHAIN && renderLappBrowserButton()}</View>
|
||||
{wallet.type === LightningLdkWallet.type && (lnNodeInfo.canSend > 0 || lnNodeInfo.canReceive > 0) && (
|
||||
<View style={[styles.marginHorizontal18, styles.marginBottom18]}>
|
||||
<LNNodeBar canSend={lnNodeInfo.canSend} canReceive={lnNodeInfo.canReceive} itemPriceUnit={itemPriceUnit} />
|
||||
@ -290,26 +289,6 @@ const WalletTransactions = ({ navigation }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const renderLappBrowserButton = () => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
accessibilityRole="button"
|
||||
onPress={() => {
|
||||
navigate('LappBrowserRoot', {
|
||||
screen: 'LappBrowser',
|
||||
params: {
|
||||
walletID,
|
||||
url: 'https://duckduckgo.com',
|
||||
},
|
||||
});
|
||||
}}
|
||||
style={[styles.browserButton2, stylesHook.browserButton2]}
|
||||
>
|
||||
<Text style={[styles.marketpalceText1, stylesHook.marketpalceText1]}>{loc.wallets.list_ln_browser}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const onWalletSelect = async selectedWallet => {
|
||||
if (selectedWallet) {
|
||||
navigate('WalletTransactions', {
|
||||
|
Loading…
Reference in New Issue
Block a user