Merge branch 'master' into confirmationslabel

This commit is contained in:
marcosrdz 2020-12-13 12:07:33 -05:00
commit c66017c500
8 changed files with 155 additions and 90 deletions

View File

@ -5,6 +5,8 @@ import Share from 'react-native-share';
import loc from '../loc';
import DocumentPicker from 'react-native-document-picker';
import isCatalyst from 'react-native-is-catalyst';
import { launchCamera, launchImageLibrary } from 'react-native-image-picker';
import { presentCameraNotAuthorizedAlert } from '../class/camera';
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const writeFileAndExport = async function (filename, contents) {
@ -92,6 +94,56 @@ const _readPsbtFileIntoBase64 = async function (uri) {
}
};
const showImagePickerAndReadImage = () => {
return new Promise((resolve, reject) =>
launchImageLibrary(
{
title: null,
mediaType: 'photo',
takePhotoButtonTitle: null,
},
response => {
if (response.uri) {
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
LocalQRCode.decode(uri, (error, result) => {
if (!error) {
resolve(result);
} else {
reject(new Error(loc.send.qr_error_no_qrcode));
}
});
}
},
),
);
};
const takePhotoWithImagePickerAndReadPhoto = () => {
return new Promise((resolve, reject) =>
launchCamera(
{
title: null,
mediaType: 'photo',
takePhotoButtonTitle: null,
},
response => {
if (response.uri) {
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
LocalQRCode.decode(uri, (error, result) => {
if (!error) {
resolve(result);
} else {
reject(new Error(loc.send.qr_error_no_qrcode));
}
});
} else if (response.error) {
presentCameraNotAuthorizedAlert(response.error);
}
},
),
);
};
const showFilePickerAndReadFile = async function () {
try {
const res = await DocumentPicker.pick({
@ -141,3 +193,5 @@ const showFilePickerAndReadFile = async function () {
module.exports.writeFileAndExport = writeFileAndExport;
module.exports.openSignedTransaction = openSignedTransaction;
module.exports.showFilePickerAndReadFile = showFilePickerAndReadFile;
module.exports.showImagePickerAndReadImage = showImagePickerAndReadImage;
module.exports.takePhotoWithImagePickerAndReadPhoto = takePhotoWithImagePickerAndReadPhoto;

View File

@ -277,6 +277,7 @@
"network_electrum": "Electrum Server",
"not_a_valid_uri": "Not a valid URI",
"notifications": "Notifications",
"open_link_in_explorer" : "Open link in explorer",
"password": "Password",
"password_explain": "Create the password you will use to decrypt the storage",
"passwords_do_not_match": "Passwords do not match",
@ -291,7 +292,8 @@
"push_notifications": "Push Notifications",
"retype_password": "Re-type password",
"save": "Save",
"saved": "Saved"
"saved": "Saved",
"success_transaction_broadcasted" : "Success! You transaction has been broadcasted!"
},
"notifications": {
"would_you_like_to_receive_notifications": "Would you like to receive notifications when you get incoming payments?",

View File

@ -277,6 +277,7 @@
"network_electrum": "سرور الکترام",
"not_a_valid_uri": "یوآرآی معتبر نیست",
"notifications": "اعلانات",
"open_link_in_explorer" : "بازکردن پیوند در مرورگر",
"password": "گذرواژه",
"password_explain": "گذرواژه‌ای را که برای رمزگشایی فضای ذخیره‌سازی استفاده خواهید کرد ایجاد کنید",
"passwords_do_not_match": "گذرواژه‌ها مطابقت ندارند",
@ -291,7 +292,8 @@
"push_notifications": "پوش نوتیفیکیشن",
"retype_password": "گذرواژه را دوباره بنویسید",
"save": "ذخیره",
"saved": "ذخیره شد"
"saved": "ذخیره شد",
"success_transaction_broadcasted" : "موفقیت‌آمیز بود! تراکنش شما منتشر شد."
},
"notifications": {
"would_you_like_to_receive_notifications": "آیا می‌خواهید هنگام دریافت وجه اعلان دریافت کنید؟",

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { ActivityIndicator, Linking, StyleSheet, View, KeyboardAvoidingView, Platform, Text, TextInput } from 'react-native';
import { ActivityIndicator, Linking, StyleSheet, View, KeyboardAvoidingView, Platform, TextInput } from 'react-native';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import loc from '../../loc';
import { HDSegwitBech32Wallet } from '../../class';
@ -14,10 +14,11 @@ import {
BlueTextCentered,
BlueBigCheckmark,
BlueNavigationStyle,
BlueButtonLink,
} from '../../BlueComponents';
import { BlueCurrentTheme } from '../../components/themes';
import BlueElectrum from '../../blue_modules/BlueElectrum';
import Notifications from '../../blue_modules/notifications';
import { useTheme } from '@react-navigation/native';
const bitcoin = require('bitcoinjs-lib');
const BROADCAST_RESULT = Object.freeze({
@ -28,9 +29,23 @@ const BROADCAST_RESULT = Object.freeze({
});
const Broadcast = () => {
const [tx, setTx] = useState('');
const [txHex, setTxHex] = useState('');
const [tx, setTx] = useState();
const [txHex, setTxHex] = useState();
const { colors } = useTheme();
const [broadcastResult, setBroadcastResult] = useState(BROADCAST_RESULT.none);
const stylesHooks = StyleSheet.create({
blueArea: {
backgroundColor: colors.background,
},
text: {
color: colors.foregroundColor,
},
input: {
borderColor: colors.formBorder,
borderBottomColor: colors.formBorder,
backgroundColor: colors.inputBackgroundColor,
},
});
const handleUpdateTxHex = nextValue => setTxHex(nextValue.trim());
const handleBroadcast = async () => {
setBroadcastResult(BROADCAST_RESULT.pending);
@ -43,7 +58,9 @@ const Broadcast = () => {
const tx = bitcoin.Transaction.fromHex(txHex);
const txid = tx.getId();
setTx(txid);
setBroadcastResult(BROADCAST_RESULT.success);
ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false });
Notifications.majorTomToGroundControl([], [], [txid]);
} else {
setBroadcastResult(BROADCAST_RESULT.error);
@ -82,17 +99,21 @@ const Broadcast = () => {
<BlueFormLabel>{status}</BlueFormLabel>
{BROADCAST_RESULT.pending === broadcastResult && <ActivityIndicator size="small" />}
</View>
<TextInput
style={styles.text}
maxHeight={100}
minHeight={100}
maxWidth="100%"
minWidth="100%"
multiline
editable
value={txHex}
onChangeText={handleUpdateTxHex}
/>
<View style={[styles.input, stylesHooks.input]}>
<TextInput
style={styles.text}
maxHeight={100}
minHeight={100}
maxWidth="100%"
minWidth="100%"
multiline
editable
placeholderTextColor="#81868e"
value={txHex}
onChangeText={handleUpdateTxHex}
/>
</View>
<BlueSpacing10 />
<BlueButton
@ -133,9 +154,6 @@ const styles = StyleSheet.create({
height: '100%',
width: '100%',
},
link: {
color: BlueCurrentTheme.colors.foregroundColor,
},
mainCard: {
padding: 0,
display: 'flex',
@ -155,41 +173,39 @@ const styles = StyleSheet.create({
height: 30,
maxHeight: 30,
},
text: {
flex: 1,
borderColor: '#ebebeb',
backgroundColor: '#d2f8d6',
input: {
flexDirection: 'row',
borderWidth: 1,
borderBottomWidth: 0.5,
alignItems: 'center',
borderRadius: 4,
marginTop: 20,
color: BlueCurrentTheme.colors.foregroundColor,
fontWeight: '500',
fontSize: 14,
paddingHorizontal: 16,
paddingBottom: 16,
paddingTop: 16,
},
text: {
padding: 8,
minHeight: 33,
color: '#81868e',
},
});
function SuccessScreen({ tx }) {
const SuccessScreen = ({ tx }) => {
if (!tx) {
return null;
}
return (
<View style={styles.wrapper}>
<BlueCard>
<View style={styles.broadcastResultWrapper}>
<BlueBigCheckmark />
<BlueSpacing20 />
<BlueTextCentered>Success! You transaction has been broadcasted!</BlueTextCentered>
<BlueTextCentered>{loc.settings.success_transaction_broadcasted}</BlueTextCentered>
<BlueSpacing10 />
<Text style={styles.link} onPress={() => Linking.openURL(`https://blockstream.info/tx/${tx}`)}>
Open link in explorer
</Text>
<BlueButtonLink title={loc.settings.open_link_in_explorer} onPress={() => Linking.openURL(`https://blockstream.info/tx/${tx}`)} />
</View>
</BlueCard>
</View>
);
}
};
SuccessScreen.propTypes = {
tx: PropTypes.string.isRequired,

View File

@ -1,17 +1,16 @@
/* global alert */
import React, { useState } from 'react';
import { ActivityIndicator, Platform, ScrollView, StyleSheet, View } from 'react-native';
import { ActivityIndicator, ScrollView, StyleSheet, View } from 'react-native';
import { BlueNavigationStyle, BlueSpacing20, SafeBlueArea } from '../../BlueComponents';
import { DynamicQRCode } from '../../components/DynamicQRCode';
import { SquareButton } from '../../components/SquareButton';
import { getSystemName } from 'react-native-device-info';
import loc from '../../loc';
import { launchCamera } from 'react-native-image-picker';
import ScanQRCode from './ScanQRCode';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import ActionSheet from '../ActionSheet';
const bitcoin = require('bitcoinjs-lib');
const fs = require('../../blue_modules/fs');
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const isDesktop = getSystemName() === 'Mac OS X';
const PsbtMultisigQRCode = () => {
@ -41,35 +40,33 @@ const PsbtMultisigQRCode = () => {
} else if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) {
// this looks like NOT base64, so maybe its transaction's hex
// we dont support it in this flow
alert(loc.wallets.import_error);
} else {
// psbt base64?
navigate('PsbtMultisig', { receivedPSBTBase64: ret.data });
}
};
const showActionSheet = () => {
const options = [loc._.cancel, loc.wallets.take_photo, loc.wallets.list_long_choose, loc.wallets.import_file];
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, async buttonIndex => {
if (buttonIndex === 1) {
fs.takePhotoWithImagePickerAndReadPhoto.then(onBarScanned);
} else if (buttonIndex === 2) {
fs.showImagePickerAndReadImage(onBarScanned).catch(error => alert(error.message));
} else if (buttonIndex === 3) {
const { data } = await fs.showFilePickerAndReadFile();
if (data) {
onBarScanned({ data });
}
}
});
};
const openScanner = () => {
if (isDesktop) {
launchCamera(
{
title: null,
mediaType: 'photo',
takePhotoButtonTitle: null,
},
response => {
if (response.uri) {
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.uri;
LocalQRCode.decode(uri, (error, result) => {
if (!error) {
onBarScanned(result);
} else {
alert(loc.send.qr_error_no_qrcode);
}
});
} else if (response.error) {
ScanQRCode.presentCameraNotAuthorizedAlert(response.error);
}
},
);
showActionSheet();
} else {
navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',

View File

@ -84,7 +84,7 @@ const TransactionsDetails = () => {
let foundTx = {};
let from = [];
let to = [];
for (const tx of getTransactions()) {
for (const tx of getTransactions(null, Infinity, true)) {
if (tx.hash === hash) {
foundTx = tx;
for (const input of foundTx.inputs) {

View File

@ -87,7 +87,7 @@ const TransactionsStatus = () => {
}
}
for (const tx of getTransactions()) {
for (const tx of getTransactions(null, Infinity, true)) {
if (tx.hash === hash) {
setTX(tx);
break;

View File

@ -29,8 +29,6 @@ import { HDSegwitBech32Wallet, MultisigCosigner, MultisigHDWallet } from '../../
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import loc from '../../loc';
import { getSystemName } from 'react-native-device-info';
import { launchCamera } from 'react-native-image-picker';
import ScanQRCode from '../send/ScanQRCode';
import QRCode from 'react-native-qrcode-svg';
import { SquareButton } from '../../components/SquareButton';
import BottomModal from '../../components/BottomModal';
@ -38,6 +36,7 @@ import MultipleStepsListItem, {
MultipleStepsListItemButtohType,
MultipleStepsListItemDashType,
} from '../../components/MultipleStepsListItem';
import ActionSheet from '../ActionSheet';
import Clipboard from '@react-native-community/clipboard';
import showPopupMenu from 'react-native-popup-menu-android';
import ToolTip from 'react-native-tooltip';
@ -48,7 +47,6 @@ const prompt = require('../../blue_modules/prompt');
const A = require('../../blue_modules/analytics');
const fs = require('../../blue_modules/fs');
const isDesktop = getSystemName() === 'Mac OS X';
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const staticCache = {};
const WalletsAddMultisigStep2 = () => {
@ -315,7 +313,7 @@ const WalletsAddMultisigStep2 = () => {
const onBarScanned = ret => {
setIsProvideMnemonicsModalVisible(false);
navigation.dangerouslyGetParent().pop();
if (!isDesktop) navigation.dangerouslyGetParent().pop();
if (!ret.data) ret = { data: ret };
if (ret.data.toUpperCase().startsWith('UR')) {
alert('BC-UR not decoded. This should never happen');
@ -392,29 +390,8 @@ const WalletsAddMultisigStep2 = () => {
};
const scanOrOpenFile = () => {
setIsProvideMnemonicsModalVisible(false);
if (isDesktop) {
launchCamera(
{
title: null,
mediaType: 'photo',
takePhotoButtonTitle: null,
},
response => {
if (response.uri) {
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.uri;
LocalQRCode.decode(uri, (error, result) => {
if (!error) {
onBarScanned(result);
} else {
alert(loc.send.qr_error_no_qrcode);
}
});
} else if (response.error) {
ScanQRCode.presentCameraNotAuthorizedAlert(response.error);
}
},
);
showActionSheet();
} else {
navigation.navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
@ -426,6 +403,23 @@ const WalletsAddMultisigStep2 = () => {
}
};
const showActionSheet = () => {
const options = [loc._.cancel, loc.wallets.take_photo, loc.wallets.list_long_choose, loc.wallets.import_file];
ActionSheet.showActionSheetWithOptions({ options, cancelButtonIndex: 0 }, async buttonIndex => {
if (buttonIndex === 1) {
fs.takePhotoWithImagePickerAndReadPhoto.then(onBarScanned);
} else if (buttonIndex === 2) {
fs.showImagePickerAndReadImage(onBarScanned).catch(error => alert(error.message));
} else if (buttonIndex === 3) {
const { data } = await fs.showFilePickerAndReadFile();
if (data) {
onBarScanned({ data });
}
}
});
};
const _renderKeyItem = el => {
const renderProvideKeyButtons = el.index === cosigners.length;
const isChecked = el.index < cosigners.length;