2018-01-30 22:42:38 +00:00
import React , { Component } from 'react' ;
2019-02-16 20:22:14 -05:00
import { View , TouchableOpacity , Text , FlatList , InteractionManager , RefreshControl , ScrollView } from 'react-native' ;
import { BlueLoading , SafeBlueArea , WalletsCarousel , BlueList , BlueHeaderDefaultMain , BlueTransactionListItem } from '../../BlueComponents' ;
2018-09-01 00:28:19 +01:00
import { Icon } from 'react-native-elements' ;
2018-12-11 22:52:46 +00:00
import { NavigationEvents } from 'react-navigation' ;
2018-12-18 01:05:03 -05:00
import ReactNativeHapticFeedback from 'react-native-haptic-feedback' ;
2018-03-18 02:48:23 +00:00
import PropTypes from 'prop-types' ;
2019-01-24 23:46:03 -05:00
import WalletGradient from '../../class/walletGradient' ;
2018-03-17 22:39:21 +02:00
let EV = require ( '../../events' ) ;
2019-01-10 15:04:16 +00:00
let A = require ( '../../analytics' ) ;
2018-03-18 02:48:23 +00:00
/** @type {AppStorage} */
let BlueApp = require ( '../../BlueApp' ) ;
2018-05-28 20:18:11 +01:00
let loc = require ( '../../loc' ) ;
2019-03-16 12:48:17 +00:00
let BlueElectrum = require ( '../../BlueElectrum' ) ;
2018-01-30 22:42:38 +00:00
export default class WalletsList extends Component {
2018-09-30 05:56:32 -04:00
static navigationOptions = ( { navigation } ) => ( {
headerStyle : {
backgroundColor : '#FFFFFF' ,
borderBottomWidth : 0 ,
2018-12-11 22:52:46 +00:00
elevation : 0 ,
2018-09-18 21:59:16 -04:00
} ,
2018-09-30 05:56:32 -04:00
headerRight : (
2018-12-14 11:40:38 -05:00
< TouchableOpacity
2018-12-15 22:10:30 -05:00
style = { { marginHorizontal : 16 , width : 40 , height : 40 , justifyContent : 'center' , alignItems : 'flex-end' } }
2018-12-14 11:40:38 -05:00
onPress = { ( ) => navigation . navigate ( 'Settings' ) }
>
2019-07-12 11:49:42 -04:00
< Icon size = { 22 } name = "kebab-horizontal" type = "octicon" color = { BlueApp . settings . foregroundColor } / >
2018-09-30 05:56:32 -04:00
< / T o u c h a b l e O p a c i t y >
) ,
} ) ;
2018-01-30 22:42:38 +00:00
constructor ( props ) {
super ( props ) ;
this . state = {
isLoading : true ,
2019-02-16 20:22:14 -05:00
isFlatListRefreshControlHidden : true ,
2018-12-11 22:52:46 +00:00
wallets : BlueApp . getWallets ( ) . concat ( false ) ,
2018-12-27 01:12:19 -05:00
lastSnappedTo : 0 ,
2018-03-17 22:39:21 +02:00
} ;
2019-02-16 20:22:14 -05:00
EV ( EV . enum . WALLETS _COUNT _CHANGED , this . redrawScreen . bind ( this ) ) ;
2018-10-09 00:25:36 -04:00
// here, when we receive TRANSACTIONS_COUNT_CHANGED we do not query
// remote server, we just redraw the screen
2019-02-16 20:22:14 -05:00
EV ( EV . enum . TRANSACTIONS _COUNT _CHANGED , this . redrawScreen . bind ( this ) ) ;
2018-01-30 22:42:38 +00:00
}
2018-12-11 22:52:46 +00:00
componentDidMount ( ) {
2019-02-16 20:22:14 -05:00
this . redrawScreen ( ) ;
2019-03-16 12:48:17 +00:00
// the idea is that upon wallet launch we will refresh
// all balances and all transactions here:
InteractionManager . runAfterInteractions ( async ( ) => {
let noErr = true ;
try {
await BlueElectrum . waitTillConnected ( ) ;
let balanceStart = + new Date ( ) ;
await BlueApp . fetchWalletBalances ( ) ;
let balanceEnd = + new Date ( ) ;
console . log ( 'fetch all wallet balances took' , ( balanceEnd - balanceStart ) / 1000 , 'sec' ) ;
let start = + new Date ( ) ;
await BlueApp . fetchWalletTransactions ( ) ;
let end = + new Date ( ) ;
console . log ( 'fetch all wallet txs took' , ( end - start ) / 1000 , 'sec' ) ;
} catch ( _ ) {
noErr = false ;
}
if ( noErr ) this . redrawScreen ( ) ;
} ) ;
2018-10-09 00:25:36 -04:00
}
2018-01-30 22:42:38 +00:00
2018-07-02 12:09:34 +01:00
/ * *
2018-12-25 19:07:43 +00:00
* Forcefully fetches TXs and balance for lastSnappedTo ( i . e . current ) wallet .
* Triggered manually by user on pull - to - refresh .
2018-07-02 12:09:34 +01:00
* /
2018-06-24 23:22:46 +01:00
refreshTransactions ( ) {
2019-02-16 20:22:14 -05:00
if ( ! ( this . lastSnappedTo < BlueApp . getWallets ( ) . length ) && this . lastSnappedTo !== undefined ) {
2018-10-09 00:25:36 -04:00
// last card, nop
console . log ( 'last card, nop' ) ;
return ;
}
2018-03-17 22:39:21 +02:00
this . setState (
2018-06-24 23:22:46 +01:00
{
2019-02-23 20:16:18 +00:00
isFlatListRefreshControlHidden : false ,
2018-06-24 23:22:46 +01:00
} ,
2019-02-16 20:22:14 -05:00
( ) => {
InteractionManager . runAfterInteractions ( async ( ) => {
2018-06-24 23:22:46 +01:00
let noErr = true ;
try {
2019-07-13 16:21:03 +01:00
await BlueElectrum . ping ( ) ;
await BlueElectrum . waitTillConnected ( ) ;
2019-01-29 02:27:07 +00:00
let balanceStart = + new Date ( ) ;
2019-02-16 20:22:14 -05:00
await BlueApp . fetchWalletBalances ( this . lastSnappedTo || 0 ) ;
2019-01-29 02:27:07 +00:00
let balanceEnd = + new Date ( ) ;
console . log ( 'fetch balance took' , ( balanceEnd - balanceStart ) / 1000 , 'sec' ) ;
2018-07-22 15:49:59 +01:00
let start = + new Date ( ) ;
2019-02-16 20:22:14 -05:00
await BlueApp . fetchWalletTransactions ( this . lastSnappedTo || 0 ) ;
2018-07-22 15:49:59 +01:00
let end = + new Date ( ) ;
2018-10-09 00:25:36 -04:00
console . log ( 'fetch tx took' , ( end - start ) / 1000 , 'sec' ) ;
2018-06-24 23:22:46 +01:00
} catch ( err ) {
noErr = false ;
console . warn ( err ) ;
}
if ( noErr ) await BlueApp . saveToDisk ( ) ; // caching
2019-02-16 20:22:14 -05:00
this . redrawScreen ( ) ;
} ) ;
2018-06-24 23:22:46 +01:00
} ,
) ;
}
2019-02-16 20:22:14 -05:00
redrawScreen ( ) {
console . log ( 'wallets/list redrawScreen()' ) ;
2019-01-10 15:04:16 +00:00
if ( BlueApp . getBalance ( ) !== 0 ) {
A ( A . ENUM . GOT _NONZERO _BALANCE ) ;
}
2018-07-06 16:41:48 +01:00
2018-10-09 00:25:36 -04:00
this . setState ( {
isLoading : false ,
2019-02-16 20:22:14 -05:00
isFlatListRefreshControlHidden : true ,
2019-02-18 23:37:53 +00:00
dataSource : BlueApp . getTransactions ( null , 10 ) ,
2018-12-11 22:52:46 +00:00
wallets : BlueApp . getWallets ( ) . concat ( false ) ,
2018-10-09 00:25:36 -04:00
} ) ;
2018-06-24 23:22:46 +01:00
}
txMemo ( hash ) {
if ( BlueApp . tx _metadata [ hash ] && BlueApp . tx _metadata [ hash ] [ 'memo' ] ) {
2018-06-28 02:43:28 +01:00
return BlueApp . tx _metadata [ hash ] [ 'memo' ] ;
2018-06-24 23:22:46 +01:00
}
return '' ;
}
2019-01-24 23:46:03 -05:00
handleClick ( index ) {
2018-10-09 00:25:36 -04:00
console . log ( 'click' , index ) ;
2018-06-24 23:22:46 +01:00
let wallet = BlueApp . wallets [ index ] ;
if ( wallet ) {
2018-10-09 00:25:36 -04:00
this . props . navigation . navigate ( 'WalletTransactions' , {
wallet : wallet ,
2019-01-24 23:46:03 -05:00
headerColor : WalletGradient . headerColorFor ( wallet . type ) ,
2018-06-24 23:22:46 +01:00
} ) ;
} else {
// if its out of index - this must be last card with incentive to create wallet
this . props . navigation . navigate ( 'AddWallet' ) ;
}
}
onSnapToItem ( index ) {
console . log ( 'onSnapToItem' , index ) ;
this . lastSnappedTo = index ;
2018-12-27 01:12:19 -05:00
this . setState ( { lastSnappedTo : index } ) ;
2018-06-24 23:22:46 +01:00
if ( index < BlueApp . getWallets ( ) . length ) {
2018-10-09 00:25:36 -04:00
// not the last
2018-06-24 23:22:46 +01:00
}
2018-07-02 14:51:24 +01:00
// now, lets try to fetch balance and txs for this wallet in case it has changed
this . lazyRefreshWallet ( index ) ;
}
/ * *
* Decides whether wallet with such index shoud be refreshed ,
* refreshes if yes and redraws the screen
* @ param index { Integer } Index of the wallet .
* @ return { Promise . < void > }
* /
async lazyRefreshWallet ( index ) {
/** @type {Array.<AbstractWallet>} wallets */
let wallets = BlueApp . getWallets ( ) ;
2018-07-05 01:56:31 +01:00
if ( ! wallets [ index ] ) {
return ;
}
2018-10-09 00:25:36 -04:00
2018-07-02 14:51:24 +01:00
let oldBalance = wallets [ index ] . getBalance ( ) ;
let noErr = true ;
2018-07-14 21:32:36 +01:00
let didRefresh = false ;
2018-07-02 14:51:24 +01:00
try {
2018-07-14 21:32:36 +01:00
if ( wallets && wallets [ index ] && wallets [ index ] . timeToRefreshBalance ( ) ) {
2018-07-02 14:51:24 +01:00
console . log ( 'snapped to, and now its time to refresh wallet #' , index ) ;
await wallets [ index ] . fetchBalance ( ) ;
2018-07-07 14:04:32 +01:00
if ( oldBalance !== wallets [ index ] . getBalance ( ) || wallets [ index ] . getUnconfirmedBalance ( ) !== 0 ) {
2018-07-05 01:56:31 +01:00
console . log ( 'balance changed, thus txs too' ) ;
2018-07-02 14:51:24 +01:00
// balance changed, thus txs too
await wallets [ index ] . fetchTransactions ( ) ;
2019-02-16 20:22:14 -05:00
this . redrawScreen ( ) ;
2018-07-14 21:32:36 +01:00
didRefresh = true ;
} else if ( wallets [ index ] . timeToRefreshTransaction ( ) ) {
2018-09-01 00:28:19 +01:00
console . log ( wallets [ index ] . getLabel ( ) , 'thinks its time to refresh TXs' ) ;
2018-07-14 21:32:36 +01:00
await wallets [ index ] . fetchTransactions ( ) ;
2018-09-01 00:28:19 +01:00
if ( wallets [ index ] . fetchPendingTransactions ) {
await wallets [ index ] . fetchPendingTransactions ( ) ;
}
2018-12-25 19:07:43 +00:00
if ( wallets [ index ] . fetchUserInvoices ) {
await wallets [ index ] . fetchUserInvoices ( ) ;
2019-06-01 21:45:01 +01:00
await wallets [ index ] . fetchBalance ( ) ; // chances are, paid ln invoice was processed during `fetchUserInvoices()` call and altered user's balance, so its worth fetching balance again
2018-12-25 19:07:43 +00:00
}
2019-02-16 20:22:14 -05:00
this . redrawScreen ( ) ;
2018-07-14 21:32:36 +01:00
didRefresh = true ;
2018-07-03 21:11:02 +01:00
} else {
2018-07-05 01:56:31 +01:00
console . log ( 'balance not changed' ) ;
2018-07-02 14:51:24 +01:00
}
}
} catch ( Err ) {
noErr = false ;
console . warn ( Err ) ;
}
2018-07-14 21:32:36 +01:00
if ( noErr && didRefresh ) {
2018-07-02 14:51:24 +01:00
await BlueApp . saveToDisk ( ) ; // caching
}
2018-01-30 22:42:38 +00:00
}
2018-12-11 22:52:46 +00:00
_keyExtractor = ( _item , index ) => index . toString ( ) ;
2018-09-18 03:24:42 -04:00
2018-10-09 00:25:36 -04:00
renderListHeaderComponent = ( ) => {
return (
< View >
< Text
style = { {
paddingLeft : 15 ,
fontWeight : 'bold' ,
fontSize : 24 ,
marginVertical : 8 ,
color : BlueApp . settings . foregroundColor ,
} }
>
{ loc . transactions . list . title }
< / T e x t >
< / V i e w >
) ;
} ;
2018-12-11 22:52:46 +00:00
handleLongPress = ( ) => {
if ( BlueApp . getWallets ( ) . length > 1 ) {
this . props . navigation . navigate ( 'ReorderWallets' ) ;
2018-12-18 01:05:03 -05:00
} else {
2019-05-03 13:36:11 +01:00
ReactNativeHapticFeedback . trigger ( 'notificationError' , { ignoreAndroidSystemSettings : false } ) ;
2018-12-11 22:52:46 +00:00
}
} ;
2019-02-16 20:22:14 -05:00
_renderItem = data => {
return < BlueTransactionListItem item = { data . item } itemPriceUnit = { data . item . walletPreferredBalanceUnit } / > ;
} ;
2018-01-30 22:42:38 +00:00
render ( ) {
if ( this . state . isLoading ) {
2018-03-17 22:39:21 +02:00
return < BlueLoading / > ;
2018-01-30 22:42:38 +00:00
}
return (
2018-10-09 00:25:36 -04:00
< SafeBlueArea style = { { flex : 1 , backgroundColor : '#FFFFFF' } } >
2018-12-11 22:33:28 -05:00
< NavigationEvents
onWillFocus = { ( ) => {
2019-02-16 20:22:14 -05:00
this . redrawScreen ( ) ;
2018-12-11 22:33:28 -05:00
} }
/ >
2018-10-09 00:25:36 -04:00
< ScrollView
2019-02-16 20:22:14 -05:00
refreshControl = {
< RefreshControl onRefresh = { ( ) => this . refreshTransactions ( ) } refreshing = { ! this . state . isFlatListRefreshControlHidden } / >
}
2018-09-30 23:12:42 -04:00
>
2018-10-09 00:25:36 -04:00
< BlueHeaderDefaultMain leftText = { loc . wallets . list . title } onNewWalletPress = { ( ) => this . props . navigation . navigate ( 'AddWallet' ) } / >
< WalletsCarousel
2018-12-11 22:52:46 +00:00
data = { this . state . wallets }
2019-01-24 23:46:03 -05:00
handleClick = { index => {
this . handleClick ( index ) ;
2018-10-09 00:25:36 -04:00
} }
2018-12-11 22:52:46 +00:00
handleLongPress = { this . handleLongPress }
2018-10-09 00:25:36 -04:00
onSnapToItem = { index => {
this . onSnapToItem ( index ) ;
} }
/ >
< BlueList >
< FlatList
ListHeaderComponent = { this . renderListHeaderComponent }
2018-10-10 20:36:32 +01:00
ListEmptyComponent = {
< View style = { { top : 50 , height : 100 } } >
< Text
style = { {
fontSize : 18 ,
color : '#9aa0aa' ,
textAlign : 'center' ,
} }
>
{ loc . wallets . list . empty _txs1 }
< / T e x t >
< Text
style = { {
fontSize : 18 ,
color : '#9aa0aa' ,
textAlign : 'center' ,
} }
>
{ loc . wallets . list . empty _txs2 }
< / T e x t >
< / V i e w >
}
2018-10-09 00:25:36 -04:00
data = { this . state . dataSource }
extraData = { this . state . dataSource }
keyExtractor = { this . _keyExtractor }
2019-01-31 01:52:21 -05:00
renderItem = { this . _renderItem }
2018-10-09 00:25:36 -04:00
/ >
< / B l u e L i s t >
< / S c r o l l V i e w >
2018-01-30 22:42:38 +00:00
< / S a f e B l u e A r e a >
) ;
}
2018-03-17 22:39:21 +02:00
}
2018-03-18 02:48:23 +00:00
WalletsList . propTypes = {
navigation : PropTypes . shape ( {
navigate : PropTypes . func ,
} ) ,
} ;