Merge branch 'master' into viewinvoicehooks

This commit is contained in:
marcosrdz 2020-11-24 21:07:19 -05:00
commit 07500682f9
9 changed files with 66 additions and 77 deletions

View file

@ -236,6 +236,7 @@ export class BlueWalletNavigationHeader extends Component {
}
static contextType = BlueStorageContext;
walletBalanceText = React.createRef();
constructor(props) {
super(props);
@ -276,7 +277,7 @@ export class BlueWalletNavigationHeader extends Component {
};
showAndroidTooltip = () => {
showPopupMenu(this.toolTipMenuOptions(), this.handleToolTipSelection, this.walletBalanceText);
showPopupMenu(this.toolTipMenuOptions(), this.handleToolTipSelection, this.walletBalanceText.current);
};
handleToolTipSelection = item => {
@ -314,7 +315,7 @@ export class BlueWalletNavigationHeader extends Component {
});
}
changeWalletBalanceUnit() {
changeWalletBalanceUnit = () => {
let walletPreviousPreferredUnit = this.state.wallet.getPreferredBalanceUnit();
const wallet = this.state.wallet;
if (walletPreviousPreferredUnit === BitcoinUnit.BTC) {
@ -334,7 +335,7 @@ export class BlueWalletNavigationHeader extends Component {
this.setState({ wallet, walletPreviousPreferredUnit: walletPreviousPreferredUnit }, () => {
this.props.onWalletUnitChange(wallet);
});
}
};
manageFundsPressed = () => {
this.props.onManageFundsPressed();
@ -402,8 +403,8 @@ export class BlueWalletNavigationHeader extends Component {
)}
<TouchableOpacity
style={styles.balance}
onPress={() => this.changeWalletBalanceUnit()}
ref={ref => (this.walletBalanceText = ref)}
onPress={this.changeWalletBalanceUnit}
ref={this.walletBalanceText}
onLongPress={() => (Platform.OS === 'ios' ? this.tooltip.showMenu() : this.showAndroidTooltip())}
>
{this.state.wallet.hideBalance ? (
@ -572,7 +573,7 @@ export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuB
headerTintColor: BlueCurrentTheme.colors.foregroundColor,
headerLeft: () => (
<TouchableOpacity
style={{ minWwidth: 40, height: 40, justifyContent: 'center', paddingHorizontal: 14 }}
style={{ minWidth: 40, height: 40, justifyContent: 'center', paddingHorizontal: 14 }}
onPress={() => {
Keyboard.dismiss();
navigation.goBack(null);
@ -589,13 +590,13 @@ export const BlueCreateTxNavigationStyle = (navigation, withAdvancedOptionsMenuB
export const BluePrivateBalance = () => {
return Platform.select({
ios: (
<View style={{ flexDirection: 'row' }}>
<View style={{ flexDirection: 'row', marginTop: 13 }}>
<BlurView style={styles.balanceBlur} blurType="light" blurAmount={25} />
<Icon name="eye-slash" type="font-awesome" color="#FFFFFF" />
</View>
),
android: (
<View style={{ flexDirection: 'row' }}>
<View style={{ flexDirection: 'row', marginTop: 13 }}>
<View style={{ backgroundColor: '#FFFFFF', opacity: 0.5, height: 30, width: 100, marginRight: 8 }} />
<Icon name="eye-slash" type="font-awesome" color="#FFFFFF" />
</View>

View file

@ -1,21 +1,19 @@
/* global alert */
import { PermissionsAndroid, Platform } from 'react-native';
import { Alert, Linking, PermissionsAndroid, Platform } from 'react-native';
import RNFS from 'react-native-fs';
import Share from 'react-native-share';
import loc from '../loc';
import { getSystemName } from 'react-native-device-info';
import DocumentPicker from 'react-native-document-picker';
import isCatalyst from 'react-native-is-catalyst';
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const isDesktop = getSystemName() === 'Mac OS X';
const writeFileAndExport = async function (filename, contents) {
if (Platform.OS === 'ios') {
const filePath = RNFS.TemporaryDirectoryPath + `/${filename}`;
await RNFS.writeFile(filePath, contents);
Share.open({
url: 'file://' + filePath,
saveToFiles: isDesktop,
saveToFiles: isCatalyst,
})
.catch(error => {
console.log(error);
@ -39,6 +37,16 @@ const writeFileAndExport = async function (filename, contents) {
alert(loc.formatString(loc._.file_saved, { filePath: filename }));
} else {
console.log('Storage Permission: Denied');
Alert.alert(loc.send.permission_storage_title, loc.send.permission_storage_denied_message, [
{
text: loc.send.open_settings,
onPress: () => {
Linking.openSettings();
},
style: 'default',
},
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
]);
}
}
};

View file

@ -208,8 +208,9 @@
"permission_camera_title": "Permission to use camera",
"open_settings": "Open Settings",
"permission_storage_later": "Ask Me Later",
"permission_storage_message": "BlueWallet needs your permission to access your storage to save this transaction.",
"permission_storage_title": "BlueWallet Storage Access Permission",
"permission_storage_message": "BlueWallet needs your permission to access your storage to save this file.",
"permission_storage_denied_message": "BlueWallet is unable save this file. Please, open your device settings and enable Storage Permission.",
"permission_storage_title": "Storage Access Permission",
"psbt_clipboard": "Copy to Clipboard",
"psbt_this_is_psbt": "This is a partially signed bitcoin transaction (PSBT). Please finish signing it with your hardware wallet.",
"psbt_tx_export": "Export to file",

View file

@ -14,6 +14,7 @@ import {
View,
Platform,
PermissionsAndroid,
Alert,
} from 'react-native';
import Clipboard from '@react-native-community/clipboard';
import { Icon } from 'react-native-elements';
@ -25,9 +26,8 @@ import Privacy from '../../Privacy';
import { BitcoinUnit } from '../../models/bitcoinUnits';
import loc from '../../loc';
import { BlueCurrentTheme } from '../../components/themes';
import { getSystemName } from 'react-native-device-info';
import isCatalyst from 'react-native-is-catalyst';
const currency = require('../../blue_modules/currency');
const isDesktop = getSystemName() === 'Mac OS X';
export default class SendCreate extends Component {
constructor(props) {
@ -59,7 +59,7 @@ export default class SendCreate extends Component {
await RNFS.writeFile(filePath, this.state.tx);
Share.open({
url: 'file://' + filePath,
saveToFiles: isDesktop,
saveToFiles: isCatalyst,
})
.catch(error => {
console.log(error);
@ -84,6 +84,16 @@ export default class SendCreate extends Component {
alert(loc.formatString(loc.send.txSaved, { filePath }));
} else {
console.log('Storage Permission: Denied');
Alert.alert(loc.send.permission_storage_title, loc.send.permission_storage_denied_message, [
{
text: loc.send.open_settings,
onPress: () => {
Linking.openSettings();
},
style: 'default',
},
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
]);
}
}
};

View file

@ -222,7 +222,7 @@ export default class SendDetails extends Component {
let fromWallet = null;
if (props.route.params) fromWallet = props.route.params.fromWallet;
const wallets = context.wallets.filter(wallet => wallet.type !== LightningCustodianWallet.type);
const wallets = context.wallets.filter(wallet => wallet.type !== LightningCustodianWallet.type && wallet.allowSend());
if (wallets.length === 0) {
alert(loc.send.details_wallet_before_tx);
@ -330,6 +330,7 @@ export default class SendDetails extends Component {
async componentDidMount() {
console.log('send/details - componentDidMount');
if (!this.state.fromWallet) return;
this.renderNavigationHeader();
this.context.setSelectedWallet(this.state.fromWallet.getID());
/** @type {BitcoinTransaction[]} */

View file

@ -11,6 +11,7 @@ import {
PermissionsAndroid,
Text,
StyleSheet,
Alert,
} from 'react-native';
import ImagePicker from 'react-native-image-picker';
import Clipboard from '@react-native-community/clipboard';
@ -34,6 +35,7 @@ import ScanQRCode from './ScanQRCode';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import Notifications from '../../blue_modules/notifications';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import isCatalyst from 'react-native-is-catalyst';
const BlueElectrum = require('../../blue_modules/BlueElectrum');
/** @type {AppStorage} */
const bitcoin = require('bitcoinjs-lib');
@ -178,7 +180,7 @@ const PsbtWithHardwareWallet = () => {
await RNFS.writeFile(filePath, typeof psbt === 'string' ? psbt : psbt.toBase64());
Share.open({
url: 'file://' + filePath,
saveToFiles: isDesktop,
saveToFiles: isCatalyst,
})
.catch(error => {
console.log(error);
@ -202,6 +204,16 @@ const PsbtWithHardwareWallet = () => {
alert(loc.formatString(loc.send.txSaved, { filePath: fileName }));
} else {
console.log('Storage Permission: Denied');
Alert.alert(loc.send.permission_storage_title, loc.send.permission_storage_denied_message, [
{
text: loc.send.open_settings,
onPress: () => {
Linking.openSettings();
},
style: 'default',
},
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
]);
}
}
};

View file

@ -29,11 +29,10 @@ import loc from '../../loc';
import { useTheme, useRoute, useNavigation } from '@react-navigation/native';
import RNFS from 'react-native-fs';
import Share from 'react-native-share';
import { getSystemName } from 'react-native-device-info';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import Notifications from '../../blue_modules/notifications';
import isCatalyst from 'react-native-is-catalyst';
const prompt = require('../../blue_modules/prompt');
const isDesktop = getSystemName() === 'Mac OS X';
const styles = StyleSheet.create({
root: {
@ -258,7 +257,7 @@ const WalletDetails = () => {
await RNFS.writeFile(filePath, contents);
Share.open({
url: 'file://' + filePath,
saveToFiles: isDesktop,
saveToFiles: isCatalyst,
})
.catch(error => {
console.log(error);
@ -283,6 +282,16 @@ const WalletDetails = () => {
alert(loc.formatString(loc.send.txSaved, { filePath: fileName }));
} else {
console.log('Storage Permission: Denied');
Alert.alert(loc.send.permission_storage_title, loc.send.permission_storage_denied_message, [
{
text: loc.send.open_settings,
onPress: () => {
Linking.openSettings();
},
style: 'default',
},
{ text: loc._.cancel, onPress: () => {}, style: 'cancel' },
]);
}
}
};

View file

@ -421,7 +421,7 @@ const WalletTransactions = () => {
fromSecret: wallet.current.getSecret(),
// ScanLndInvoice actrually uses `fromSecret` so keeping it for now
uri: ret.data ? ret.data : ret,
fromWallet: wallet,
fromWallet: wallet.current,
};
if (wallet.current.chain === Chain.ONCHAIN) {
navigate('SendDetailsRoot', { screen: 'SendDetails', params });

View file

@ -471,59 +471,6 @@ describe('BlueWallet UI Tests', () => {
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
});
it('can import zpub as watch-only and create PSBT, and scan txhex back', async () => {
const lockFile = '/tmp/travislock.' + hashIt(jasmine.currentTest.fullName);
if (process.env.TRAVIS) {
if (require('fs').existsSync(lockFile))
return console.warn('skipping', JSON.stringify(jasmine.currentTest.fullName), 'as it previously passed on Travis');
}
await helperImportWallet(
'zpub6r7jhKKm7BAVx3b3nSnuadY1WnshZYkhK8gKFoRLwK9rF3Mzv28BrGcCGA3ugGtawi1WLb2vyjQAX9ZTDGU5gNk2bLdTc3iEXr6tzR1ipNP',
'Imported Watch-only',
'0.002 BTC',
);
await element(by.id('SendButton')).tap();
await element(by.text('OK')).tap();
await element(by.id('AddressInput')).replaceText('bc1q063ctu6jhe5k4v8ka99qac8rcm2tzjjnuktyrl');
await element(by.id('BitcoinAmountInput')).typeText('0.0005\n');
// setting fee rate:
const feeRate = 1;
await element(by.id('chooseFee')).tap();
await element(by.id('feeCustom')).tap();
await element(by.type('android.widget.EditText')).typeText(feeRate + '');
await element(by.text('OK')).tap();
if (process.env.TRAVIS) await sleep(5000);
try {
await element(by.id('CreateTransactionButton')).tap();
} catch (_) {}
await yo('TextHelperForPSBT');
// now lets test scanning back QR with txhex. this should lead straight to broadcast dialog
await element(by.id('PsbtWithHardwareScrollView')).swipe('up', 'fast', 1); // in case emu screen is small and it doesnt fit
await element(by.id('PsbtTxScanButton')).tap(); // opening camera
// tapping 10 times invisible button is a backdoor:
for (let c = 0; c <= 5; c++) {
await element(by.id('ScanQrBackdoorButton')).tap();
await sleep(1000);
}
const randomTxHex =
'020000000001011628f58e8e81bfcfff1b106bb8968e342fb86f09aa810ed2939e43d5127c51040200000000000000000227e42d000000000017a914c679a827d57a9b8b539515dbafb4e573d2bcc6ca87df15cf02000000002200209705cdfcbc459a220e7f39ffe547a31335505c2357f452ae12a22b9ae36ea59d04004730440220626c5205a6f49d1dd1577c85c0af4c5fc70f41de61f891d71a5cf57af09110d4022045bcb1e7d4e93e1a9baf6ae1ad0b4087c9e9f73ec366e97576912377d9f6904301473044022044aea98e8983f09cb0639f08d34526bb7e3ed47d208b7bf714fb29a1b5f9535a02200baa510b94cf434775b4aa2184682f2fb33f15e5e76f79aa0885e7ee12bdc8f70169522102e67ce679d617d674d68eea95ecb166c67b4b5520105c4745adf37ce8a40b92dc21029ff54b8bf26dbddd7bd4336593d2ff17519d5374989f36a6f5f8239675ff79a421039000ee2853c6db4bd956e80b1ecfb8711bf3e0a9a8886d15450c29458b60473153ae00000000';
await element(by.id('scanQrBackdoorInput')).replaceText(randomTxHex);
await element(by.id('scanQrBackdoorOkButton')).tap();
await expect(element(by.id('ScanQrBackdoorButton'))).toBeNotVisible();
await yo('PsbtWithHardwareWalletBroadcastTransactionButton');
process.env.TRAVIS && require('fs').writeFileSync(lockFile, '1');
});
/**
* test plan:
* 1. import wallet