import Clipboard from '@react-native-clipboard/clipboard'; import { useNavigation, useRoute } from '@react-navigation/native'; import BigNumber from 'bignumber.js'; import * as bitcoin from 'bitcoinjs-lib'; import PropTypes from 'prop-types'; import React, { useCallback, useEffect } from 'react'; import { Alert, FlatList, Linking, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'; import { Icon } from '@rneui/themed'; import RNFS from 'react-native-fs'; import { PERMISSIONS, request, RESULTS } from 'react-native-permissions'; import Share from 'react-native-share'; import { satoshiToBTC } from '../../blue_modules/currency'; import { isDesktop } from '../../blue_modules/environment'; import { BlueText } from '../../BlueComponents'; import presentAlert from '../../components/Alert'; import { DynamicQRCode } from '../../components/DynamicQRCode'; import { useTheme } from '../../components/themes'; import usePrivacy from '../../hooks/usePrivacy'; import loc from '../../loc'; import { BitcoinUnit } from '../../models/bitcoinUnits'; const SendCreate = () => { const { fee, recipients, memo = '', satoshiPerByte, psbt, showAnimatedQr, tx } = useRoute().params; const transaction = bitcoin.Transaction.fromHex(tx); const size = transaction.virtualSize(); const { colors } = useTheme(); const { setOptions } = useNavigation(); const { enableBlur, disableBlur } = usePrivacy(); const styleHooks = StyleSheet.create({ transactionDetailsTitle: { color: colors.feeText, }, transactionDetailsSubtitle: { color: colors.foregroundColor, }, separator: { backgroundColor: colors.inputBorderColor, }, root: { backgroundColor: colors.elevated, }, cardText: { color: colors.foregroundColor, }, }); useEffect(() => { console.log('send/create - useEffect'); enableBlur(); return () => { disableBlur(); }; }, [disableBlur, enableBlur]); const exportTXN = useCallback(async () => { const fileName = `${Date.now()}.txn`; if (Platform.OS === 'ios') { const filePath = RNFS.TemporaryDirectoryPath + `/${fileName}`; await RNFS.writeFile(filePath, tx); Share.open({ url: 'file://' + filePath, saveToFiles: isDesktop, }) .catch(error => { console.log(error); }) .finally(() => { RNFS.unlink(filePath); }); } else if (Platform.OS === 'android') { const granted = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); if (granted === RESULTS.GRANTED) { console.log('Storage Permission: Granted'); const filePath = RNFS.DownloadDirectoryPath + `/${fileName}`; try { await RNFS.writeFile(filePath, tx); presentAlert({ message: loc.formatString(loc.send.txSaved, { filePath }) }); } catch (e) { console.log(e); presentAlert({ message: e.message }); } } 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' }, ]); } } }, [tx]); useEffect(() => { setOptions({ // eslint-disable-next-line react/no-unstable-nested-components headerRight: () => ( ), }); }, [colors, exportTXN, setOptions]); const _renderItem = ({ index, item }) => { return ( <> {loc.send.create_to} {item.address} {loc.send.create_amount} {satoshiToBTC(item.value)} {BitcoinUnit.BTC} {recipients.length > 1 && ( {loc.formatString(loc._.of, { number: index + 1, total: recipients.length })} )} ); }; _renderItem.propTypes = { index: PropTypes.number, item: PropTypes.shape({ address: PropTypes.string, value: PropTypes.number, }), }; const renderSeparator = () => { return ; }; const ListHeaderComponent = ( {showAnimatedQr && psbt ? : null} {loc.send.create_this_is_hex} Clipboard.setString(tx)}> {loc.send.create_copy} Linking.openURL('https://coinb.in/?verify=' + tx)} > {loc.send.create_verify} ); const ListFooterComponent = ( {loc.send.create_fee} {new BigNumber(fee).toFixed()} {BitcoinUnit.BTC} {loc.send.create_tx_size} {size} vbytes {loc.send.create_satoshi_per_vbyte} {satoshiPerByte} Sat/vB {memo?.length > 0 && ( <> {loc.send.create_memo} {memo} )} ); return ( `${index}`} ItemSeparatorComponent={renderSeparator} ListHeaderComponent={ListHeaderComponent} ListFooterComponent={ListFooterComponent} contentInsetAdjustmentBehavior="automatic" automaticallyAdjustContentInsets /> ); }; export default SendCreate; const styles = StyleSheet.create({ transactionDetailsTitle: { fontWeight: '500', fontSize: 17, marginBottom: 2, }, root: { paddingHorizontal: 20, }, transactionDetailsSubtitle: { fontWeight: '500', fontSize: 15, marginBottom: 20, }, itemOf: { alignSelf: 'flex-end', }, separator: { height: 0.5, marginVertical: 16, }, cardText: { fontWeight: '500', }, cardTx: { borderColor: '#ebebeb', backgroundColor: '#d2f8d6', borderRadius: 4, marginTop: 20, color: '#37c0a1', fontWeight: '500', fontSize: 14, paddingHorizontal: 16, paddingBottom: 16, paddingTop: 16, }, actionTouch: { marginVertical: 24, }, actionText: { color: '#9aa0aa', fontSize: 15, fontWeight: '500', alignSelf: 'center', }, });