2018-10-30 05:35:24 -04:00
/* global alert */
2018-01-30 22:42:38 +00:00
import React , { Component } from 'react' ;
2019-09-27 15:49:56 +01:00
import {
ActivityIndicator ,
View ,
Text ,
TextInput ,
Alert ,
2020-01-02 16:06:51 -06:00
KeyboardAvoidingView ,
2019-09-27 15:49:56 +01:00
TouchableOpacity ,
Keyboard ,
TouchableWithoutFeedback ,
Switch ,
2020-04-16 13:41:12 +02:00
Platform ,
Linking ,
2020-05-24 12:17:26 +03:00
StyleSheet ,
2020-06-10 23:54:47 -04:00
StatusBar ,
2019-09-27 15:49:56 +01:00
} from 'react-native' ;
2019-08-30 20:10:26 -04:00
import { BlueButton , SafeBlueArea , BlueCard , BlueSpacing20 , BlueNavigationStyle , BlueText } from '../../BlueComponents' ;
2018-03-18 02:48:23 +00:00
import PropTypes from 'prop-types' ;
2020-05-24 06:27:08 -04:00
import { LightningCustodianWallet } from '../../class/wallets/lightning-custodian-wallet' ;
import { HDLegacyBreadwalletWallet } from '../../class/wallets/hd-legacy-breadwallet-wallet' ;
import { HDLegacyP2PKHWallet } from '../../class/wallets/hd-legacy-p2pkh-wallet' ;
import { HDSegwitP2SHWallet } from '../../class/wallets/hd-segwit-p2sh-wallet' ;
2018-12-13 11:50:18 -05:00
import ReactNativeHapticFeedback from 'react-native-haptic-feedback' ;
2019-09-24 23:42:21 -04:00
import Biometric from '../../class/biometrics' ;
2020-02-26 14:39:19 +00:00
import { HDSegwitBech32Wallet , SegwitP2SHWallet , LegacyWallet , SegwitBech32Wallet , WatchOnlyWallet } from '../../class' ;
2019-12-31 21:31:04 -06:00
import { ScrollView } from 'react-native-gesture-handler' ;
2020-01-02 16:06:51 -06:00
const EV = require ( '../../events' ) ;
const prompt = require ( '../../prompt' ) ;
2018-03-18 02:48:23 +00:00
/** @type {AppStorage} */
2020-01-02 16:06:51 -06:00
const BlueApp = require ( '../../BlueApp' ) ;
const loc = require ( '../../loc' ) ;
2018-01-30 22:42:38 +00:00
2020-05-24 12:17:26 +03:00
const styles = StyleSheet . create ( {
root : {
flex : 1 ,
} ,
scrollViewContent : {
flexGrow : 1 ,
} ,
save : {
marginHorizontal : 16 ,
justifyContent : 'center' ,
alignItems : 'center' ,
} ,
saveText : {
color : '#0c2550' ,
} ,
address : {
alignItems : 'center' ,
flex : 1 ,
} ,
textLabel1 : {
color : '#0c2550' ,
fontWeight : '500' ,
fontSize : 14 ,
marginVertical : 12 ,
} ,
textLabel2 : {
color : '#0c2550' ,
fontWeight : '500' ,
fontSize : 14 ,
marginVertical : 16 ,
} ,
textValue : {
color : '#81868e' ,
fontWeight : '500' ,
fontSize : 14 ,
} ,
input : {
flexDirection : 'row' ,
borderColor : '#d2d2d2' ,
borderBottomColor : '#d2d2d2' ,
borderWidth : 1 ,
borderBottomWidth : 0.5 ,
backgroundColor : '#f5f5f5' ,
minHeight : 44 ,
height : 44 ,
alignItems : 'center' ,
borderRadius : 4 ,
} ,
inputText : {
flex : 1 ,
marginHorizontal : 8 ,
minHeight : 33 ,
2020-06-09 08:23:21 -04:00
color : '#81868e' ,
2020-05-24 12:17:26 +03:00
} ,
hardware : {
flexDirection : 'row' ,
alignItems : 'center' ,
justifyContent : 'space-between' ,
} ,
center : {
alignItems : 'center' ,
} ,
delete : {
color : '#d0021b' ,
fontSize : 15 ,
fontWeight : '500' ,
} ,
} ) ;
2018-01-30 22:42:38 +00:00
export default class WalletDetails extends Component {
2020-05-27 14:12:17 +03:00
static navigationOptions = ( { navigation , route } ) => ( {
2018-10-30 05:35:24 -04:00
... BlueNavigationStyle ( ) ,
2018-10-29 18:11:48 -04:00
title : loc . wallets . details . title ,
2020-05-27 14:12:17 +03:00
headerRight : ( ) => (
2018-11-09 23:44:34 +00:00
< TouchableOpacity
2020-05-27 14:12:17 +03:00
disabled = { route . params . isLoading === true }
2020-05-24 12:17:26 +03:00
style = { styles . save }
2018-10-30 05:35:24 -04:00
onPress = { ( ) => {
2020-05-27 14:12:17 +03:00
if ( route . params . saveAction ) {
route . params . saveAction ( ) ;
2019-03-08 21:54:47 +00:00
}
2018-10-30 05:35:24 -04:00
} }
2018-11-09 23:44:34 +00:00
>
2020-05-24 12:17:26 +03:00
< Text style = { styles . saveText } > { loc . wallets . details . save } < / T e x t >
2018-11-09 23:44:34 +00:00
< / T o u c h a b l e O p a c i t y >
2018-10-30 05:35:24 -04:00
) ,
2018-10-29 18:11:48 -04:00
} ) ;
2018-01-30 22:42:38 +00:00
constructor ( props ) {
super ( props ) ;
2020-05-27 14:12:17 +03:00
const wallet = props . route . params . wallet ;
2019-01-11 23:01:15 -05:00
const isLoading = true ;
2018-01-30 22:42:38 +00:00
this . state = {
2019-01-11 23:01:15 -05:00
isLoading ,
2018-10-30 05:35:24 -04:00
walletName : wallet . getLabel ( ) ,
2018-03-17 22:39:21 +02:00
wallet ,
2020-02-26 14:39:19 +00:00
useWithHardwareWallet : wallet . useWithHardwareWalletEnabled ( ) ,
2018-03-17 22:39:21 +02:00
} ;
2019-01-11 23:01:15 -05:00
this . props . navigation . setParams ( { isLoading , saveAction : ( ) => this . setLabel ( ) } ) ;
2018-01-30 22:42:38 +00:00
}
2019-01-06 23:54:22 -05:00
componentDidMount ( ) {
2019-09-27 15:49:56 +01:00
console . log ( 'wallets/details componentDidMount' ) ;
2018-01-30 22:42:38 +00:00
this . setState ( {
isLoading : false ,
2018-03-17 22:39:21 +02:00
} ) ;
2019-01-11 23:01:15 -05:00
this . props . navigation . setParams ( { isLoading : false , saveAction : ( ) => this . setLabel ( ) } ) ;
2018-01-30 22:42:38 +00:00
}
2019-01-06 23:54:22 -05:00
setLabel ( ) {
2019-01-11 23:01:15 -05:00
this . props . navigation . setParams ( { isLoading : true } ) ;
2019-03-08 21:54:47 +00:00
this . setState ( { isLoading : true } , async ( ) => {
2020-01-19 15:17:06 -05:00
if ( this . state . walletName . trim ( ) . length > 0 ) {
this . state . wallet . setLabel ( this . state . walletName ) ;
}
2020-06-18 10:59:44 -04:00
await BlueApp . saveToDisk ( ) ;
EV ( EV . enum . TRANSACTIONS _COUNT _CHANGED ) ;
2019-01-06 23:54:22 -05:00
alert ( 'Wallet updated.' ) ;
this . props . navigation . goBack ( null ) ;
} ) ;
2018-01-30 22:42:38 +00:00
}
2019-08-30 00:45:08 -04:00
async presentWalletHasBalanceAlert ( ) {
ReactNativeHapticFeedback . trigger ( 'notificationWarning' , { ignoreAndroidSystemSettings : false } ) ;
const walletBalanceConfirmation = await prompt (
'Wallet Balance' ,
` This wallet has a balance. Before proceeding, please be aware that you will not be able to recover the funds without this wallet's seed phrase. In order to avoid accidental removal this wallet, please enter your wallet's balance of ${ this . state . wallet . getBalance ( ) } satoshis. ` ,
true ,
'plain-text' ,
) ;
if ( Number ( walletBalanceConfirmation ) === this . state . wallet . getBalance ( ) ) {
this . props . navigation . setParams ( { isLoading : true } ) ;
this . setState ( { isLoading : true } , async ( ) => {
BlueApp . deleteWallet ( this . state . wallet ) ;
ReactNativeHapticFeedback . trigger ( 'notificationSuccess' , { ignoreAndroidSystemSettings : false } ) ;
await BlueApp . saveToDisk ( ) ;
EV ( EV . enum . TRANSACTIONS _COUNT _CHANGED ) ;
EV ( EV . enum . WALLETS _COUNT _CHANGED ) ;
2020-05-29 22:10:43 +01:00
this . props . navigation . popToTop ( ) ;
2019-08-30 00:45:08 -04:00
} ) ;
} else {
ReactNativeHapticFeedback . trigger ( 'notificationError' , { ignoreAndroidSystemSettings : false } ) ;
this . setState ( { isLoading : false } , async ( ) => {
alert ( "The provided balance amount does not match this wallet's balance. Please, try again" ) ;
} ) ;
}
}
2019-09-27 15:49:56 +01:00
async onUseWithHardwareWalletSwitch ( value ) {
this . setState ( ( state , props ) => {
2020-06-01 15:54:23 +03:00
const wallet = state . wallet ;
2020-02-26 14:39:19 +00:00
wallet . setUseWithHardwareWalletEnabled ( value ) ;
2019-09-27 15:49:56 +01:00
return { useWithHardwareWallet : ! ! value , wallet } ;
} ) ;
}
2020-06-18 10:59:44 -04:00
onHideTransactionsInWalletsListSwitch = value => {
this . setState ( state => {
const wallet = state . wallet ;
wallet . setHideTransactionsInWalletsList ( ! value ) ;
return { wallet } ;
} ) ;
} ;
2020-04-16 13:41:12 +02:00
renderMarketplaceButton = ( ) => {
return Platform . select ( {
android : (
< BlueButton
onPress = { ( ) =>
this . props . navigation . navigate ( 'Marketplace' , {
fromWallet : this . state . wallet ,
} )
}
title = "Marketplace"
/ >
) ,
2020-04-30 16:31:29 +01:00
ios : (
< BlueButton
onPress = { async ( ) => {
Linking . openURL ( 'https://bluewallet.io/marketplace-btc/' ) ;
} }
title = "Marketplace"
/ >
) ,
2020-04-16 13:41:12 +02:00
} ) ;
} ;
2018-01-30 22:42:38 +00:00
render ( ) {
if ( this . state . isLoading ) {
return (
2020-05-24 12:17:26 +03:00
< View style = { styles . root } >
2018-01-30 22:42:38 +00:00
< ActivityIndicator / >
< / V i e w >
) ;
}
return (
2020-05-24 12:17:26 +03:00
< SafeBlueArea style = { styles . root } >
2020-06-10 23:54:47 -04:00
< StatusBar barStyle = "dark-content" / >
2018-12-11 22:52:46 +00:00
< TouchableWithoutFeedback onPress = { Keyboard . dismiss } accessible = { false } >
2020-01-02 16:06:51 -06:00
< KeyboardAvoidingView behavior = "position" >
2020-05-24 12:17:26 +03:00
< ScrollView contentContainerStyle = { styles . scrollViewContent } >
< BlueCard style = { styles . address } >
2020-01-02 16:06:51 -06:00
{ ( ( ) => {
2020-02-26 14:39:19 +00:00
if (
[ LegacyWallet . type , SegwitBech32Wallet . type , SegwitP2SHWallet . type ] . includes ( this . state . wallet . type ) ||
( this . state . wallet . type === WatchOnlyWallet . type && ! this . state . wallet . isHd ( ) )
) {
2020-01-02 16:06:51 -06:00
return (
2020-06-01 15:54:23 +03:00
< >
2020-05-24 12:17:26 +03:00
< Text style = { styles . textLabel1 } > { loc . wallets . details . address . toLowerCase ( ) } < / T e x t >
< Text style = { styles . textValue } > { this . state . wallet . getAddress ( ) } < / T e x t >
2020-06-01 15:54:23 +03:00
< / >
2020-01-02 16:06:51 -06:00
) ;
2019-01-25 01:12:07 -05:00
}
2020-01-02 16:06:51 -06:00
} ) ( ) }
2020-05-24 12:17:26 +03:00
< Text style = { styles . textLabel2 } > { loc . wallets . add . wallet _name . toLowerCase ( ) } < / T e x t >
2019-01-25 01:12:07 -05:00
2020-05-24 12:17:26 +03:00
< View style = { styles . input } >
2020-01-02 16:06:51 -06:00
< TextInput
placeholder = { loc . send . details . note _placeholder }
value = { this . state . walletName }
onChangeText = { text => {
this . setState ( { walletName : text } ) ;
} }
onBlur = { ( ) => {
if ( this . state . walletName . trim ( ) . length === 0 ) {
2020-01-04 19:03:02 -06:00
const walletLabel = this . state . wallet . getLabel ( ) ;
this . setState ( { walletName : walletLabel } ) ;
2020-01-02 16:06:51 -06:00
}
} }
numberOfLines = { 1 }
2020-06-09 08:23:21 -04:00
placeholderTextColor = "#81868e"
2020-05-24 12:17:26 +03:00
style = { styles . inputText }
2020-01-02 16:06:51 -06:00
editable = { ! this . state . isLoading }
underlineColorAndroid = "transparent"
/ >
< / V i e w >
2019-01-25 01:12:07 -05:00
< BlueSpacing20 / >
2020-05-24 12:17:26 +03:00
< Text style = { styles . textLabel1 } > { loc . wallets . details . type . toLowerCase ( ) } < / T e x t >
< Text style = { styles . textValue } > { this . state . wallet . typeReadable } < / T e x t >
2020-01-02 16:06:51 -06:00
{ this . state . wallet . type === LightningCustodianWallet . type && (
2020-06-01 15:54:23 +03:00
< >
2020-05-24 12:17:26 +03:00
< Text style = { styles . textLabel1 } > { loc . wallets . details . connected _to . toLowerCase ( ) } < / T e x t >
2020-01-02 16:06:51 -06:00
< BlueText > { this . state . wallet . getBaseURI ( ) } < / B l u e T e x t >
2020-06-01 15:54:23 +03:00
< / >
2019-01-25 01:12:07 -05:00
) }
2020-06-18 10:59:44 -04:00
< >
< Text style = { styles . textLabel2 } > { loc . transactions . list . title . toLowerCase ( ) } < / T e x t >
< View style = { styles . hardware } >
< BlueText > display in wallets list < / B l u e T e x t >
< Switch
value = { ! this . state . wallet . getHideTransactionsInWalletsList ( ) }
onValueChange = { this . onHideTransactionsInWalletsListSwitch }
/ >
< / V i e w >
< / >
2020-01-02 16:06:51 -06:00
< View >
< BlueSpacing20 / >
{ this . state . wallet . type === WatchOnlyWallet . type && this . state . wallet . getSecret ( ) . startsWith ( 'zpub' ) && (
< >
2020-05-24 12:17:26 +03:00
< Text style = { styles . textLabel2 } > { loc . wallets . details . advanced . toLowerCase ( ) } < / T e x t >
< View style = { styles . hardware } >
2020-05-08 16:49:54 +01:00
< BlueText > { loc . wallets . details . use _with _hardware _wallet } < / B l u e T e x t >
2020-01-02 16:06:51 -06:00
< Switch
value = { this . state . useWithHardwareWallet }
onValueChange = { value => this . onUseWithHardwareWalletSwitch ( value ) }
/ >
< / V i e w >
2020-06-01 15:54:23 +03:00
< >
2020-05-24 12:17:26 +03:00
< Text style = { styles . textLabel1 } > { loc . wallets . details . master _fingerprint . toLowerCase ( ) } < / T e x t >
< Text style = { styles . textValue } > { this . state . wallet . getMasterFingerprintHex ( ) } < / T e x t >
2020-06-01 15:54:23 +03:00
< / >
2020-01-02 16:06:51 -06:00
< BlueSpacing20 / >
< / >
) }
2018-12-11 22:52:46 +00:00
2018-12-28 16:53:02 +01:00
< BlueButton
onPress = { ( ) =>
2020-01-02 16:06:51 -06:00
this . props . navigation . navigate ( 'WalletExport' , {
2020-03-12 17:26:05 +00:00
wallet : this . state . wallet ,
2018-12-28 16:53:02 +01:00
} )
}
2020-01-02 16:06:51 -06:00
title = { loc . wallets . details . export _backup }
2018-12-28 16:53:02 +01:00
/ >
2020-01-02 16:06:51 -06:00
< BlueSpacing20 / >
2019-10-16 21:33:00 -04:00
2020-01-02 16:06:51 -06:00
{ ( this . state . wallet . type === HDLegacyBreadwalletWallet . type ||
this . state . wallet . type === HDLegacyP2PKHWallet . type ||
this . state . wallet . type === HDSegwitBech32Wallet . type ||
this . state . wallet . type === HDSegwitP2SHWallet . type ) && (
2020-06-01 15:54:23 +03:00
< >
2020-01-02 16:06:51 -06:00
< BlueButton
onPress = { ( ) =>
this . props . navigation . navigate ( 'WalletXpub' , {
secret : this . state . wallet . getSecret ( ) ,
} )
}
title = { loc . wallets . details . show _xpub }
/ >
< BlueSpacing20 / >
2020-04-16 13:41:12 +02:00
{ this . renderMarketplaceButton ( ) }
2020-06-01 15:54:23 +03:00
< / >
2020-01-02 16:06:51 -06:00
) }
2020-04-30 16:31:29 +01:00
{ this . state . wallet . type !== LightningCustodianWallet . type && (
2020-06-01 15:54:23 +03:00
< >
2020-04-30 16:31:29 +01:00
< BlueSpacing20 / >
2020-04-29 18:00:11 +02:00
< BlueButton onPress = { ( ) => this . props . navigation . navigate ( 'Broadcast' ) } title = "Broadcast transaction" / >
2020-06-01 15:54:23 +03:00
< / >
2020-04-30 16:31:29 +01:00
) }
2020-01-02 16:06:51 -06:00
< BlueSpacing20 / >
< TouchableOpacity
2020-05-24 12:17:26 +03:00
style = { styles . center }
2020-01-02 16:06:51 -06:00
onPress = { ( ) => {
ReactNativeHapticFeedback . trigger ( 'notificationWarning' , { ignoreAndroidSystemSettings : false } ) ;
Alert . alert (
loc . wallets . details . delete + ' ' + loc . wallets . details . title ,
loc . wallets . details . are _you _sure ,
[
{
text : loc . wallets . details . yes _delete ,
onPress : async ( ) => {
const isBiometricsEnabled = await Biometric . isBiometricUseCapableAndEnabled ( ) ;
if ( isBiometricsEnabled ) {
if ( ! ( await Biometric . unlockWithBiometrics ( ) ) ) {
return ;
}
}
2020-02-24 21:45:14 +00:00
if ( this . state . wallet . getBalance ( ) > 0 && this . state . wallet . allowSend ( ) ) {
this . presentWalletHasBalanceAlert ( ) ;
} else {
this . props . navigation . setParams ( { isLoading : true } ) ;
this . setState ( { isLoading : true } , async ( ) => {
BlueApp . deleteWallet ( this . state . wallet ) ;
ReactNativeHapticFeedback . trigger ( 'notificationSuccess' , { ignoreAndroidSystemSettings : false } ) ;
await BlueApp . saveToDisk ( ) ;
EV ( EV . enum . TRANSACTIONS _COUNT _CHANGED ) ;
EV ( EV . enum . WALLETS _COUNT _CHANGED ) ;
2020-05-29 22:10:43 +01:00
this . props . navigation . popToTop ( ) ;
2020-02-24 21:45:14 +00:00
} ) ;
}
} ,
2020-05-27 23:15:00 -04:00
style : 'destructive' ,
2019-01-25 01:12:07 -05:00
} ,
2020-01-02 16:06:51 -06:00
{ text : loc . wallets . details . no _cancel , onPress : ( ) => { } , style : 'cancel' } ,
] ,
{ cancelable : false } ,
) ;
} }
>
2020-05-24 12:17:26 +03:00
< Text style = { styles . delete } > { loc . wallets . details . delete } < / T e x t >
2020-01-02 16:06:51 -06:00
< / T o u c h a b l e O p a c i t y >
< / V i e w >
< / B l u e C a r d >
< / S c r o l l V i e w >
< / K e y b o a r d A v o i d i n g V i e w >
2018-12-11 22:52:46 +00:00
< / T o u c h a b l e W i t h o u t F e e d b a c k >
2018-01-30 22:42:38 +00:00
< / S a f e B l u e A r e a >
) ;
}
}
2018-03-18 02:48:23 +00:00
WalletDetails . propTypes = {
navigation : PropTypes . shape ( {
state : PropTypes . shape ( {
params : PropTypes . shape ( {
2018-07-22 15:49:59 +01:00
secret : PropTypes . string ,
2018-03-18 02:48:23 +00:00
} ) ,
} ) ,
navigate : PropTypes . func ,
goBack : PropTypes . func ,
2020-05-29 22:10:43 +01:00
popToTop : PropTypes . func ,
2018-10-30 05:35:24 -04:00
setParams : PropTypes . func ,
2018-03-18 02:48:23 +00:00
} ) ,
2020-05-27 14:12:17 +03:00
route : PropTypes . shape ( {
params : PropTypes . object ,
} ) ,
2018-03-18 02:48:23 +00:00
} ;