mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-20 14:05:27 +01:00
FIX: Create button was difficult to press on android. (#369)
FIX: Create button was difficult to press on android. ADD: Clipboard detection on app state change to foreground OPS: Upgrade to RN 58.6 due to various important fixes FIX: Statusbar restored
This commit is contained in:
parent
a1bf0f8276
commit
6017f4d990
6 changed files with 169 additions and 58 deletions
137
App.js
137
App.js
|
@ -1,22 +1,76 @@
|
|||
import React from 'react';
|
||||
import { Linking } from 'react-native';
|
||||
import { Linking, AppState, Clipboard, StyleSheet, KeyboardAvoidingView, Platform, View } from 'react-native';
|
||||
import Modal from 'react-native-modal';
|
||||
import { NavigationActions } from 'react-navigation';
|
||||
import MainBottomTabs from './MainBottomTabs';
|
||||
import NavigationService from './NavigationService';
|
||||
import { BlueTextCentered, BlueButton } from './BlueComponents';
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const bitcoinModalString = 'Bitcoin address';
|
||||
const lightningModalString = 'Lightning Invoice';
|
||||
let loc = require('./loc');
|
||||
|
||||
export default class App extends React.Component {
|
||||
navigator = null;
|
||||
|
||||
state = {
|
||||
appState: AppState.currentState,
|
||||
isClipboardContentModalVisible: false,
|
||||
clipboardContentModalAddressType: bitcoinModalString,
|
||||
clipboardContent: '',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
Linking.getInitialURL()
|
||||
.then(url => this.handleOpenURL({ url }))
|
||||
.catch(console.error);
|
||||
|
||||
Linking.addEventListener('url', this.handleOpenURL);
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Linking.removeEventListener('url', this.handleOpenURL);
|
||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
_handleAppStateChange = async nextAppState => {
|
||||
if (this.state.appState.match(/inactive|background/) && nextAppState === 'active') {
|
||||
const clipboard = await Clipboard.getString();
|
||||
if (this.state.clipboardContent !== clipboard && (this.isBitcoinAddress(clipboard) || this.isLightningInvoice(clipboard))) {
|
||||
this.setState({ isClipboardContentModalVisible: true });
|
||||
}
|
||||
|
||||
this.setState({ clipboardContent: clipboard });
|
||||
}
|
||||
this.setState({ appState: nextAppState });
|
||||
};
|
||||
|
||||
isBitcoinAddress(address) {
|
||||
let isValidBitcoinAddress = false;
|
||||
try {
|
||||
bitcoin.address.toOutputScript(address);
|
||||
isValidBitcoinAddress = true;
|
||||
this.setState({ clipboardContentModalAddressType: bitcoinModalString });
|
||||
} catch (err) {
|
||||
isValidBitcoinAddress = false;
|
||||
}
|
||||
if (!isValidBitcoinAddress) {
|
||||
if (address.indexOf('bitcoin:') === 0 || address.indexOf('BITCOIN:') === 0) {
|
||||
isValidBitcoinAddress = true;
|
||||
this.setState({ clipboardContentModalAddressType: bitcoinModalString });
|
||||
}
|
||||
}
|
||||
return isValidBitcoinAddress;
|
||||
}
|
||||
|
||||
isLightningInvoice(invoice) {
|
||||
let isValidLightningInvoice = false;
|
||||
if (invoice.indexOf('lightning:lnb') === 0 || invoice.indexOf('LIGHTNING:lnb') === 0 || invoice.toLowerCase().startsWith('lnb')) {
|
||||
this.setState({ clipboardContentModalAddressType: lightningModalString });
|
||||
isValidLightningInvoice = true;
|
||||
}
|
||||
return isValidLightningInvoice;
|
||||
}
|
||||
|
||||
handleOpenURL = event => {
|
||||
|
@ -26,7 +80,7 @@ export default class App extends React.Component {
|
|||
if (typeof event.url !== 'string') {
|
||||
return;
|
||||
}
|
||||
if (event.url.indexOf('bitcoin:') === 0 || event.url.indexOf('BITCOIN:') === 0) {
|
||||
if (this.isBitcoinAddress(event.url)) {
|
||||
this.navigator &&
|
||||
this.navigator.dispatch(
|
||||
NavigationActions.navigate({
|
||||
|
@ -36,7 +90,7 @@ export default class App extends React.Component {
|
|||
},
|
||||
}),
|
||||
);
|
||||
} else if (event.url.indexOf('lightning:') === 0 || event.url.indexOf('LIGHTNING:') === 0) {
|
||||
} else if (this.isLightningInvoice(event.url)) {
|
||||
this.navigator &&
|
||||
this.navigator.dispatch(
|
||||
NavigationActions.navigate({
|
||||
|
@ -49,14 +103,79 @@ export default class App extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
renderClipboardContentModal = () => {
|
||||
return (
|
||||
<Modal
|
||||
isVisible={this.state.isClipboardContentModalVisible}
|
||||
style={styles.bottomModal}
|
||||
onBackdropPress={() => {
|
||||
this.setState({ isClipboardContentModalVisible: false });
|
||||
}}
|
||||
>
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
|
||||
<View style={styles.modalContent}>
|
||||
<BlueTextCentered>
|
||||
You have a {this.state.clipboardContentModalAddressType} on your clipboard. Would you like to use it for a transaction?
|
||||
</BlueTextCentered>
|
||||
<View style={styles.modelContentButtonLayout}>
|
||||
<BlueButton
|
||||
noMinWidth
|
||||
title={loc.send.details.cancel}
|
||||
onPress={() => this.setState({ isClipboardContentModalVisible: false })}
|
||||
/>
|
||||
<View style={{ marginHorizontal: 8 }} />
|
||||
<BlueButton
|
||||
noMinWidth
|
||||
title="OK"
|
||||
onPress={() => {
|
||||
this.setState({ isClipboardContentModalVisible: false }, async () => {
|
||||
const clipboard = await Clipboard.getString();
|
||||
setTimeout(() => this.handleOpenURL({ url: clipboard }), 100);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MainBottomTabs
|
||||
ref={nav => {
|
||||
this.navigator = nav;
|
||||
NavigationService.setTopLevelNavigator(nav);
|
||||
}}
|
||||
/>
|
||||
<View style={{ flex: 1 }}>
|
||||
<MainBottomTabs
|
||||
ref={nav => {
|
||||
this.navigator = nav;
|
||||
NavigationService.setTopLevelNavigator(nav);
|
||||
}}
|
||||
/>
|
||||
{this.renderClipboardContentModal()}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
modalContent: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
padding: 22,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderTopLeftRadius: 16,
|
||||
borderTopRightRadius: 16,
|
||||
borderColor: 'rgba(0, 0, 0, 0.1)',
|
||||
minHeight: 200,
|
||||
height: 200,
|
||||
},
|
||||
bottomModal: {
|
||||
justifyContent: 'flex-end',
|
||||
margin: 0,
|
||||
},
|
||||
modelContentButtonLayout: {
|
||||
flexDirection: 'row',
|
||||
margin: 16,
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -51,6 +51,10 @@ export class BlueButton extends Component {
|
|||
backgroundColor = '#eef0f4';
|
||||
fontColor = '#9aa0aa';
|
||||
}
|
||||
let buttonWidth = width / 1.5;
|
||||
if (this.props.hasOwnProperty('noMinWidth')) {
|
||||
buttonWidth = 0;
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
|
@ -62,7 +66,7 @@ export class BlueButton extends Component {
|
|||
height: 45,
|
||||
maxHeight: 45,
|
||||
borderRadius: 25,
|
||||
minWidth: width / 1.5,
|
||||
minWidth: buttonWidth,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
|
|
|
@ -8,6 +8,6 @@ export default class Privacy {
|
|||
}
|
||||
|
||||
static disableBlur() {
|
||||
Platform.OS === 'android' ? Obscure.disableBlur() : PrivacySnapshot.enabled(false);
|
||||
Platform.OS === 'android' ? Obscure.deactivateObscure() : PrivacySnapshot.enabled(false);
|
||||
}
|
||||
}
|
||||
|
|
64
package-lock.json
generated
64
package-lock.json
generated
|
@ -2624,11 +2624,11 @@
|
|||
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
|
||||
},
|
||||
"compressible": {
|
||||
"version": "2.0.15",
|
||||
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz",
|
||||
"integrity": "sha512-4aE67DL33dSW9gw4CI2H/yTxqHLNcxp0yS6jB+4h+wr3e43+1z7vm0HU9qXOH8j+qjKuL8+UtkOxYQSMq60Ylw==",
|
||||
"version": "2.0.16",
|
||||
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.16.tgz",
|
||||
"integrity": "sha512-JQfEOdnI7dASwCuSPWIeVYwc/zMsu/+tRhoUvEfXz2gxOA2DNjmG5vhtFdBlhWPPGo+RdT9S3tgc/uH5qgDiiA==",
|
||||
"requires": {
|
||||
"mime-db": ">= 1.36.0 < 2"
|
||||
"mime-db": ">= 1.38.0 < 2"
|
||||
}
|
||||
},
|
||||
"compression": {
|
||||
|
@ -2769,13 +2769,14 @@
|
|||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "5.0.7",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz",
|
||||
"integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.1.0.tgz",
|
||||
"integrity": "sha512-kCNPvthka8gvLtzAxQXvWo4FxqRB+ftRZyPZNuab5ngvM9Y7yw7hbEysglptLgpkGX9nAOKTBVkHUAe8xtYR6Q==",
|
||||
"requires": {
|
||||
"import-fresh": "^2.0.0",
|
||||
"is-directory": "^0.3.1",
|
||||
"js-yaml": "^3.9.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"parse-json": "^4.0.0"
|
||||
}
|
||||
},
|
||||
|
@ -3944,9 +3945,9 @@
|
|||
"integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="
|
||||
},
|
||||
"fbjs-scripts": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fbjs-scripts/-/fbjs-scripts-1.0.1.tgz",
|
||||
"integrity": "sha512-x8bfX7k0z5B24Ue0YqjZq/2QxxaKZUNbkGdX//zbQDElMJFqBRrvRi8O3qds7UNNzs78jYqIYCS32Sk/wu5UJg==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fbjs-scripts/-/fbjs-scripts-1.1.0.tgz",
|
||||
"integrity": "sha512-VMCpHJd76YI2nYOfVM/d9LDAIFTH4uw4/7sAIGEgxk6kaNmirgTY9bLgpla9DTu+DvV2+ufvDxehGbl2U9bYCA==",
|
||||
"requires": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"ansi-colors": "^1.0.1",
|
||||
|
@ -8212,6 +8213,11 @@
|
|||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||
},
|
||||
"lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
|
||||
},
|
||||
"lodash.isempty": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
|
||||
|
@ -8867,22 +8873,6 @@
|
|||
"metro-cache": "0.49.2",
|
||||
"metro-core": "0.49.2",
|
||||
"pretty-format": "24.0.0-alpha.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz",
|
||||
"integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w=="
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "24.0.0-alpha.6",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz",
|
||||
"integrity": "sha512-zG2m6YJeuzwBFqb5EIdmwYVf30sap+iMRuYNPytOccEXZMAJbPIFGKVJ/U0WjQegmnQbRo9CI7j6j3HtDaifiA==",
|
||||
"requires": {
|
||||
"ansi-regex": "^4.0.0",
|
||||
"ansi-styles": "^3.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"metro-core": {
|
||||
|
@ -9569,9 +9559,9 @@
|
|||
}
|
||||
},
|
||||
"on-headers": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
|
||||
"integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
|
@ -10778,9 +10768,9 @@
|
|||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "24.0.0-alpha.4",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.0.0-alpha.4.tgz",
|
||||
"integrity": "sha512-icvbBt3XlLEVqPHdHwR2Ou9+hezS9Eccd+mA+fXfOU7T9t7ClOpq2HgCwlyw+3WogccCubKWnmzyrA/3ZZ/aOA==",
|
||||
"version": "24.0.0-alpha.6",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.0.0-alpha.6.tgz",
|
||||
"integrity": "sha512-zG2m6YJeuzwBFqb5EIdmwYVf30sap+iMRuYNPytOccEXZMAJbPIFGKVJ/U0WjQegmnQbRo9CI7j6j3HtDaifiA==",
|
||||
"requires": {
|
||||
"ansi-regex": "^4.0.0",
|
||||
"ansi-styles": "^3.2.0"
|
||||
|
@ -11087,9 +11077,9 @@
|
|||
}
|
||||
},
|
||||
"react-native": {
|
||||
"version": "0.58.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.58.1.tgz",
|
||||
"integrity": "sha512-8aD0PBTney5dKQ4MBOfBEcHmdm2OBCx/9gSbeT4OUXE54fNNmDfbkVnx7EZ1iwvEdOiAl+pEpWqgAb/tvhRwBA==",
|
||||
"version": "0.58.6",
|
||||
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.58.6.tgz",
|
||||
"integrity": "sha512-m/7L0gYXS4yHjs+PKmyurh1LLr7/tpobAX8Iv7Dwu4XT1ZcZFeCATn420E9U3nC2XsT54AmRR2Fv7VGgf+M2vQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"absolute-path": "^0.0.0",
|
||||
|
@ -11129,11 +11119,11 @@
|
|||
"opn": "^3.0.2",
|
||||
"optimist": "^0.6.1",
|
||||
"plist": "^3.0.0",
|
||||
"pretty-format": "24.0.0-alpha.4",
|
||||
"pretty-format": "24.0.0-alpha.6",
|
||||
"promise": "^7.1.1",
|
||||
"prop-types": "^15.5.8",
|
||||
"react-clone-referenced-element": "^1.0.1",
|
||||
"react-devtools-core": "^3.4.0",
|
||||
"react-devtools-core": "^3.4.2",
|
||||
"regenerator-runtime": "^0.11.0",
|
||||
"rimraf": "^2.5.4",
|
||||
"semver": "^5.0.3",
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
"prop-types": "15.6.2",
|
||||
"react": "16.7.0",
|
||||
"react-localization": "1.0.10",
|
||||
"react-native": "0.58.1",
|
||||
"react-native": "0.58.6",
|
||||
"react-native-camera": "1.10.0",
|
||||
"react-native-device-info": "0.26.1",
|
||||
"react-native-elements": "0.19.0",
|
||||
|
|
|
@ -198,11 +198,11 @@ export default class SendDetails extends Component {
|
|||
};
|
||||
|
||||
decodeBitcoinUri(uri) {
|
||||
let amount = '';
|
||||
let parsedBitcoinUri = null;
|
||||
let address = uri || '';
|
||||
let memo = '';
|
||||
try {
|
||||
let amount = '';
|
||||
let parsedBitcoinUri = null;
|
||||
let address = '';
|
||||
let memo = '';
|
||||
parsedBitcoinUri = bip21.decode(uri);
|
||||
address = parsedBitcoinUri.hasOwnProperty('address') ? parsedBitcoinUri.address : address;
|
||||
if (parsedBitcoinUri.hasOwnProperty('options')) {
|
||||
|
@ -213,10 +213,8 @@ export default class SendDetails extends Component {
|
|||
memo = parsedBitcoinUri.options.label || memo;
|
||||
}
|
||||
}
|
||||
return { address, amount, memo };
|
||||
} catch (_) {
|
||||
return undefined;
|
||||
}
|
||||
} catch (_) {}
|
||||
return { address, amount, memo };
|
||||
}
|
||||
|
||||
recalculateAvailableBalance(balance, amount, fee) {
|
||||
|
@ -521,7 +519,7 @@ export default class SendDetails extends Component {
|
|||
|
||||
renderCreateButton = () => {
|
||||
return (
|
||||
<View style={{ paddingHorizontal: 56, paddingVertical: 16, alignContent: 'center', backgroundColor: '#FFFFFF' }}>
|
||||
<View style={{ marginHorizontal: 56, marginVertical: 16, alignContent: 'center', backgroundColor: '#FFFFFF', minHeight: 44 }}>
|
||||
{this.state.isLoading ? (
|
||||
<ActivityIndicator />
|
||||
) : (
|
||||
|
|
Loading…
Add table
Reference in a new issue