diff --git a/BlueComponents.js b/BlueComponents.js index dbf36db71..1b3e8d21e 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -92,43 +92,6 @@ 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; @@ -167,61 +130,72 @@ export class SecondButton extends Component { } } -export const BitcoinButton = props => { - const { colors } = useTheme(); - return ( - - { + if (this.props.onPress) this.props.onPress(); }} > - - {loc.wallets.add_bitcoin} + + + {loc.wallets.add_bitcoin} + + - - - - ); -}; + + ); + } +} -export const LightningButton = props => { - const { colors } = useTheme(); - return ( - - { + if (this.props.onPress) this.props.onPress(); }} > - - {loc.wallets.add_lightning} + + + {loc.wallets.add_lightning} + + - - - - ); -}; + + ); + } +} export class BlueWalletNavigationHeader extends Component { static propTypes = { @@ -424,7 +398,7 @@ export class BlueWalletNavigationHeader extends Component { } } -export const BlueButtonLinkHook = props => { +export const BlueButtonLinkHook = ({ title, onPress }) => { const { colors } = useTheme(); return ( { height: 60, justifyContent: 'center', }} - onPress={props.onPress} - {...props} + onPress={onPress} > - {props.title} + {title} ); }; @@ -683,11 +656,6 @@ export class BlueTextCentered extends Component { } } -export const BlueTextCenteredHooks = props => { - const { colors } = useTheme(); - return ; -}; - export const BlueListItem = React.memo(props => ( { ); }; -export const BlueFormLabel = props => { - const { colors } = useTheme(); - - return ; -}; +export class BlueFormLabel extends Component { + render() { + return ; + } +} export class BlueFormInput extends Component { render() { @@ -1817,6 +1785,7 @@ const WalletCarouselItem = ({ item, index, onPress, handleLongPress }) => { onPress={() => { onPressedOut(); onPress(index); + onPressedOut(); }} /> ); diff --git a/screen/wallets/add.js b/screen/wallets/add.js index bd54c10e3..4486b1636 100644 --- a/screen/wallets/add.js +++ b/screen/wallets/add.js @@ -1,8 +1,9 @@ /* global alert */ -import React, { useState, useEffect } from 'react'; +import React, { Component } from 'react'; import { Text, ScrollView, + LayoutAnimation, ActivityIndicator, Keyboard, KeyboardAvoidingView, @@ -14,35 +15,40 @@ import { } from 'react-native'; import AsyncStorage from '@react-native-community/async-storage'; import { - BlueTextCenteredHooks, - BlueTextHooks, - BlueListItemHooks, + BlueTextCentered, + BlueText, + BlueListItem, LightningButton, BitcoinButton, BlueFormLabel, - BlueButtonHook, + BlueButton, BlueNavigationStyle, - BlueButtonLinkHook, + BlueButtonLink, 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, @@ -80,12 +86,16 @@ 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', @@ -103,305 +113,334 @@ const styles = StyleSheet.create({ }, noPadding: { paddingHorizontal: 0, + backgroundColor: BlueCurrentTheme.colors.elevated, + }, + root: { + backgroundColor: BlueCurrentTheme.colors.elevated, }, }); -const WalletsAdd = () => { - const { colors } = useTheme(); +export default class WalletsAdd extends Component { + constructor(props) { + super(props); + this.state = { + isLoading: true, + walletBaseURI: '', + selectedIndex: 0, + }; + } - 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, - }, + 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 }); }; - useEffect(() => { - AsyncStorage.getItem(AppStorage.LNDHUB) - .then(setWalletBaseURI) - .catch(() => setWalletBaseURI('')); - BlueApp.isAdancedModeEnabled() - .then(setIsAdvancedOptionsEnabled) - .finally(() => setIsLoading(false)); - }, [isAdvancedOptionsEnabled]); + render() { + if (this.state.isLoading) { + return ( + + + + ); + } - const entropyGenerated = newEntropy => { let entropyTitle; - if (!newEntropy) { + if (!this.state.entropy) { entropyTitle = loc.wallets.add_entropy_provide; - } else if (newEntropy.length < 32) { + } else if (this.state.entropy.length < 32) { entropyTitle = loc.formatString(loc.wallets.add_entropy_remain, { - gen: newEntropy.length, - rem: 32 - newEntropy.length, + gen: this.state.entropy.length, + rem: 32 - this.state.entropy.length, }); } else { entropyTitle = loc.formatString(loc.wallets.add_entropy_generated, { - gen: newEntropy.length, + gen: this.state.entropy.length, }); } - setEntropy(newEntropy); - setEntropyButtonText(entropyTitle); - }; - 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} + return ( + + + + + {loc.wallets.add_wallet_name} + + { + this.setLabel(text); + }} + style={styles.textInputCommon} + editable={!this.state.isLoading} + underlineColorAndroid="transparent" + /> - - + {loc.wallets.add_wallet_type} - - {(() => { - 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 - - + { + 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 })} /> - - ); - } - })()} - - {!isLoading ? ( - - ) : ( - - )} - - {!isLoading && ( - + + {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(); + } + } + }); + }} + /> + ) : ( + + )} + + { + this.props.navigation.navigate('ImportWallet'); + }} /> - )} - {isAdvancedOptionsEnabled && !isLoading && ( - - )} - - - - ); -}; + {this.state.isAdvancedOptionsEnabled && ( + { + this.props.navigation.navigate('ProvideEntropy', { onGenerated: entropy => this.setState({ entropy }) }); + }} + /> + )} + + + + ); + } +} WalletsAdd.navigationOptions = ({ navigation }) => ({ ...BlueNavigationStyle(navigation, true), - headerTitle: loc.wallets.add_title, + title: loc.wallets.add_title, headerLeft: null, }); -export default WalletsAdd; +WalletsAdd.propTypes = { + navigation: PropTypes.shape({ + navigate: PropTypes.func, + goBack: PropTypes.func, + }), +};