import React, { Component } from 'react'; import { Text, View, Image, FlatList, RefreshControl, TouchableOpacity, StatusBar } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; import PropTypes from 'prop-types'; import { NavigationEvents } from 'react-navigation'; import { BlueText, ManageFundsBigButton, BlueSendButtonIcon, BlueReceiveButtonIcon, BlueTransactionListItem } from '../../BlueComponents'; import { Icon } from 'react-native-elements'; import { BitcoinUnit } from '../../models/bitcoinUnits'; import { LightningCustodianWallet } from '../../class'; import WalletGradient from '../../class/walletGradient'; /** @type {AppStorage} */ let BlueApp = require('../../BlueApp'); let loc = require('../../loc'); let EV = require('../../events'); export default class WalletTransactions extends Component { static navigationOptions = ({ navigation }) => { return { headerRight: ( navigation.navigate('WalletDetails', { wallet: navigation.state.params.wallet, }) } > {loc.wallets.options} ), headerStyle: { backgroundColor: navigation.getParam('headerColor'), borderBottomWidth: 0, elevation: 0, shadowRadius: 0, }, headerTintColor: '#FFFFFF', }; }; constructor(props) { super(props); // here, when we receive REMOTE_TRANSACTIONS_COUNT_CHANGED we fetch TXs and balance for current wallet EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED, this.refreshTransactionsFunction.bind(this)); const wallet = props.navigation.getParam('wallet'); this.props.navigation.setParams({ wallet: wallet }); this.state = { isLoading: true, isTransactionsLoading: false, wallet: wallet, dataSource: wallet.getTransactions(), walletPreviousPreferredUnit: wallet.getPreferredBalanceUnit(), }; } componentDidMount() { this.refreshFunction(); } /** * Forcefully fetches TXs and balance for wallet */ refreshTransactionsFunction() { let that = this; setTimeout(function() { that.refreshTransactions(); }, 4000); // giving a chance to remote server to propagate } /** * Redraws the screen */ refreshFunction() { setTimeout(() => { console.log('wallets/transactions refreshFunction()'); let showSend = false; let showReceive = false; const wallet = this.state.wallet; if (wallet) { showSend = wallet.allowSend(); showReceive = wallet.allowReceive(); } let showManageFundsBigButton = false; let showManageFundsSmallButton = false; if (wallet && wallet.type === LightningCustodianWallet.type && wallet.getBalance() * 1 <= 0) { showManageFundsBigButton = true; showManageFundsSmallButton = false; } else if (wallet && wallet.type === LightningCustodianWallet.type && wallet.getBalance() > 0) { showManageFundsSmallButton = true; showManageFundsBigButton = false; } let txs = wallet.getTransactions(); for (let tx of txs) { tx.sort_ts = +new Date(tx.received); } txs = txs.sort(function(a, b) { return b.sort_ts - a.sort_ts; }); this.setState({ isLoading: false, isTransactionsLoading: false, showReceiveButton: showReceive, showSendButton: showSend, showManageFundsBigButton, showManageFundsSmallButton, dataSource: txs, }); }, 1); } isLightning() { let w = this.state.wallet; if (w && w.type === LightningCustodianWallet.type) { return true; } return false; } /** * Forcefully fetches TXs and balance for wallet */ refreshTransactions() { this.setState( { isTransactionsLoading: true, }, async function() { let that = this; setTimeout(async function() { // more responsive let noErr = true; let smthChanged = false; try { /** @type {LegacyWallet} */ let wallet = that.state.wallet; let balanceStart = +new Date(); const oldBalance = wallet.getBalance(); await wallet.fetchBalance(); if (oldBalance !== wallet.getBalance()) smthChanged = true; let balanceEnd = +new Date(); console.log(wallet.getLabel(), 'fetch balance took', (balanceEnd - balanceStart) / 1000, 'sec'); let start = +new Date(); const oldTxLen = wallet.getTransactions().length; await wallet.fetchTransactions(); if (oldTxLen !== wallet.getTransactions().length) smthChanged = true; if (wallet.fetchPendingTransactions) { await wallet.fetchPendingTransactions(); } if (wallet.fetchUserInvoices) { await wallet.fetchUserInvoices(); } let end = +new Date(); console.log(wallet.getLabel(), 'fetch tx took', (end - start) / 1000, 'sec'); } catch (err) { noErr = false; console.warn(err); } if (noErr && smthChanged) { console.log('saving to disk'); await BlueApp.saveToDisk(); // caching EV(EV.enum.TRANSACTIONS_COUNT_CHANGED); // let other components know they should redraw } that.refreshFunction(); // Redraws the screen }, 1); }, ); } changeWalletBalanceUnit() { let walletPreviousPreferredUnit = this.state.wallet.getPreferredBalanceUnit(); const wallet = this.state.wallet; if (walletPreviousPreferredUnit === BitcoinUnit.BTC) { wallet.preferredBalanceUnit = BitcoinUnit.SATS; walletPreviousPreferredUnit = BitcoinUnit.BTC; } else if (walletPreviousPreferredUnit === BitcoinUnit.SATS) { wallet.preferredBalanceUnit = BitcoinUnit.LOCAL_CURRENCY; walletPreviousPreferredUnit = BitcoinUnit.SATS; } else if (walletPreviousPreferredUnit === BitcoinUnit.LOCAL_CURRENCY) { wallet.preferredBalanceUnit = BitcoinUnit.BTC; walletPreviousPreferredUnit = BitcoinUnit.BTC; } else { wallet.preferredBalanceUnit = BitcoinUnit.BTC; walletPreviousPreferredUnit = BitcoinUnit.BTC; } this.setState({ wallet: wallet, walletPreviousPreferredUnit: walletPreviousPreferredUnit }); } renderWalletHeader = () => { return ( {this.state.wallet.getLabel()} this.changeWalletBalanceUnit()}> {loc.formatBalance(this.state.wallet.getBalance(), this.state.wallet.getPreferredBalanceUnit(), true).toString()} {loc.wallets.list.latest_transaction} {loc.transactionTimeToReadable(this.state.wallet.getLatestTransactionTime())} ); }; _keyExtractor = (_item, index) => index.toString(); renderListHeaderComponent = () => { return ( {loc.transactions.list.title} ); }; async onWillBlur() { StatusBar.setBarStyle('dark-content'); await BlueApp.saveToDisk(); } componentWillUnmount() { this.onWillBlur(); } renderItem = item => { return ; }; render() { const { navigate } = this.props.navigation; return ( { StatusBar.setBarStyle('light-content'); this.refreshFunction(); }} onWillBlur={() => this.onWillBlur()} /> {this.renderWalletHeader()} {(() => { if (this.state.showManageFundsSmallButton) { return ( { console.log('navigating to LappBrowser'); navigate('LappBrowser', { fromSecret: this.state.wallet.getSecret(), fromWallet: this.state.wallet }); }} > marketplace { console.log('navigating to', this.state.wallet.getLabel()); navigate('ManageFunds', { fromWallet: this.state.wallet }); }} > {loc.lnd.title} ); } })()} {(this.isLightning() && 'Lightning wallet should be used for your daily transactions. Fees are unfairly cheap and speed is blazing fast.') || loc.wallets.list.empty_txs1} {(this.isLightning() && '\nTo start using it tap on "manage funds" and topup your balance') || loc.wallets.list.empty_txs2} {!this.isLightning() && ( this.props.navigation.navigate('BuyBitcoin', { address: this.state.wallet.getAddress(), secret: this.state.wallet.getSecret(), }) } > {loc.wallets.list.tap_here_to_buy} )} } refreshControl={ this.refreshTransactions()} refreshing={this.state.isTransactionsLoading} />} data={this.state.dataSource} keyExtractor={this._keyExtractor} initialNumToRender={10} renderItem={this.renderItem} /> {(() => { if (this.state.showReceiveButton) { return ( { if (this.state.wallet.type === new LightningCustodianWallet().type) { navigate('LNDCreateInvoice', { fromWallet: this.state.wallet }); } else { navigate('ReceiveDetails', { address: this.state.wallet.getAddress(), secret: this.state.wallet.getSecret() }); } }} /> ); } })()} {(() => { if (this.state.showSendButton) { return ( { if (this.state.wallet.type === LightningCustodianWallet.type) { navigate('ScanLndInvoice', { fromSecret: this.state.wallet.getSecret() }); } else { navigate('SendDetails', { fromAddress: this.state.wallet.getAddress(), fromSecret: this.state.wallet.getSecret() }); } }} /> ); } })()} {(() => { if (this.state.showManageFundsBigButton) { return ( { console.log('navigating to', this.state.wallet.getLabel()); navigate('ManageFunds', { fromWallet: this.state.wallet }); }} /> ); } })()} ); } } WalletTransactions.propTypes = { navigation: PropTypes.shape({ navigate: PropTypes.func, goBack: PropTypes.func, getParam: PropTypes.func, setParams: PropTypes.func, }), };