From d76b889d66e16e9861da3664a9907d57bee72a87 Mon Sep 17 00:00:00 2001 From: Bruno Barbieri Date: Fri, 8 Nov 2019 13:12:19 -0500 Subject: [PATCH 1/3] walletconnect deeplink support --- android/app/build.gradle | 3 +- app/components/Nav/Main/index.js | 11 +++ .../__snapshots__/index.test.js.snap | 81 +++++++++++++++++++ .../UI/BlockingActionModal/index.js | 56 +++++++++++++ .../UI/BlockingActionModal/index.test.js | 15 ++++ .../__snapshots__/index.test.js.snap | 51 ++++++++++++ .../index.js | 53 ++++++++++++ .../index.test.js | 10 +++ app/core/DeeplinkManager.js | 7 +- app/core/WalletConnect.js | 16 ++-- locales/en.json | 4 + locales/es.json | 4 + 12 files changed, 294 insertions(+), 17 deletions(-) create mode 100644 app/components/UI/BlockingActionModal/__snapshots__/index.test.js.snap create mode 100644 app/components/UI/BlockingActionModal/index.js create mode 100644 app/components/UI/BlockingActionModal/index.test.js create mode 100644 app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap create mode 100644 app/components/UI/WalletConnectReturnToBrowserModal/index.js create mode 100644 app/components/UI/WalletConnectReturnToBrowserModal/index.test.js diff --git a/android/app/build.gradle b/android/app/build.gradle index 6f1a63b67a2..f8cdab0b8f6 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -274,7 +274,8 @@ dependencies { implementation "com.facebook.react:react-native:+" // From node_modules implementation project(':react-native-branch') - implementation "io.branch.sdk.android:library:3.0.4" + implementation "io.branch.sdk.android:library:4.1.2" + implementation project(':react-native-camera') implementation project(':react-native-share') diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js index be84cf05058..45ebca5b649 100644 --- a/app/components/Nav/Main/index.js +++ b/app/components/Nav/Main/index.js @@ -87,6 +87,7 @@ import contractMap from 'eth-contract-metadata'; import { BN } from 'gaba'; import { BNToHex } from 'gaba/util'; import MessageSign from '../../UI/MessageSign'; +import WalletConnectReturnToBrowserModal from '../../UI/WalletConnectReturnToBrowserModal'; const styles = StyleSheet.create({ flex: { @@ -384,6 +385,7 @@ class Main extends PureComponent { signType: '', walletConnectRequest: false, walletConnectRequestInfo: {}, + walletConnectReturnModalVisible: false, paymentChannelRequest: false, paymentChannelRequestLoading: false, paymentChannelRequestCompleted: false, @@ -498,6 +500,9 @@ class Main extends PureComponent { WalletConnect.hub.on('walletconnectSessionRequest', peerInfo => { this.setState({ walletConnectRequest: true, walletConnectRequestInfo: peerInfo }); }); + WalletConnect.hub.on('walletconnect:return', () => { + this.setState({ walletConnectReturnModalVisible: true }); + }); WalletConnect.init(); }; @@ -739,6 +744,7 @@ class Main extends PureComponent { // If the app is now in background, we need to start // the background timer, which is less intense if (this.backgroundMode) { + this.setState({ walletConnectReturnModalVisible: false }); BackgroundTimer.runBackgroundTimer(async () => { await Engine.refreshTransactionHistory(); }, AppConstants.TX_CHECK_BACKGROUND_FREQUENCY); @@ -902,6 +908,10 @@ class Main extends PureComponent { ); }; + renderWalletConnectReturnModal = () => ( + + ); + renderPaymentChannelRequestApproval = () => { const { paymentChannelRequest, @@ -952,6 +962,7 @@ class Main extends PureComponent { {this.renderSigningModal()} {this.renderWalletConnectSessionRequestModal()} {this.renderPaymentChannelRequestApproval()} + {this.renderWalletConnectReturnModal()} ); } diff --git a/app/components/UI/BlockingActionModal/__snapshots__/index.test.js.snap b/app/components/UI/BlockingActionModal/__snapshots__/index.test.js.snap new file mode 100644 index 00000000000..877a1a1b324 --- /dev/null +++ b/app/components/UI/BlockingActionModal/__snapshots__/index.test.js.snap @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`BlockingActionModal should render correctly 1`] = ` + + + + + Please wait + + + + + +`; diff --git a/app/components/UI/BlockingActionModal/index.js b/app/components/UI/BlockingActionModal/index.js new file mode 100644 index 00000000000..eafdc7ae3dc --- /dev/null +++ b/app/components/UI/BlockingActionModal/index.js @@ -0,0 +1,56 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { ActivityIndicator, StyleSheet, View } from 'react-native'; +import Modal from 'react-native-modal'; +import { colors, baseStyles } from '../../../styles/common'; + +const styles = StyleSheet.create({ + modal: { + margin: 0, + width: '100%' + }, + modalView: { + justifyContent: 'center', + alignItems: 'center', + alignSelf: 'center', + backgroundColor: colors.white, + width: '90%', + borderRadius: 6, + minHeight: 200, + padding: 15 + }, + loader: { + marginTop: 30 + } +}); + +/** + * View that renders an action modal + */ +export default function BlockingActionModal({ children, modalVisible, isLoadingAction }) { + return ( + + + + {children} + {isLoadingAction && } + + + + ); +} + +BlockingActionModal.propTypes = { + /** + * Whether modal is shown + */ + modalVisible: PropTypes.bool, + /** + * Whether a spinner is shown + */ + isLoadingAction: PropTypes.bool, + /** + * Content to display above the action buttons + */ + children: PropTypes.node +}; diff --git a/app/components/UI/BlockingActionModal/index.test.js b/app/components/UI/BlockingActionModal/index.test.js new file mode 100644 index 00000000000..65049b24175 --- /dev/null +++ b/app/components/UI/BlockingActionModal/index.test.js @@ -0,0 +1,15 @@ +import React from 'react'; +import { Text } from 'react-native'; +import { shallow } from 'enzyme'; +import BlockingActionModal from './'; + +describe('BlockingActionModal', () => { + it('should render correctly', () => { + const wrapper = shallow( + + Please wait + + ); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap b/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap new file mode 100644 index 00000000000..de76353c1a7 --- /dev/null +++ b/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`WalletConnectReturnToBrowserModal should render correctly 1`] = ` + + + You're all set! + + + [missing "en.walletconnect_return_modal.text" translation] + + + +`; diff --git a/app/components/UI/WalletConnectReturnToBrowserModal/index.js b/app/components/UI/WalletConnectReturnToBrowserModal/index.js new file mode 100644 index 00000000000..4c8ba072f6d --- /dev/null +++ b/app/components/UI/WalletConnectReturnToBrowserModal/index.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { StyleSheet, Text } from 'react-native'; +import Icon from 'react-native-vector-icons/Ionicons'; +import { fontStyles, colors } from '../../../styles/common'; +import { strings } from '../../../../locales/i18n'; + +const styles = StyleSheet.create({ + blockingModalText: { + alignSelf: 'center', + borderRadius: 10, + fontSize: 16, + textAlign: 'center', + color: colors.fontSecondary, + ...fontStyles.normal + }, + blockingModalTitle: { + color: colors.fontPrimary, + fontSize: 22, + marginBottom: 15, + textAlign: 'center', + ...fontStyles.bold + }, + returnIcon: { + marginTop: 15, + textAlign: 'center', + color: colors.fontSecondary, + fontSize: 60, + lineHeight: 60 + } +}); + +/** + * View that renders an action modal + */ +export default function BlockingActionModal({ modalVisible }) { + return ( + + + {strings('walletconnect_return_modal.title')} + {strings('walletconnect_return_modal.text')} + + + + ); +} + +BlockingActionModal.propTypes = { + /** + * Whether modal is shown + */ + modalVisible: PropTypes.bool +}; diff --git a/app/components/UI/WalletConnectReturnToBrowserModal/index.test.js b/app/components/UI/WalletConnectReturnToBrowserModal/index.test.js new file mode 100644 index 00000000000..0e6f5eb2f0b --- /dev/null +++ b/app/components/UI/WalletConnectReturnToBrowserModal/index.test.js @@ -0,0 +1,10 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import WalletConnectReturnToBrowserModal from './'; + +describe('WalletConnectReturnToBrowserModal', () => { + it('should render correctly', () => { + const wrapper = shallow(); + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/app/core/DeeplinkManager.js b/app/core/DeeplinkManager.js index 54b5b8c5f8f..b6a05bafbe2 100644 --- a/app/core/DeeplinkManager.js +++ b/app/core/DeeplinkManager.js @@ -110,12 +110,7 @@ class DeeplinkManager { const redirect = params && params.redirect; // eslint-disable-next-line no-case-declarations const autosign = params && params.autosign; - - if (urlObj.hostname === 'sign' || urlObj.hostname === 'send') { - WalletConnect.setRedirectUri(redirect); - } else { - WalletConnect.newSession(url, redirect, autosign); - } + WalletConnect.newSession(url, redirect, autosign); break; case 'ethereum': this.handleEthereumUrl(url); diff --git a/app/core/WalletConnect.js b/app/core/WalletConnect.js index 0a216fc7df9..85c35e3a000 100644 --- a/app/core/WalletConnect.js +++ b/app/core/WalletConnect.js @@ -1,6 +1,5 @@ import RNWalletConnect from '@walletconnect/react-native'; import Engine from './Engine'; -import { Linking } from 'react-native'; import Logger from '../util/Logger'; // eslint-disable-next-line import/no-nodejs-modules import { EventEmitter } from 'events'; @@ -8,7 +7,6 @@ import AsyncStorage from '@react-native-community/async-storage'; const hub = new EventEmitter(); let connectors = []; -let pendingRedirect = null; const CLIENT_OPTIONS = { clientMeta: { @@ -37,7 +35,7 @@ class WalletConnect { constructor(options) { if (options.redirect) { - pendingRedirect = options.redirect; + this.redirectUrl = options.redirect; } if (options.autosign) { @@ -207,6 +205,7 @@ class WalletConnect { }); } } + this.redirectIfNeeded(); } }); @@ -290,11 +289,11 @@ class WalletConnect { }); redirectIfNeeded = () => { - if (pendingRedirect) { + console.log('redirect if needed', this.redirectUrl); + if (this.redirectUrl) { setTimeout(() => { - Linking.openURL(pendingRedirect); - pendingRedirect = null; - }, 500); + hub.emit('walletconnect:return'); + }, 1500); } }; } @@ -353,9 +352,6 @@ const instance = { shutdown() { Engine.context.TransactionController.hub.removeAllListeners(); Engine.context.PreferencesController.unsubscribe(); - }, - setRedirectUri: uri => { - pendingRedirect = uri; } }; diff --git a/locales/en.json b/locales/en.json index f097eff8c3f..03b735f3c67 100644 --- a/locales/en.json +++ b/locales/en.json @@ -986,5 +986,9 @@ "amount_error_message": "The amount must be a number", "address_error_message": "The address is invalid", "balance_error_message": "Insufficient balance" + }, + "walletconnect_return_modal": { + "title": "You're all set!", + "text:": "You can now return to your browser" } } diff --git a/locales/es.json b/locales/es.json index 5a5a34d8518..0d9c15c4837 100644 --- a/locales/es.json +++ b/locales/es.json @@ -966,5 +966,9 @@ "amount_error_message": "El monto debe ser un número", "address_error_message": "La dirección no es válida", "balance_error_message": "Balance insuficiente" + }, + "walletconnect_return_modal": { + "title": "Listo!", + "text:": "Ahora puedes volver a tu navegador" } } From a1daae50abf602339335bbf9fc3a801e2a27aa7b Mon Sep 17 00:00:00 2001 From: Bruno Barbieri Date: Fri, 8 Nov 2019 13:21:15 -0500 Subject: [PATCH 2/3] fix --- .../__snapshots__/index.test.js.snap | 2 +- app/components/UI/WalletConnectReturnToBrowserModal/index.js | 5 +++-- locales/en.json | 2 +- locales/es.json | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap b/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap index de76353c1a7..49238492ef0 100644 --- a/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap +++ b/app/components/UI/WalletConnectReturnToBrowserModal/__snapshots__/index.test.js.snap @@ -31,7 +31,7 @@ exports[`WalletConnectReturnToBrowserModal should render correctly 1`] = ` } } > - [missing "en.walletconnect_return_modal.text" translation] + You can now return to your browser @@ -45,7 +46,7 @@ export default function BlockingActionModal({ modalVisible }) { ); } -BlockingActionModal.propTypes = { +WalletConnectReturnToBrowserModal.propTypes = { /** * Whether modal is shown */ diff --git a/locales/en.json b/locales/en.json index 03b735f3c67..508e2e269fd 100644 --- a/locales/en.json +++ b/locales/en.json @@ -989,6 +989,6 @@ }, "walletconnect_return_modal": { "title": "You're all set!", - "text:": "You can now return to your browser" + "text": "You can now return to your browser" } } diff --git a/locales/es.json b/locales/es.json index 0d9c15c4837..8b35ecfddd6 100644 --- a/locales/es.json +++ b/locales/es.json @@ -969,6 +969,6 @@ }, "walletconnect_return_modal": { "title": "Listo!", - "text:": "Ahora puedes volver a tu navegador" + "text": "Ahora puedes volver a tu navegador" } } From a86555eaf28cfdd1e8ebb5aa5d203b900731934e Mon Sep 17 00:00:00 2001 From: Bruno Barbieri Date: Fri, 8 Nov 2019 13:46:20 -0500 Subject: [PATCH 3/3] Update WalletConnect.js --- app/core/WalletConnect.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/core/WalletConnect.js b/app/core/WalletConnect.js index 85c35e3a000..36b0c4d200a 100644 --- a/app/core/WalletConnect.js +++ b/app/core/WalletConnect.js @@ -289,7 +289,6 @@ class WalletConnect { }); redirectIfNeeded = () => { - console.log('redirect if needed', this.redirectUrl); if (this.redirectUrl) { setTimeout(() => { hub.emit('walletconnect:return');