BlueWallet/screen/send/create.js

242 lines
8.1 KiB
JavaScript
Raw Normal View History

2021-02-28 00:13:37 -05:00
import Clipboard from '@react-native-clipboard/clipboard';
2024-05-20 10:54:13 +01:00
import { useNavigation, useRoute } from '@react-navigation/native';
import BigNumber from 'bignumber.js';
2024-04-09 18:14:14 +02:00
import * as bitcoin from 'bitcoinjs-lib';
2024-05-20 10:54:13 +01:00
import PropTypes from 'prop-types';
import React, { useCallback, useEffect } from 'react';
import { Alert, FlatList, Linking, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
2024-06-12 12:46:44 -04:00
import { Icon } from '@rneui/themed';
2024-05-20 10:54:13 +01:00
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';
2021-05-29 01:57:40 -04:00
import { isDesktop } from '../../blue_modules/environment';
2024-05-20 10:54:13 +01:00
import { BlueText } from '../../BlueComponents';
import presentAlert from '../../components/Alert';
2024-05-20 10:54:13 +01:00
import { DynamicQRCode } from '../../components/DynamicQRCode';
2023-10-23 21:28:44 -04:00
import { useTheme } from '../../components/themes';
2024-02-20 13:40:16 -04:00
import usePrivacy from '../../hooks/usePrivacy';
2024-05-20 10:54:13 +01:00
import loc from '../../loc';
import { BitcoinUnit } from '../../models/bitcoinUnits';
2018-01-30 22:42:38 +00:00
2021-09-07 12:54:57 -04:00
const SendCreate = () => {
2021-09-07 19:43:13 -04:00
const { fee, recipients, memo = '', satoshiPerByte, psbt, showAnimatedQr, tx } = useRoute().params;
const transaction = bitcoin.Transaction.fromHex(tx);
const size = transaction.virtualSize();
2021-09-07 12:54:57 -04:00
const { colors } = useTheme();
const { setOptions } = useNavigation();
2024-02-20 13:40:16 -04:00
const { enableBlur, disableBlur } = usePrivacy();
2021-09-07 12:54:57 -04:00
const styleHooks = StyleSheet.create({
transactionDetailsTitle: {
color: colors.feeText,
},
transactionDetailsSubtitle: {
color: colors.foregroundColor,
},
separator: {
backgroundColor: colors.inputBorderColor,
},
root: {
backgroundColor: colors.elevated,
},
cardText: {
color: colors.foregroundColor,
},
});
2018-01-30 22:42:38 +00:00
2021-09-07 12:54:57 -04:00
useEffect(() => {
console.log('send/create - useEffect');
2024-02-20 13:40:16 -04:00
enableBlur();
2021-09-07 12:54:57 -04:00
return () => {
2024-02-20 13:40:16 -04:00
disableBlur();
2021-09-07 12:54:57 -04:00
};
2024-02-20 13:40:16 -04:00
}, [disableBlur, enableBlur]);
2021-09-07 12:54:57 -04:00
const exportTXN = useCallback(async () => {
2020-01-03 23:02:30 -06:00
const fileName = `${Date.now()}.txn`;
if (Platform.OS === 'ios') {
const filePath = RNFS.TemporaryDirectoryPath + `/${fileName}`;
2021-09-07 12:54:57 -04:00
await RNFS.writeFile(filePath, tx);
2020-01-03 23:02:30 -06:00
Share.open({
url: 'file://' + filePath,
2021-05-29 01:57:40 -04:00
saveToFiles: isDesktop,
2020-01-03 23:02:30 -06:00
})
2020-09-06 21:47:47 -04:00
.catch(error => {
console.log(error);
})
2020-01-03 23:02:30 -06:00
.finally(() => {
RNFS.unlink(filePath);
});
} else if (Platform.OS === 'android') {
const granted = await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
if (granted === RESULTS.GRANTED) {
2020-01-14 23:49:57 -05:00
console.log('Storage Permission: Granted');
const filePath = RNFS.DownloadDirectoryPath + `/${fileName}`;
try {
2021-09-07 12:54:57 -04:00
await RNFS.writeFile(filePath, tx);
presentAlert({ message: loc.formatString(loc.send.txSaved, { filePath }) });
} catch (e) {
console.log(e);
presentAlert({ message: e.message });
}
2020-01-14 23:49:57 -05:00
} 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' },
]);
2020-01-14 23:49:57 -05:00
}
2020-01-03 23:02:30 -06:00
}
2021-09-07 12:54:57 -04:00
}, [tx]);
2020-01-03 23:02:30 -06:00
2021-09-07 13:10:35 -04:00
useEffect(() => {
setOptions({
// eslint-disable-next-line react/no-unstable-nested-components
2021-09-07 13:10:35 -04:00
headerRight: () => (
2021-09-13 13:43:26 -04:00
<TouchableOpacity accessibilityRole="button" onPress={exportTXN}>
2021-09-07 13:10:35 -04:00
<Icon size={22} name="share-alternative" type="entypo" color={colors.foregroundColor} />
</TouchableOpacity>
),
});
}, [colors, exportTXN, setOptions]);
2021-09-07 12:54:57 -04:00
const _renderItem = ({ index, item }) => {
return (
<>
<View>
2021-09-07 12:54:57 -04:00
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_to}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>{item.address}</Text>
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_amount}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>
2024-01-28 11:11:08 -04:00
{satoshiToBTC(item.value)} {BitcoinUnit.BTC}
</Text>
2021-09-07 12:54:57 -04:00
{recipients.length > 1 && (
<BlueText style={styles.itemOf}>{loc.formatString(loc._.of, { number: index + 1, total: recipients.length })}</BlueText>
)}
</View>
</>
);
};
2021-09-07 12:54:57 -04:00
_renderItem.propTypes = {
index: PropTypes.number,
item: PropTypes.shape({
address: PropTypes.string,
value: PropTypes.number,
}),
};
2021-09-07 12:54:57 -04:00
const renderSeparator = () => {
return <View style={[styles.separator, styleHooks.separator]} />;
};
2021-09-07 12:54:57 -04:00
const ListHeaderComponent = (
<View>
{showAnimatedQr && psbt ? <DynamicQRCode value={psbt.toHex()} /> : null}
<BlueText style={[styles.cardText, styleHooks.cardText]}>{loc.send.create_this_is_hex}</BlueText>
2021-09-07 15:30:35 -04:00
<TextInput testID="TxhexInput" style={styles.cardTx} height={72} multiline editable={false} value={tx} />
2021-09-07 12:54:57 -04:00
<TouchableOpacity accessibilityRole="button" style={styles.actionTouch} onPress={() => Clipboard.setString(tx)}>
<Text style={styles.actionText}>{loc.send.create_copy}</Text>
</TouchableOpacity>
<TouchableOpacity
accessibilityRole="button"
style={styles.actionTouch}
onPress={() => Linking.openURL('https://coinb.in/?verify=' + tx)}
>
<Text style={styles.actionText}>{loc.send.create_verify}</Text>
</TouchableOpacity>
</View>
);
2018-01-30 22:42:38 +00:00
2021-09-07 15:30:35 -04:00
const ListFooterComponent = (
<View>
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_fee}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>
{new BigNumber(fee).toFixed()} {BitcoinUnit.BTC}
</Text>
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_tx_size}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>{size} vbytes</Text>
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_satoshi_per_vbyte}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>{satoshiPerByte} Sat/vB</Text>
2021-09-07 19:43:13 -04:00
{memo?.length > 0 && (
2021-09-07 15:30:35 -04:00
<>
<Text style={[styles.transactionDetailsTitle, styleHooks.transactionDetailsTitle]}>{loc.send.create_memo}</Text>
<Text style={[styles.transactionDetailsSubtitle, styleHooks.transactionDetailsSubtitle]}>{memo}</Text>
</>
)}
</View>
);
2021-09-07 12:54:57 -04:00
return (
2021-09-07 15:30:35 -04:00
<FlatList
contentContainerStyle={[styles.root, styleHooks.root]}
extraData={recipients}
data={recipients}
renderItem={_renderItem}
keyExtractor={(_item, index) => `${index}`}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={ListHeaderComponent}
ListFooterComponent={ListFooterComponent}
contentInsetAdjustmentBehavior="automatic"
automaticallyAdjustContentInsets
/>
2021-09-07 12:54:57 -04:00
);
};
export default SendCreate;
2018-03-18 02:48:23 +00:00
const styles = StyleSheet.create({
transactionDetailsTitle: {
fontWeight: '500',
fontSize: 17,
marginBottom: 2,
},
2021-09-07 15:30:35 -04:00
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',
},
});