diff --git a/BlueComponents.js b/BlueComponents.js index 1b3e8d21e..dbf36db71 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -92,6 +92,43 @@ export class BlueButton extends Component { } } +export const BlueButtonHook = props => { + const { colors } = useTheme(); + let backgroundColor = props.backgroundColor ? props.backgroundColor : colors.mainColor; + let fontColor = colors.buttonTextColor; + if (props.disabled === true) { + backgroundColor = colors.buttonDisabledBackgroundColor; + fontColor = colors.buttonDisabledTextColor; + } + let buttonWidth = props.width ? props.width : width / 1.5; + if ('noMinWidth' in props) { + buttonWidth = 0; + } + return ( + + + {props.icon && } + {props.title && {props.title}} + + + ); +}; + export class SecondButton extends Component { render() { let backgroundColor = this.props.backgroundColor ? this.props.backgroundColor : BlueCurrentTheme.colors.buttonBlueBackgroundColor; @@ -130,72 +167,61 @@ export class SecondButton extends Component { } } -export class BitcoinButton extends Component { - render() { - return ( - { - if (this.props.onPress) this.props.onPress(); +export const BitcoinButton = props => { + const { colors } = useTheme(); + return ( + + - - - {loc.wallets.add_bitcoin} - - + + {loc.wallets.add_bitcoin} - - ); - } -} + + + + ); +}; -export class LightningButton extends Component { - render() { - return ( - { - if (this.props.onPress) this.props.onPress(); +export const LightningButton = props => { + const { colors } = useTheme(); + return ( + + - - - {loc.wallets.add_lightning} - - + + {loc.wallets.add_lightning} - - ); - } -} + + + + ); +}; export class BlueWalletNavigationHeader extends Component { static propTypes = { @@ -398,7 +424,7 @@ export class BlueWalletNavigationHeader extends Component { } } -export const BlueButtonLinkHook = ({ title, onPress }) => { +export const BlueButtonLinkHook = props => { const { colors } = useTheme(); return ( { height: 60, justifyContent: 'center', }} - onPress={onPress} + onPress={props.onPress} + {...props} > - {title} + {props.title} ); }; @@ -656,6 +683,11 @@ export class BlueTextCentered extends Component { } } +export const BlueTextCenteredHooks = props => { + const { colors } = useTheme(); + return ; +}; + export const BlueListItem = React.memo(props => ( { ); }; -export class BlueFormLabel extends Component { - render() { - return ; - } -} +export const BlueFormLabel = props => { + const { colors } = useTheme(); + + return ; +}; export class BlueFormInput extends Component { render() { @@ -1785,7 +1817,6 @@ const WalletCarouselItem = ({ item, index, onPress, handleLongPress }) => { onPress={() => { onPressedOut(); onPress(index); - onPressedOut(); }} /> ); diff --git a/screen/wallets/add.js b/screen/wallets/add.js index 4486b1636..bd54c10e3 100644 --- a/screen/wallets/add.js +++ b/screen/wallets/add.js @@ -1,9 +1,8 @@ /* global alert */ -import React, { Component } from 'react'; +import React, { useState, useEffect } from 'react'; import { Text, ScrollView, - LayoutAnimation, ActivityIndicator, Keyboard, KeyboardAvoidingView, @@ -15,40 +14,35 @@ import { } from 'react-native'; import AsyncStorage from '@react-native-community/async-storage'; import { - BlueTextCentered, - BlueText, - BlueListItem, + BlueTextCenteredHooks, + BlueTextHooks, + BlueListItemHooks, LightningButton, BitcoinButton, BlueFormLabel, - BlueButton, + BlueButtonHook, BlueNavigationStyle, - BlueButtonLink, + BlueButtonLinkHook, BlueSpacing20, } from '../../BlueComponents'; -import PropTypes from 'prop-types'; import { HDSegwitBech32Wallet, SegwitP2SHWallet, HDSegwitP2SHWallet, LightningCustodianWallet, AppStorage } from '../../class'; -import { BlueCurrentTheme } from '../../components/themes'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; import { Icon } from 'react-native-elements'; +import { useTheme, useNavigation } from '@react-navigation/native'; +import { Chain } from '../../models/bitcoinUnits'; import loc from '../../loc'; const EV = require('../../blue_modules/events'); const A = require('../../blue_modules/analytics'); const BlueApp: AppStorage = require('../../BlueApp'); - const styles = StyleSheet.create({ loading: { flex: 1, paddingTop: 20, - backgroundColor: BlueCurrentTheme.colors.elevated, }, label: { flexDirection: 'row', - borderColor: BlueCurrentTheme.colors.formBorder, - borderBottomColor: BlueCurrentTheme.colors.formBorder, borderWidth: 1, borderBottomWidth: 0.5, - backgroundColor: BlueCurrentTheme.colors.inputBackgroundColor, minHeight: 44, height: 44, marginHorizontal: 20, @@ -86,16 +80,12 @@ const styles = StyleSheet.create({ marginHorizontal: 20, }, advancedText: { - color: BlueCurrentTheme.colors.feeText, fontWeight: '500', }, lndUri: { flexDirection: 'row', - borderColor: BlueCurrentTheme.colors.formBorder, - borderBottomColor: BlueCurrentTheme.colors.formBorder, borderWidth: 1, borderBottomWidth: 0.5, - backgroundColor: BlueCurrentTheme.colors.inputBackgroundColor, minHeight: 44, height: 44, alignItems: 'center', @@ -113,334 +103,305 @@ const styles = StyleSheet.create({ }, noPadding: { paddingHorizontal: 0, - backgroundColor: BlueCurrentTheme.colors.elevated, - }, - root: { - backgroundColor: BlueCurrentTheme.colors.elevated, }, }); -export default class WalletsAdd extends Component { - constructor(props) { - super(props); - this.state = { - isLoading: true, - walletBaseURI: '', - selectedIndex: 0, - }; - } +const WalletsAdd = () => { + const { colors } = useTheme(); - async componentDidMount() { - let walletBaseURI = await AsyncStorage.getItem(AppStorage.LNDHUB); - const isAdvancedOptionsEnabled = await BlueApp.isAdancedModeEnabled(); - walletBaseURI = walletBaseURI || ''; - this.setState({ - isLoading: false, - activeBitcoin: undefined, - label: '', - isAdvancedOptionsEnabled, - walletBaseURI, - }); - } - - setLabel(text) { - this.setState({ - label: text, - }); /* also, a hack to make screen update new typed text */ - } - - onSelect(index) { - this.setState({ - selectedIndex: index, - }); - } - - showAdvancedOptions = () => { - Keyboard.dismiss(); - LayoutAnimation.configureNext(LayoutAnimation.Presets.spring); - this.setState({ isAdvancedOptionsEnabled: true }); + const [isLoading, setIsLoading] = useState(true); + const [walletBaseURI, setWalletBaseURI] = useState(); + const [selectedIndex, setSelectedIndex] = useState(0); + const [label, setLabel] = useState(''); + const [isAdvancedOptionsEnabled, setIsAdvancedOptionsEnabled] = useState(false); + const [selectedWalletType, setSelectedWalletType] = useState(false); + const { navigate, goBack } = useNavigation(); + const [entropy, setEntropy] = useState(); + const [entropyButtonText, setEntropyButtonText] = useState(loc.wallets.add_entropy_provide); + const stylesHook = { + advancedText: { + color: colors.feeText, + }, + label: { + borderColor: colors.formBorder, + borderBottomColor: colors.formBorder, + backgroundColor: colors.inputBackgroundColor, + }, + noPadding: { + backgroundColor: colors.elevated, + }, + root: { + backgroundColor: colors.elevated, + }, + lndUri: { + borderColor: colors.formBorder, + borderBottomColor: colors.formBorder, + backgroundColor: colors.inputBackgroundColor, + }, }; - render() { - if (this.state.isLoading) { - return ( - - - - ); - } + useEffect(() => { + AsyncStorage.getItem(AppStorage.LNDHUB) + .then(setWalletBaseURI) + .catch(() => setWalletBaseURI('')); + BlueApp.isAdancedModeEnabled() + .then(setIsAdvancedOptionsEnabled) + .finally(() => setIsLoading(false)); + }, [isAdvancedOptionsEnabled]); + const entropyGenerated = newEntropy => { let entropyTitle; - if (!this.state.entropy) { + if (!newEntropy) { entropyTitle = loc.wallets.add_entropy_provide; - } else if (this.state.entropy.length < 32) { + } else if (newEntropy.length < 32) { entropyTitle = loc.formatString(loc.wallets.add_entropy_remain, { - gen: this.state.entropy.length, - rem: 32 - this.state.entropy.length, + gen: newEntropy.length, + rem: 32 - newEntropy.length, }); } else { entropyTitle = loc.formatString(loc.wallets.add_entropy_generated, { - gen: this.state.entropy.length, + gen: newEntropy.length, }); } + setEntropy(newEntropy); + setEntropyButtonText(entropyTitle); + }; - return ( - - - - - {loc.wallets.add_wallet_name} - - { - this.setLabel(text); - }} - style={styles.textInputCommon} - editable={!this.state.isLoading} - underlineColorAndroid="transparent" - /> + const createWallet = async () => { + setIsLoading(true); + + let w; + + if (selectedWalletType === Chain.OFFCHAIN) { + createLightningWallet(w); + } else if (selectedWalletType === Chain.ONCHAIN) { + if (selectedIndex === 2) { + // zero index radio - HD segwit + w = new HDSegwitP2SHWallet(); + w.setLabel(label || loc.wallets.details.title); + } else if (selectedIndex === 1) { + // btc was selected + // index 1 radio - segwit single address + w = new SegwitP2SHWallet(); + w.setLabel(label || loc.wallets.details.title); + } else { + // btc was selected + // index 2 radio - hd bip84 + w = new HDSegwitBech32Wallet(); + w.setLabel(label || loc.wallets.details.title); + } + if (selectedWalletType === Chain.ONCHAIN) { + if (entropy) { + try { + await w.generateFromEntropy(entropy); + } catch (e) { + console.log(e.toString()); + alert(e.toString()); + goBack(); + return; + } + } else { + await w.generate(); + } + BlueApp.wallets.push(w); + await BlueApp.saveToDisk(); + EV(EV.enum.WALLETS_COUNT_CHANGED); + A(A.ENUM.CREATED_WALLET); + ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false }); + if (w.type === HDSegwitP2SHWallet.type || w.type === HDSegwitBech32Wallet.type) { + navigate('PleaseBackup', { + secret: w.getSecret(), + }); + } else { + goBack(); + } + } + } + }; + + const createLightningWallet = async wallet => { + wallet = new LightningCustodianWallet(); + wallet.setLabel(label || loc.wallets.details.title); + + try { + const lndhub = walletBaseURI && walletBaseURI.trim().length > 0 ? walletBaseURI : LightningCustodianWallet.defaultBaseUri; + if (lndhub) { + const isValidNodeAddress = await LightningCustodianWallet.isValidNodeAddress(lndhub); + if (isValidNodeAddress) { + wallet.setBaseURI(lndhub); + wallet.init(); + } else { + throw new Error('The provided node address is not valid LNDHub node.'); + } + } + await wallet.createAccount(); + await wallet.authorize(); + } catch (Err) { + setIsLoading(false); + console.warn('lnd create failure', Err); + return alert(Err); + // giving app, not adding anything + } + A(A.ENUM.CREATED_LIGHTNING_WALLET); + await wallet.generate(); + BlueApp.wallets.push(wallet); + await BlueApp.saveToDisk(); + EV(EV.enum.WALLETS_COUNT_CHANGED); + A(A.ENUM.CREATED_WALLET); + ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false }); + navigate('PleaseBackupLNDHub', { + wallet, + }); + }; + + const navigateToEntropy = () => { + navigate('ProvideEntropy', { onGenerated: entropyGenerated }); + }; + + const navigateToImportWallet = () => { + navigate('ImportWallet'); + }; + + const handleOnBitcoinButtonPressed = () => { + Keyboard.dismiss(); + setSelectedWalletType(Chain.ONCHAIN); + }; + + const handleOnLightningButtonPressed = () => { + Keyboard.dismiss(); + setSelectedWalletType(Chain.OFFCHAIN); + }; + + return ( + + + + + {loc.wallets.add_wallet_name} + + + + {loc.wallets.add_wallet_type} + + + + + {loc.wallets.add_or} - {loc.wallets.add_wallet_type} + + - - { - Keyboard.dismiss(); - this.setState({ - activeBitcoin: true, - activeLightning: false, - }); - }} - style={styles.button} - /> - - {loc.wallets.add_or} - - { - Keyboard.dismiss(); - this.setState({ - activeBitcoin: false, - activeLightning: true, - }); - }} - style={styles.button} - /> - - - - {(() => { - if (this.state.activeBitcoin && this.state.isAdvancedOptionsEnabled) { - return ( - - - {loc.settings.advanced_options} - { - this.onSelect(0, HDSegwitBech32Wallet.type); - }} - title={HDSegwitBech32Wallet.typeReadable} - {...(this.state.selectedIndex === 0 - ? { - rightIcon: , - } - : { hideChevron: true })} - /> - { - this.onSelect(1, SegwitP2SHWallet.type); - }} - title={SegwitP2SHWallet.typeReadable} - {...(this.state.selectedIndex === 1 - ? { - rightIcon: , - } - : { hideChevron: true })} - /> - { - this.onSelect(2, HDSegwitP2SHWallet.typeReadable.type); - }} - title={HDSegwitP2SHWallet.typeReadable} - {...(this.state.selectedIndex === 2 - ? { - rightIcon: , - } - : { hideChevron: true })} + + {(() => { + if (selectedWalletType === Chain.ONCHAIN && isAdvancedOptionsEnabled) { + return ( + + + {loc.settings.advanced_options} + setSelectedIndex(0)} + title={HDSegwitBech32Wallet.typeReadable} + {...(selectedIndex === 0 + ? { + rightIcon: , + } + : { hideChevron: true })} + /> + setSelectedIndex(1)} + title={SegwitP2SHWallet.typeReadable} + {...(selectedIndex === 1 + ? { + rightIcon: , + } + : { hideChevron: true })} + /> + setSelectedIndex(2)} + title={HDSegwitP2SHWallet.typeReadable} + {...(selectedIndex === 2 + ? { + rightIcon: , + } + : { hideChevron: true })} + /> + + ); + } else if (selectedWalletType === Chain.OFFCHAIN && isAdvancedOptionsEnabled) { + return ( + <> + + {loc.settings.advanced_options} + + Connect to your LNDHub + + - ); - } else if (this.state.activeLightning && this.state.isAdvancedOptionsEnabled) { - return ( - <> - - {loc.settings.advanced_options} - - {loc.wallets.add_lndhub} - - this.setState({ walletBaseURI: text })} - onSubmitEditing={Keyboard.dismiss} - placeholder={loc.wallets.add_lndhub_placeholder} - clearButtonMode="while-editing" - autoCapitalize="none" - placeholderTextColor="#81868e" - style={styles.textInputCommon} - editable={!this.state.isLoading} - underlineColorAndroid="transparent" - /> - - - ); - } else if (this.state.activeBitcoin === undefined && this.state.isAdvancedOptionsEnabled) { - return ; - } - })()} - - {!this.state.isLoading ? ( - { - this.setState({ isLoading: true }, async () => { - let w; - - if (this.state.activeLightning) { - this.createLightningWallet = async () => { - w = new LightningCustodianWallet(); - w.setLabel(this.state.label || loc.wallets.details_title); - - try { - const lndhub = - this.state.walletBaseURI.trim().length > 0 - ? this.state.walletBaseURI - : LightningCustodianWallet.defaultBaseUri; - if (lndhub) { - const isValidNodeAddress = await LightningCustodianWallet.isValidNodeAddress(lndhub); - if (isValidNodeAddress) { - w.setBaseURI(lndhub); - w.init(); - } else { - throw new Error(loc.wallets.add_lndhub_error); - } - } - - await w.createAccount(); - await w.authorize(); - } catch (Err) { - this.setState({ isLoading: false }); - console.warn('lnd create failure', Err); - return alert(Err); - // giving app, not adding anything - } - A(A.ENUM.CREATED_LIGHTNING_WALLET); - await w.generate(); - BlueApp.wallets.push(w); - await BlueApp.saveToDisk(); - EV(EV.enum.WALLETS_COUNT_CHANGED); - A(A.ENUM.CREATED_WALLET); - ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false }); - this.props.navigation.navigate('PleaseBackupLNDHub', { - wallet: w, - }); - }; - this.createLightningWallet(); - } else if (this.state.selectedIndex === 2) { - // zero index radio - HD segwit - w = new HDSegwitP2SHWallet(); - w.setLabel(this.state.label || loc.wallets.details_title); - } else if (this.state.selectedIndex === 1) { - // btc was selected - // index 1 radio - segwit single address - w = new SegwitP2SHWallet(); - w.setLabel(this.state.label || loc.wallets.details_title); - } else { - // btc was selected - // index 2 radio - hd bip84 - w = new HDSegwitBech32Wallet(); - w.setLabel(this.state.label || loc.wallets.details_title); - } - if (this.state.activeBitcoin) { - if (this.state.entropy) { - try { - await w.generateFromEntropy(this.state.entropy); - } catch (e) { - console.log(e.toString()); - alert(e.toString()); - this.props.navigation.goBack(); - return; - } - } else { - await w.generate(); - } - BlueApp.wallets.push(w); - await BlueApp.saveToDisk(); - EV(EV.enum.WALLETS_COUNT_CHANGED); - A(A.ENUM.CREATED_WALLET); - ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false }); - if (w.type === HDSegwitP2SHWallet.type || w.type === HDSegwitBech32Wallet.type) { - this.props.navigation.navigate('PleaseBackup', { - secret: w.getSecret(), - }); - } else { - this.props.navigation.goBack(); - } - } - }); - }} - /> - ) : ( - - )} - - + ); + } + })()} + + {!isLoading ? ( + + ) : ( + + )} + + {!isLoading && ( + { - this.props.navigation.navigate('ImportWallet'); - }} + onPress={navigateToImportWallet} /> - {this.state.isAdvancedOptionsEnabled && ( - { - this.props.navigation.navigate('ProvideEntropy', { onGenerated: entropy => this.setState({ entropy }) }); - }} - /> - )} - - - - ); - } -} + )} + {isAdvancedOptionsEnabled && !isLoading && ( + + )} + + + + ); +}; WalletsAdd.navigationOptions = ({ navigation }) => ({ ...BlueNavigationStyle(navigation, true), - title: loc.wallets.add_title, + headerTitle: loc.wallets.add_title, headerLeft: null, }); -WalletsAdd.propTypes = { - navigation: PropTypes.shape({ - navigate: PropTypes.func, - goBack: PropTypes.func, - }), -}; +export default WalletsAdd;