2019-01-12 01:23:32 +01:00
|
|
|
import React, { Component } from 'react';
|
2019-01-19 16:10:23 +01:00
|
|
|
import { TouchableOpacity, ActivityIndicator, View, Platform, Alert, Dimensions } from 'react-native';
|
2019-01-12 01:23:32 +01:00
|
|
|
import { WebView } from 'react-native-webview';
|
2019-01-19 16:10:23 +01:00
|
|
|
import WKWebView from 'react-native-wkwebview-reborn';
|
2019-01-16 05:06:16 +01:00
|
|
|
import { BlueNavigationStyle, SafeBlueArea } from '../../BlueComponents';
|
2019-01-12 01:23:32 +01:00
|
|
|
import { FormInput } from 'react-native-elements';
|
|
|
|
import Ionicons from 'react-native-vector-icons/Ionicons';
|
|
|
|
import PropTypes from 'prop-types';
|
2019-01-12 03:08:03 +01:00
|
|
|
const { width } = Dimensions.get('window');
|
2019-01-12 01:23:32 +01:00
|
|
|
|
2019-01-12 23:33:02 +01:00
|
|
|
let processedInvoices = {};
|
|
|
|
let lastTimeTriedToPay = 0;
|
|
|
|
|
2019-01-16 17:54:17 +01:00
|
|
|
/// ///////////////////////////////////////////////////////////////////////
|
|
|
|
// this code has no use in RN, it gets copypasted in webview injected code
|
|
|
|
//
|
|
|
|
let bluewalletResponses = {};
|
|
|
|
// eslint-disable-next-line
|
2019-01-17 21:34:29 +01:00
|
|
|
var webln = {
|
2019-01-16 17:54:17 +01:00
|
|
|
enable: function() {
|
2019-01-18 14:12:21 +01:00
|
|
|
window.postMessage(JSON.stringify({ enable: true }));
|
2019-01-16 17:54:17 +01:00
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
resolve(true);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
getInfo: function() {
|
|
|
|
window.postMessage('getInfo');
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
reject(new Error('not implemented'));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
sendPayment: function(paymentRequest) {
|
|
|
|
window.postMessage(JSON.stringify({ sendPayment: paymentRequest }));
|
|
|
|
return new Promise(function(resolve, reject) {
|
2019-01-17 21:34:29 +01:00
|
|
|
/* 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 */
|
2019-01-16 17:54:17 +01:00
|
|
|
});
|
|
|
|
},
|
|
|
|
makeInvoice: function(RequestInvoiceArgs) {
|
2019-01-17 21:34:29 +01:00
|
|
|
var id = Math.random();
|
2019-01-16 17:54:17 +01:00
|
|
|
window.postMessage(JSON.stringify({ makeInvoice: RequestInvoiceArgs, id: id }));
|
|
|
|
return new Promise(function(resolve, reject) {
|
2019-01-17 21:34:29 +01:00
|
|
|
var interval = setInterval(function() {
|
2019-01-16 17:54:17 +01:00
|
|
|
if (bluewalletResponses[id]) {
|
|
|
|
clearInterval(interval);
|
|
|
|
resolve(bluewalletResponses[id]);
|
|
|
|
}
|
|
|
|
}, 1000);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
signMessage: function() {
|
|
|
|
window.postMessage('signMessage');
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
reject(new Error('not implemented'));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
verifyMessage: function() {
|
|
|
|
window.postMessage('verifyMessage');
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
reject(new Error('not implemented'));
|
|
|
|
});
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// end injected code
|
|
|
|
/// /////////////////
|
|
|
|
/// /////////////////
|
|
|
|
|
2019-01-18 14:12:21 +01:00
|
|
|
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.postMessage(JSON.stringify({'enable': true}));
|
|
|
|
return new Promise(function(resolve, reject){
|
|
|
|
resolve(true);
|
|
|
|
})
|
|
|
|
},
|
|
|
|
getInfo : function () {
|
|
|
|
window.postMessage('getInfo');
|
|
|
|
return new Promise(function(resolve, reject){
|
|
|
|
reject('not implemented');
|
|
|
|
})
|
|
|
|
},
|
|
|
|
sendPayment: function(paymentRequest) {
|
|
|
|
window.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.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.postMessage('signMessage');
|
|
|
|
return new Promise(function(resolve, reject){
|
|
|
|
reject('not implemented');
|
|
|
|
})
|
|
|
|
},
|
|
|
|
verifyMessage: function () {
|
|
|
|
window.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.postMessage("inside webview, received post message: " + event.data);
|
|
|
|
var json;
|
|
|
|
try {
|
|
|
|
json = JSON.parse(event.data);
|
|
|
|
} 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.postMessage(JSON.stringify({sendPayment:invoice}));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* for non-webln compatible pages we do it oldschool,
|
|
|
|
searching for all bolt11 manually */
|
|
|
|
|
|
|
|
setInterval(function() {
|
|
|
|
window.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);
|
|
|
|
|
|
|
|
`;
|
|
|
|
|
2019-01-12 01:23:32 +01:00
|
|
|
export default class Browser extends Component {
|
|
|
|
static navigationOptions = ({ navigation }) => ({
|
|
|
|
...BlueNavigationStyle(navigation, true),
|
|
|
|
title: 'Lapp Browser',
|
|
|
|
headerLeft: null,
|
|
|
|
});
|
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
2019-01-12 03:08:03 +01:00
|
|
|
if (!props.navigation.getParam('fromSecret')) throw new Error('Invalid param');
|
2019-01-16 17:54:17 +01:00
|
|
|
if (!props.navigation.getParam('fromWallet')) throw new Error('Invalid param');
|
2019-01-12 03:08:03 +01:00
|
|
|
|
2019-01-16 17:54:17 +01:00
|
|
|
this.state = {
|
|
|
|
url: 'https://bluewallet.io/marketplace/',
|
|
|
|
pageIsLoading: false,
|
|
|
|
fromSecret: props.navigation.getParam('fromSecret'),
|
|
|
|
fromWallet: props.navigation.getParam('fromWallet'),
|
|
|
|
};
|
2019-01-12 01:23:32 +01:00
|
|
|
}
|
|
|
|
|
2019-01-19 16:10:23 +01:00
|
|
|
renderWebView = () => {
|
|
|
|
if (Platform.OS === 'android') {
|
2019-01-19 17:46:11 +01:00
|
|
|
return (
|
2019-01-19 16:10:23 +01:00
|
|
|
<WebView
|
2019-01-19 17:46:11 +01:00
|
|
|
ref={ref => (this.webview = ref)}
|
|
|
|
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 {
|
2019-01-19 21:39:09 +01:00
|
|
|
// checking that we do not trigger alert too often:
|
|
|
|
if (+new Date() - lastTimeTriedToPay < 3000) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lastTimeTriedToPay = +new Date();
|
|
|
|
//
|
2019-01-19 17:46:11 +01:00
|
|
|
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({
|
|
|
|
routeName: 'ScanLndInvoice',
|
|
|
|
params: {
|
|
|
|
uri: json.sendPayment,
|
|
|
|
fromSecret: this.state.fromSecret,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
{ cancelable: false },
|
|
|
|
);
|
2019-01-19 16:10:23 +01:00
|
|
|
}
|
|
|
|
|
2019-01-19 17:46:11 +01:00
|
|
|
if (json && json.makeInvoice) {
|
|
|
|
let amount = Math.max(+json.makeInvoice.minimumAmount, +json.makeInvoice.maximumAmount, +json.makeInvoice.defaultAmount);
|
|
|
|
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 }));
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
{ cancelable: false },
|
|
|
|
);
|
2019-01-19 16:10:23 +01:00
|
|
|
}
|
|
|
|
|
2019-01-19 17:46:11 +01:00
|
|
|
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.injectJavaScript(injectedParadise);
|
|
|
|
alreadyInjected = true;
|
|
|
|
console.log('injected');
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
2019-01-19 16:10:23 +01:00
|
|
|
} else if (Platform.OS === 'ios') {
|
2019-01-19 17:46:11 +01:00
|
|
|
return (
|
2019-01-19 16:10:23 +01:00
|
|
|
<WKWebView
|
2019-01-19 17:46:11 +01:00
|
|
|
ref={ref => (this.webview = ref)}
|
|
|
|
source={{ uri: this.state.url }}
|
|
|
|
injectJavaScript={injectedParadise}
|
|
|
|
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 we do not trigger alert too often:
|
|
|
|
if (+new Date() - lastTimeTriedToPay < 3000) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
lastTimeTriedToPay = +new Date();
|
|
|
|
|
|
|
|
// checking that already asked about this invoice:
|
|
|
|
if (processedInvoices[json.sendPayment]) {
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
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({
|
|
|
|
routeName: 'ScanLndInvoice',
|
|
|
|
params: {
|
|
|
|
uri: json.sendPayment,
|
|
|
|
fromSecret: this.state.fromSecret,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
{ cancelable: false },
|
|
|
|
);
|
2019-01-19 16:10:23 +01:00
|
|
|
}
|
|
|
|
|
2019-01-19 17:46:11 +01:00
|
|
|
if (json && json.makeInvoice) {
|
|
|
|
let amount = Math.max(+json.makeInvoice.minimumAmount, +json.makeInvoice.maximumAmount, +json.makeInvoice.defaultAmount);
|
|
|
|
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 }));
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
{ cancelable: false },
|
|
|
|
);
|
2019-01-19 16:10:23 +01:00
|
|
|
}
|
|
|
|
|
2019-01-19 17:46:11 +01:00
|
|
|
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 });
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
2019-01-19 16:10:23 +01:00
|
|
|
}
|
2019-01-19 17:46:11 +01:00
|
|
|
};
|
2019-01-12 01:23:32 +01:00
|
|
|
render() {
|
|
|
|
return (
|
2019-01-16 05:06:16 +01:00
|
|
|
<SafeBlueArea>
|
2019-01-12 01:23:32 +01:00
|
|
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
2019-01-16 02:20:35 +01:00
|
|
|
<TouchableOpacity
|
2019-01-12 01:23:32 +01:00
|
|
|
onPress={() => {
|
|
|
|
this.webview.goBack();
|
|
|
|
}}
|
2019-01-16 02:20:35 +01:00
|
|
|
>
|
|
|
|
<Ionicons
|
|
|
|
name={'ios-arrow-round-back'}
|
|
|
|
size={36}
|
|
|
|
style={{
|
|
|
|
color: 'red',
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
paddingLeft: 10,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</TouchableOpacity>
|
2019-01-12 01:23:32 +01:00
|
|
|
|
|
|
|
<FormInput
|
2019-01-16 02:20:35 +01:00
|
|
|
inputStyle={{ color: '#0c2550', maxWidth: width - 150, fontSize: 16 }}
|
2019-01-12 01:23:32 +01:00
|
|
|
containerStyle={{
|
2019-01-16 02:20:35 +01:00
|
|
|
maxWidth: width - 150,
|
2019-01-12 01:23:32 +01:00
|
|
|
borderColor: '#d2d2d2',
|
|
|
|
borderWidth: 0.5,
|
|
|
|
backgroundColor: '#f5f5f5',
|
|
|
|
}}
|
|
|
|
value={this.state.url}
|
|
|
|
/>
|
|
|
|
|
2019-01-16 02:20:35 +01:00
|
|
|
<TouchableOpacity
|
2019-01-12 01:23:32 +01:00
|
|
|
onPress={() => {
|
2019-01-18 14:12:21 +01:00
|
|
|
processedInvoices = {};
|
2019-01-16 02:20:35 +01:00
|
|
|
this.setState({ url: 'https://bluewallet.io/marketplace/' });
|
2019-01-12 01:23:32 +01:00
|
|
|
}}
|
2019-01-16 02:20:35 +01:00
|
|
|
>
|
|
|
|
<Ionicons
|
|
|
|
name={'ios-home'}
|
|
|
|
size={36}
|
|
|
|
style={{
|
2019-01-18 14:12:21 +01:00
|
|
|
color: this.state.weblnEnabled ? 'green' : 'red',
|
2019-01-16 02:20:35 +01:00
|
|
|
backgroundColor: 'transparent',
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
|
|
<TouchableOpacity
|
|
|
|
onPress={() => {
|
2019-01-18 14:12:21 +01:00
|
|
|
let reloadUrl = this.state.url;
|
|
|
|
this.setState({ url: 'about:blank' });
|
|
|
|
processedInvoices = {};
|
|
|
|
setTimeout(() => this.setState({ url: reloadUrl }), 500);
|
|
|
|
// this.webview.reload();
|
2019-01-12 01:23:32 +01:00
|
|
|
}}
|
2019-01-16 02:20:35 +01:00
|
|
|
>
|
|
|
|
{(!this.state.pageIsLoading && (
|
|
|
|
<Ionicons
|
|
|
|
name={'ios-sync'}
|
|
|
|
size={36}
|
|
|
|
style={{
|
|
|
|
color: 'red',
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
paddingLeft: 15,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
)) || (
|
|
|
|
<View style={{ paddingLeft: 20 }}>
|
|
|
|
<ActivityIndicator />
|
|
|
|
</View>
|
|
|
|
)}
|
|
|
|
</TouchableOpacity>
|
2019-01-12 01:23:32 +01:00
|
|
|
</View>
|
2019-01-19 17:46:11 +01:00
|
|
|
{this.renderWebView()}
|
2019-01-16 05:06:16 +01:00
|
|
|
</SafeBlueArea>
|
2019-01-12 01:23:32 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Browser.propTypes = {
|
|
|
|
navigation: PropTypes.shape({
|
2019-02-01 16:28:43 +01:00
|
|
|
getParam: PropTypes.func,
|
2019-01-12 01:23:32 +01:00
|
|
|
navigate: PropTypes.func,
|
|
|
|
}),
|
|
|
|
};
|