diff --git a/BlueComponents.js b/BlueComponents.js
index c68c0c4d8..3d6d57306 100644
--- a/BlueComponents.js
+++ b/BlueComponents.js
@@ -144,42 +144,41 @@ export const BlueButtonHook = props => {
);
};
-export class SecondButton extends Component {
- render() {
- let backgroundColor = this.props.backgroundColor ? this.props.backgroundColor : BlueCurrentTheme.colors.buttonBlueBackgroundColor;
- let fontColor = BlueCurrentTheme.colors.buttonTextColor;
- if (this.props.disabled === true) {
- backgroundColor = BlueCurrentTheme.colors.buttonDisabledBackgroundColor;
- fontColor = BlueCurrentTheme.colors.buttonDisabledTextColor;
- }
- // let buttonWidth = this.props.width ? this.props.width : width / 1.5;
- // if ('noMinWidth' in this.props) {
- // buttonWidth = 0;
- // }
- return (
-
-
- {this.props.icon && }
- {this.props.title && {this.props.title}}
-
-
- );
+export const SecondButton = props => {
+ const { colors } = useTheme();
+ let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.buttonBlueBackgroundColor;
+ let fontColor = colors.buttonTextColor;
+ if (props.disabled === true) {
+ backgroundColor = colors.buttonDisabledBackgroundColor;
+ fontColor = colors.buttonDisabledTextColor;
}
-}
+ // let buttonWidth = this.props.width ? this.props.width : width / 1.5;
+ // if ('noMinWidth' in this.props) {
+ // buttonWidth = 0;
+ // }
+ return (
+
+
+ {props.icon && }
+ {props.title && {props.title}}
+
+
+ );
+};
export const BitcoinButton = props => {
const { colors } = useTheme();
diff --git a/Navigation.js b/Navigation.js
index 27850e71f..16670c709 100644
--- a/Navigation.js
+++ b/Navigation.js
@@ -146,7 +146,7 @@ const WalletsRoot = () => (
component={LNDViewInvoice}
options={LNDViewInvoice.navigationOptions}
swipeEnabled={false}
- gesturesEnabled={false}
+ gestureEnabled={false}
/>
(
/>
-
+
);
@@ -205,7 +212,7 @@ const LNDCreateInvoiceRoot = () => (
component={LNDViewInvoice}
options={LNDViewInvoice.navigationOptions}
swipeEnabled={false}
- gesturesEnabled={false}
+ gestureEnabled={false}
/>
{
+ const { txMetadata, fetchAndSaveWalletTransactions } = useContext(BlueStorageContext);
+ const navigation = useNavigation();
+ const route = useRoute();
+ const { fromWallet, memo, psbt, deepLinkPSBT } = route.params;
+ const routeParamsPSBT = useRef(route.params.psbt);
+ const routeParamsTXHex = route.params.txhex;
+ const { colors } = useTheme();
+ const [isLoading, setIsLoading] = useState(false);
+ const [txHex, setTxHex] = useState(route.params.txhex);
- _combinePSBT = receivedPSBT => {
- return this.state.fromWallet.combinePsbt(this.state.psbt, receivedPSBT);
+ const stylesHook = StyleSheet.create({
+ root: {
+ backgroundColor: colors.elevated,
+ },
+ rootPadding: {
+ backgroundColor: colors.elevated,
+ },
+ hexWrap: {
+ backgroundColor: colors.elevated,
+ },
+ hexLabel: {
+ color: colors.foregroundColor,
+ },
+ hexInput: {
+ borderColor: colors.formBorder,
+ backgroundColor: colors.inputBackgroundColor,
+ color: colors.foregroundColor,
+ },
+ hexText: {
+ color: colors.foregroundColor,
+ },
+ });
+
+ const _combinePSBT = receivedPSBT => {
+ return fromWallet.combinePsbt(psbt, receivedPSBT);
};
- onBarScanned = ret => {
+ const onBarScanned = ret => {
if (ret && !ret.data) ret = { data: ret };
if (ret.data.toUpperCase().startsWith('UR')) {
alert('BC-UR not decoded. This should never happen');
}
if (ret.data.indexOf('+') === -1 && ret.data.indexOf('=') === -1 && ret.data.indexOf('=') === -1) {
// this looks like NOT base64, so maybe its transaction's hex
- this.setState({ txhex: ret.data });
+ setTxHex(ret.data);
return;
}
try {
- const Tx = this._combinePSBT(ret.data);
- this.setState({ txhex: Tx.toHex() });
+ const Tx = _combinePSBT(ret.data);
+ setTxHex(Tx.toHex());
} catch (Err) {
alert(Err);
}
};
- constructor(props) {
- super(props);
- this.state = {
- isLoading: false,
- qrCodeHeight: height > width ? width - 40 : width / 3,
- memo: props.route.params.memo,
- psbt: props.route.params.psbt,
- fromWallet: props.route.params.fromWallet,
- isSecondPSBTAlreadyBase64: false,
- deepLinkPSBT: undefined,
- txhex: props.route.params.txhex || undefined,
- animatedQRCodeData: [],
- };
- this.fileName = `${Date.now()}.psbt`;
- }
-
- static getDerivedStateFromProps(nextProps, prevState) {
- if (!prevState.psbt && !nextProps.route.params.txhex) {
- alert('There is no transaction signing in progress');
- return {
- ...prevState,
- isLoading: true,
- };
+ useEffect(() => {
+ if (!psbt && !route.params.txhex) {
+ alert(loc.send.no_tx_signing_in_progress);
}
- const deepLinkPSBT = nextProps.route.params.deepLinkPSBT;
- const txhex = nextProps.route.params.txhex;
if (deepLinkPSBT) {
const psbt = bitcoin.Psbt.fromBase64(deepLinkPSBT);
try {
- const Tx = prevState.fromWallet.combinePsbt(prevState.psbt, psbt);
- return {
- ...prevState,
- txhex: Tx.toHex(),
- };
+ const Tx = fromWallet.combinePsbt(routeParamsPSBT.current, psbt);
+ setTxHex(Tx.toHex());
} catch (Err) {
alert(Err);
}
- } else if (txhex) {
- return {
- ...prevState,
- txhex: txhex,
- };
+ } else if (routeParamsTXHex) {
+ setTxHex(routeParamsTXHex);
}
- return prevState;
- }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [deepLinkPSBT, routeParamsTXHex]);
- componentDidMount() {
- console.log('send/psbtWithHardwareWallet - componentDidMount');
- }
-
- broadcast = () => {
- this.setState({ isLoading: true }, async () => {
- try {
- await BlueElectrum.ping();
- await BlueElectrum.waitTillConnected();
- const result = await this.state.fromWallet.broadcastTx(this.state.txhex);
- if (result) {
- this.setState({ success: true, isLoading: false });
- const txDecoded = bitcoin.Transaction.fromHex(this.state.txhex);
- const txid = txDecoded.getId();
- Notifications.majorTomToGroundControl([], [], [txid]);
- if (this.state.memo) {
- this.context.txMetadata[txid] = { memo: this.state.memo };
- }
- } else {
- ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
- this.setState({ isLoading: false });
- alert(loc.errors.broadcast);
+ const broadcast = async () => {
+ setIsLoading(true);
+ try {
+ await BlueElectrum.ping();
+ await BlueElectrum.waitTillConnected();
+ const result = await fromWallet.broadcastTx(txHex);
+ if (result) {
+ setIsLoading(false);
+ const txDecoded = bitcoin.Transaction.fromHex(txHex);
+ const txid = txDecoded.getId();
+ Notifications.majorTomToGroundControl([], [], [txid]);
+ if (memo) {
+ txMetadata[txid] = { memo };
}
- } catch (error) {
+ fetchAndSaveWalletTransactions(fromWallet.getID());
+ navigation.navigate('Success', { amount: undefined });
+ } else {
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
- this.setState({ isLoading: false });
- alert(error.message);
+ setIsLoading(false);
+ alert(loc.errors.broadcast);
}
- });
+ } catch (error) {
+ ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
+ setIsLoading(false);
+ alert(error.message);
+ }
};
- _renderSuccess() {
- return (
-
-
-
- this.props.navigation.dangerouslyGetParent().pop()} title={loc.send.success_done} />
-
-
- );
- }
+ const handleOnVerifyPressed = () => {
+ Linking.openURL('https://coinb.in/?verify=' + txHex);
+ };
- _renderBroadcastHex() {
- return (
-
-
- {loc.send.create_this_is_hex}
-
+ const copyHexToClipboard = () => {
+ Clipboard.setString(txHex);
+ };
- Clipboard.setString(this.state.txhex)}>
- {loc.send.create_copy}
+ const _renderBroadcastHex = () => {
+ return (
+
+
+ {loc.send.create_this_is_hex}
+
+
+
+ {loc.send.create_copy}
- Linking.openURL('https://coinb.in/?verify=' + this.state.txhex)}>
- {loc.send.create_verify}
+
+ {loc.send.create_verify}
-
+
);
- }
+ };
- exportPSBT = async () => {
+ const exportPSBT = async () => {
+ const fileName = `${Date.now()}.psbt`;
if (Platform.OS === 'ios') {
- const filePath = RNFS.TemporaryDirectoryPath + `/${this.fileName}`;
- await RNFS.writeFile(filePath, typeof this.state.psbt === 'string' ? this.state.psbt : this.state.psbt.toBase64());
+ const filePath = RNFS.TemporaryDirectoryPath + `/${fileName}`;
+ await RNFS.writeFile(filePath, typeof psbt === 'string' ? psbt : psbt.toBase64());
Share.open({
url: 'file://' + filePath,
saveToFiles: isDesktop,
})
.catch(error => {
console.log(error);
- alert(error.message);
})
.finally(() => {
RNFS.unlink(filePath);
@@ -286,25 +197,24 @@ export default class PsbtWithHardwareWallet extends Component {
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Storage Permission: Granted');
- const filePath = RNFS.DownloadDirectoryPath + `/${this.fileName}`;
- await RNFS.writeFile(filePath, typeof this.state.psbt === 'string' ? this.state.psbt : this.state.psbt.toBase64());
- alert(loc.formatString(loc.send.txSaved, { filePath: this.fileName }));
+ const filePath = RNFS.DownloadDirectoryPath + `/${fileName}`;
+ await RNFS.writeFile(filePath, typeof psbt === 'string' ? psbt : psbt.toBase64());
+ alert(loc.formatString(loc.send.txSaved, { filePath: fileName }));
} else {
console.log('Storage Permission: Denied');
}
}
};
- openSignedTransaction = async () => {
+ const openSignedTransaction = async () => {
try {
const res = await DocumentPicker.pick({
type: Platform.OS === 'ios' ? ['io.bluewallet.psbt', 'io.bluewallt.psbt.txn'] : [DocumentPicker.types.allFiles],
});
const file = await RNFS.readFile(res.uri);
if (file) {
- this.setState({ isSecondPSBTAlreadyBase64: true }, () => this.onBarScanned({ data: file }));
+ onBarScanned({ data: file });
} else {
- this.setState({ isSecondPSBTAlreadyBase64: false });
throw new Error();
}
} catch (err) {
@@ -314,7 +224,7 @@ export default class PsbtWithHardwareWallet extends Component {
}
};
- openScanner = () => {
+ const openScanner = () => {
if (isDesktop) {
ImagePicker.launchCamera(
{
@@ -327,7 +237,7 @@ export default class PsbtWithHardwareWallet extends Component {
const uri = Platform.OS === 'ios' ? response.uri.toString().replace('file://', '') : response.path.toString();
LocalQRCode.decode(uri, (error, result) => {
if (!error) {
- this.onBarScanned(result);
+ onBarScanned(result);
} else {
alert(loc.send.qr_error_no_qrcode);
}
@@ -338,96 +248,127 @@ export default class PsbtWithHardwareWallet extends Component {
},
);
} else {
- this.props.navigation.navigate('ScanQRCodeRoot', {
+ navigation.navigate('ScanQRCodeRoot', {
screen: 'ScanQRCode',
params: {
- launchedBy: this.props.route.name,
+ launchedBy: route.name,
showFileImportButton: false,
- onBarScanned: this.onBarScanned,
+ onBarScanned,
},
});
}
};
- render() {
- if (this.state.isLoading) {
- return (
-
-
+ if (txHex) return _renderBroadcastHex();
+
+ return isLoading ? (
+
+
+
+ ) : (
+
+
+
+
+ {loc.send.psbt_this_is_psbt}
+
+
+
+
+
+
+
+
+
+
+
+
+
- );
- }
-
- if (this.state.success) return this._renderSuccess();
- if (this.state.txhex) return this._renderBroadcastHex();
-
- return (
-
-
-
-
- {loc.send.psbt_this_is_psbt}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
-
-PsbtWithHardwareWallet.propTypes = {
- navigation: PropTypes.shape({
- goBack: PropTypes.func,
- navigate: PropTypes.func,
- dangerouslyGetParent: PropTypes.func,
- }),
- route: PropTypes.shape({
- params: PropTypes.object,
- name: PropTypes.string,
- }),
+
+
+ );
};
+export default PsbtWithHardwareWallet;
+
PsbtWithHardwareWallet.navigationOptions = () => ({
...BlueNavigationStyle(null, false),
title: loc.send.header,
});
+
+const styles = StyleSheet.create({
+ root: {
+ flex: 1,
+ },
+ scrollViewContent: {
+ flexGrow: 1,
+ justifyContent: 'space-between',
+ },
+ container: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ paddingTop: 16,
+ paddingBottom: 16,
+ },
+ rootPadding: {
+ flex: 1,
+ paddingTop: 20,
+ },
+ hexWrap: {
+ alignItems: 'center',
+ flex: 1,
+ },
+ hexLabel: {
+ fontWeight: '500',
+ },
+ hexInput: {
+ borderRadius: 4,
+ marginTop: 20,
+ fontWeight: '500',
+ fontSize: 14,
+ paddingHorizontal: 16,
+ paddingBottom: 16,
+ paddingTop: 16,
+ },
+ hexTouch: {
+ marginVertical: 24,
+ },
+ hexText: {
+ fontSize: 15,
+ fontWeight: '500',
+ alignSelf: 'center',
+ },
+ copyToClipboard: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
diff --git a/screen/send/success.js b/screen/send/success.js
index adad08ac5..a6d115a47 100644
--- a/screen/send/success.js
+++ b/screen/send/success.js
@@ -1,9 +1,9 @@
import React, { useEffect, useRef } from 'react';
import LottieView from 'lottie-react-native';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
-import { View, StyleSheet } from 'react-native';
+import { View, StyleSheet, SafeAreaView } from 'react-native';
import { Text } from 'react-native-elements';
-import { BlueButton, SafeBlueArea, BlueCard } from '../../BlueComponents';
+import { BlueButton, BlueCard } from '../../BlueComponents';
import { BitcoinUnit } from '../../models/bitcoinUnits';
import loc from '../../loc';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
@@ -11,7 +11,7 @@ import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
const Success = () => {
const { colors } = useTheme();
const { dangerouslyGetParent } = useNavigation();
- const { amount, fee = 0, amountUnit = BitcoinUnit.BTC, invoiceDescription = '' } = useRoute().params;
+ const { amount = 0, fee = 0, amountUnit = BitcoinUnit.BTC, invoiceDescription = '' } = useRoute().params;
const animationRef = useRef();
const stylesHook = StyleSheet.create({
root: {
@@ -39,14 +39,16 @@ const Success = () => {
}, [colors]);
return (
-
-
- {amount > 0 && (
-
- {amount}
- {' ' + amountUnit}
-
- )}
+
+
+
+ {amount > 0 && (
+ <>
+ {amount}
+ {' ' + amountUnit}
+ >
+ )}
+
{fee > 0 && (
{loc.send.create_fee}: {fee} {BitcoinUnit.BTC}
@@ -81,28 +83,26 @@ const Success = () => {
]}
/>
-
+
-
-
+
+
);
};
-Success.navigationOptions = {
- headerShown: false,
- gesturesEnabled: false,
-};
-
export default Success;
const styles = StyleSheet.create({
root: {
flex: 1,
paddingTop: 19,
+ justifyContent: 'space-between',
},
- amout: {
+ buttonContainer: {
+ padding: 58,
+ },
+ amount: {
alignItems: 'center',
- flex: 1,
},
view: {
flexDirection: 'row',