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