From 2cb56b51e9631a6ddd2fae3af6ebce740aa5d806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Rodriguez=20Ve=CC=81lez?= Date: Tue, 29 Jan 2019 21:13:45 -0500 Subject: [PATCH] ADD: Create BlueTransactionListItem --- BlueComponents.js | 200 +++++++++++++++++++++++++++- index.js | 6 +- screen/wallets/list.js | 233 ++++----------------------------- screen/wallets/transactions.js | 179 +------------------------ 4 files changed, 234 insertions(+), 384 deletions(-) diff --git a/BlueComponents.js b/BlueComponents.js index 18571d62..31cf6e60 100644 --- a/BlueComponents.js +++ b/BlueComponents.js @@ -988,6 +988,195 @@ export class NewWalletPanel extends Component { } } +export class BlueTransactionListItem extends Component { + static propTypes = { + item: PropTypes.shape().isRequired, + itemPriceUnit: PropTypes.string, + }; + + static defaultProps = { + itemPriceUnit: BitcoinUnit.BTC, + }; + + txMemo = () => { + if (BlueApp.tx_metadata[this.props.item.hash] && BlueApp.tx_metadata[this.props.item.hash]['memo']) { + return BlueApp.tx_metadata[this.props.item.hash]['memo']; + } + return ''; + }; + + rowTitle = () => { + const item = this.props.item; + if (item.type === 'user_invoice' || item.type === 'payment_request') { + if (isNaN(item.value)) { + item.value = '0'; + } + const currentDate = new Date(); + const now = (currentDate.getTime() / 1000) | 0; + const invoiceExpiration = item.timestamp + item.expire_time; + + if (invoiceExpiration > now) { + return loc.formatBalanceWithoutSuffix(item.value && item.value, this.props.itemPriceUnit, true).toString(); + } else if (invoiceExpiration < now) { + if (item.ispaid) { + return loc.formatBalanceWithoutSuffix(item.value && item.value, this.props.itemPriceUnit, true).toString(); + } else { + return loc.lnd.expired; + } + } + } else { + return loc.formatBalanceWithoutSuffix(item.value && item.value, this.props.itemPriceUnit, true).toString(); + } + }; + + rowTitleStyle = () => { + const item = this.props.item; + let color = '#37c0a1'; + + if (item.type === 'user_invoice' || item.type === 'payment_request') { + const currentDate = new Date(); + const now = (currentDate.getTime() / 1000) | 0; + const invoiceExpiration = item.timestamp + item.expire_time; + + if (invoiceExpiration > now) { + color = '#37c0a1'; + } else if (invoiceExpiration < now) { + if (item.ispaid) { + color = '#37c0a1'; + } else { + color = '#FF0000'; + } + } + } else if (item.value / 100000000 < 0) { + color = BlueApp.settings.foregroundColor; + } + + return { + fontWeight: '600', + fontSize: 16, + color: color, + }; + }; + + avatar = () => { + // is it lightning refill tx? + if (this.props.item.category === 'receive' && this.props.item.confirmations < 3) { + return ( + + + + ); + } + + if (this.props.item.type && this.props.item.type === 'bitcoind_tx') { + return ( + + + + ); + } + if (this.props.item.type === 'paid_invoice') { + // is it lightning offchain payment? + return ( + + + + ); + } + + if (this.props.item.type === 'user_invoice' || this.props.item.type === 'payment_request') { + if (!this.props.item.ispaid) { + const currentDate = new Date(); + const now = (currentDate.getTime() / 1000) | 0; + const invoiceExpiration = this.props.item.timestamp + this.props.item.expire_time; + if (invoiceExpiration < now) { + return ( + + + + ); + } + } else { + return ( + + + + ); + } + } + + if (!this.props.item.confirmations) { + return ( + + + + ); + } else if (this.props.item.value < 0) { + return ( + + + + ); + } else { + return ( + + + + ); + } + }; + + subtitle = () => { + return ( + (this.props.item.confirmations < 7 ? loc.transactions.list.conf + ': ' + this.props.item.confirmations + ' ' : '') + + this.txMemo() + + (this.props.item.memo || '') + ); + }; + + onPress = () => { + if (this.props.item.hash) { + NavigationService.navigate('TransactionDetails', { hash: this.props.item.hash }); + } else if ( + this.props.item.type === 'user_invoice' || + this.props.item.type === 'payment_request' || + this.props.item.type === 'paid_invoice' + ) { + const lightningWallet = BlueAddressInput.getWallets().filter(wallet => { + if (typeof wallet === 'object') { + if (wallet.hasOwnProperty('secret')) { + return wallet.getSecret() === this.props.item.fromWallet; + } + } + }); + NavigationService.navigate('LNDViewInvoice', { + invoice: this.props.item, + fromWallet: lightningWallet[0], + isModal: false, + }); + } + }; + + render() { + return ( + + ); + } +} + const sliderWidth = width * 1; const itemWidth = width * 0.82; const sliderHeight = 190; @@ -1004,12 +1193,17 @@ export class WalletsCarousel extends Component { _renderItem({ item, index }) { let scaleValue = new Animated.Value(1.0); - + let props = { toValue: 0.9, duration: 100 }; + if (Platform.OS === 'android') { + props.push({ useNativeDriver: true }); + } this.onPressedIn = () => { - Animated.spring(scaleValue, { toValue: 0.9, duration: 100, useNativeDriver: Platform.OS === 'android' }).start(); + scaleValue.toValue = 0.9; + Animated.spring(scaleValue, props).start(); }; this.onPressedOut = () => { - Animated.spring(scaleValue, { toValue: 1.0, duration: 100, useNativeDriver: Platform.OS === 'android' }).start(); + scaleValue.toValue = 1.0; + Animated.spring(scaleValue, props).start(); }; if (!item) { diff --git a/index.js b/index.js index 2e420160..b0fcb1de 100644 --- a/index.js +++ b/index.js @@ -24,13 +24,13 @@ class BlueAppComponent extends React.Component { this.state = { isMigratingData: true }; } - async setIsMigratingData() { + setIsMigratingData = async () => { await BlueApp.startAndDecrypt(); this.setState({ isMigratingData: false }); - } + }; render() { - return this.state.isMigratingData ? this.setIsMigratingData()} /> : ; + return this.state.isMigratingData ? : ; } } diff --git a/screen/wallets/list.js b/screen/wallets/list.js index 9b0a0079..018886d9 100644 --- a/screen/wallets/list.js +++ b/screen/wallets/list.js @@ -1,20 +1,6 @@ import React, { Component } from 'react'; import { View, TouchableOpacity, Text, FlatList, RefreshControl, ScrollView } from 'react-native'; -import { - BlueTransactionOnchainIcon, - BlueLoading, - SafeBlueArea, - WalletsCarousel, - BlueTransactionIncommingIcon, - BlueTransactionOutgoingIcon, - BlueTransactionPendingIcon, - BlueTransactionOffchainIcon, - BlueTransactionExpiredIcon, - BlueList, - BlueListItem, - BlueHeaderDefaultMain, - BlueTransactionOffchainIncomingIcon, -} from '../../BlueComponents'; +import { BlueLoading, SafeBlueArea, WalletsCarousel, BlueList, BlueHeaderDefaultMain, BlueTransactionListItem } from '../../BlueComponents'; import { Icon } from 'react-native-elements'; import { NavigationEvents } from 'react-navigation'; import ReactNativeHapticFeedback from 'react-native-haptic-feedback'; @@ -65,7 +51,7 @@ export default class WalletsList extends Component { * Forcefully fetches TXs and balance for lastSnappedTo (i.e. current) wallet. * Triggered manually by user on pull-to-refresh. */ - refreshTransactions() { + refreshTransactions = () => { if (!(this.lastSnappedTo < BlueApp.getWallets().length)) { // last card, nop console.log('last card, nop'); @@ -76,28 +62,24 @@ export default class WalletsList extends Component { { isTransactionsLoading: true, }, - async function() { - let that = this; - setTimeout(async function() { - // more responsive - let noErr = true; - try { - await BlueApp.fetchWalletBalances(that.lastSnappedTo || 0); - let start = +new Date(); - await BlueApp.fetchWalletTransactions(that.lastSnappedTo || 0); - let end = +new Date(); - console.log('fetch tx took', (end - start) / 1000, 'sec'); - } catch (err) { - noErr = false; - console.warn(err); - } - if (noErr) await BlueApp.saveToDisk(); // caching + async () => { + let noErr = true; + try { + await BlueApp.fetchWalletBalances(this.lastSnappedTo || 0); + let start = +new Date(); + await BlueApp.fetchWalletTransactions(this.lastSnappedTo || 0); + let end = +new Date(); + console.log('fetch tx took', (end - start) / 1000, 'sec'); + } catch (err) { + noErr = false; + console.warn(err); + } + if (noErr) await BlueApp.saveToDisk(); // caching - that.refreshFunction(); - }, 1); + this.refreshFunction(); }, ); - } + }; /** * Redraws the screen @@ -107,11 +89,14 @@ export default class WalletsList extends Component { A(A.ENUM.GOT_NONZERO_BALANCE); } + const dataSource = BlueApp.getTransactions(); + const wallets = BlueApp.getWallets().concat(false); + this.setState({ isLoading: false, isTransactionsLoading: false, - dataSource: BlueApp.getTransactions(), - wallets: BlueApp.getWallets().concat(false), + dataSource, + wallets, }); } @@ -203,6 +188,10 @@ export default class WalletsList extends Component { _keyExtractor = (_item, index) => index.toString(); + _renderItem = rowData => { + return ; + }; + renderListHeaderComponent = () => { return ( @@ -229,60 +218,7 @@ export default class WalletsList extends Component { } }; - rowTitle = item => { - if (item.type === 'user_invoice' || item.type === 'payment_request') { - if (isNaN(item.value)) { - item.value = '0'; - } - const currentDate = new Date(); - const now = (currentDate.getTime() / 1000) | 0; - const invoiceExpiration = item.timestamp + item.expire_time; - - if (invoiceExpiration > now) { - return loc.formatBalanceWithoutSuffix(item.value && item.value, item.walletPreferredBalanceUnit, true).toString(); - } else if (invoiceExpiration < now) { - if (item.ispaid) { - return loc.formatBalanceWithoutSuffix(item.value && item.value, item.walletPreferredBalanceUnit, true).toString(); - } else { - return loc.lnd.expired; - } - } - } else { - return loc.formatBalanceWithoutSuffix(item.value && item.value, item.walletPreferredBalanceUnit, true).toString(); - } - }; - - rowTitleStyle = item => { - let color = '#37c0a1'; - - if (item.type === 'user_invoice' || item.type === 'payment_request') { - const currentDate = new Date(); - const now = (currentDate.getTime() / 1000) | 0; - const invoiceExpiration = item.timestamp + item.expire_time; - - if (invoiceExpiration > now) { - color = '#37c0a1'; - } else if (invoiceExpiration < now) { - if (item.ispaid) { - color = '#37c0a1'; - } else { - color = '#FF0000'; - } - } - } else if (item.value / 100000000 < 0) { - color = BlueApp.settings.foregroundColor; - } - - return { - fontWeight: '600', - fontSize: 16, - color: color, - }; - }; - render() { - const { navigate } = this.props.navigation; - if (this.state.isLoading) { return ; } @@ -293,9 +229,7 @@ export default class WalletsList extends Component { this.refreshFunction(); }} /> - this.refreshTransactions()} refreshing={this.state.isTransactionsLoading} />} - > + }> this.props.navigation.navigate('AddWallet')} /> @@ -335,117 +270,7 @@ export default class WalletsList extends Component { data={this.state.dataSource} extraData={this.state.dataSource} keyExtractor={this._keyExtractor} - renderItem={rowData => { - return ( - { - // is it lightning refill tx? - if (rowData.item.category === 'receive' && rowData.item.confirmations < 3) { - return ( - - - - ); - } - - if (rowData.item.type && rowData.item.type === 'bitcoind_tx') { - return ( - - - - ); - } - if (rowData.item.type === 'paid_invoice') { - // is it lightning offchain payment? - return ( - - - - ); - } - - if (rowData.item.type === 'user_invoice' || rowData.item.type === 'payment_request') { - if (!rowData.item.ispaid) { - const currentDate = new Date(); - const now = (currentDate.getTime() / 1000) | 0; - const invoiceExpiration = rowData.item.timestamp + rowData.item.expire_time; - if (invoiceExpiration < now) { - return ( - - - - ); - } - } else { - return ( - - - - ); - } - } - - if (!rowData.item.confirmations) { - return ( - - - - ); - } else if (rowData.item.value < 0) { - return ( - - - - ); - } else { - return ( - - - - ); - } - })()} - title={loc.transactionTimeToReadable(rowData.item.received)} - subtitle={ - (rowData.item.confirmations < 7 ? loc.transactions.list.conf + ': ' + rowData.item.confirmations + ' ' : '') + - this.txMemo(rowData.item.hash) + - (rowData.item.memo || '') - } - onPress={() => { - if (rowData.item.hash) { - navigate('TransactionDetails', { - hash: rowData.item.hash, - }); - } else if ( - rowData.item.type === 'user_invoice' || - rowData.item.type === 'payment_request' || - rowData.item.type === 'paid_invoice' - ) { - const lightningWallet = this.state.wallets.filter(wallet => { - if (typeof wallet === 'object') { - if (wallet.hasOwnProperty('secret')) { - return wallet.getSecret() === rowData.item.fromWallet; - } - } - }); - this.props.navigation.navigate('LNDViewInvoice', { - invoice: rowData.item, - fromWallet: lightningWallet[0], - isModal: false, - }); - } - }} - badge={{ - value: 3, - textStyle: { color: 'orange' }, - containerStyle: { marginTop: 0 }, - }} - hideChevron - rightTitle={this.rowTitle(rowData.item)} - rightTitleStyle={this.rowTitleStyle(rowData.item)} - /> - ); - }} + renderItem={this._renderItem} /> diff --git a/screen/wallets/transactions.js b/screen/wallets/transactions.js index 02e6c093..f4553888 100644 --- a/screen/wallets/transactions.js +++ b/screen/wallets/transactions.js @@ -3,20 +3,7 @@ import { Text, View, Image, FlatList, RefreshControl, TouchableOpacity, StatusBa import LinearGradient from 'react-native-linear-gradient'; import PropTypes from 'prop-types'; import { NavigationEvents } from 'react-navigation'; -import { - BlueText, - BlueTransactionOnchainIcon, - ManageFundsBigButton, - BlueTransactionExpiredIcon, - BlueTransactionIncommingIcon, - BlueTransactionOutgoingIcon, - BlueTransactionPendingIcon, - BlueTransactionOffchainIcon, - BlueSendButtonIcon, - BlueReceiveButtonIcon, - BlueListItem, - BlueTransactionOffchainIncomingIcon, -} from '../../BlueComponents'; +import { BlueText, ManageFundsBigButton, BlueSendButtonIcon, BlueReceiveButtonIcon, BlueTransactionListItem } from '../../BlueComponents'; import { Icon } from 'react-native-elements'; import { BitcoinUnit } from '../../models/bitcoinUnits'; import { LightningCustodianWallet } from '../../class'; @@ -269,13 +256,6 @@ export default class WalletTransactions extends Component { ); }; - txMemo(hash) { - if (BlueApp.tx_metadata[hash] && BlueApp.tx_metadata[hash]['memo']) { - return BlueApp.tx_metadata[hash]['memo']; - } - return ''; - } - _keyExtractor = (_item, index) => index.toString(); renderListHeaderComponent = () => { @@ -305,55 +285,8 @@ export default class WalletTransactions extends Component { this.onWillBlur(); } - rowTitle = item => { - if (item.type === 'user_invoice' || item.type === 'payment_request') { - if (isNaN(item.value)) { - item.value = 0; - } - const currentDate = new Date(); - const now = (currentDate.getTime() / 1000) | 0; - const invoiceExpiration = item.timestamp + item.expire_time; - - if (invoiceExpiration > now) { - return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit(), true).toString(); - } else if (invoiceExpiration < now) { - if (item.ispaid) { - return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit(), true).toString(); - } else { - return loc.lnd.expired; - } - } - } else { - return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit(), true).toString(); - } - }; - - rowTitleStyle = item => { - let color = '#37c0a1'; - - if (item.type === 'user_invoice' || item.type === 'payment_request') { - const currentDate = new Date(); - const now = (currentDate.getTime() / 1000) | 0; - const invoiceExpiration = item.timestamp + item.expire_time; - - if (invoiceExpiration > now) { - color = '#37c0a1'; - } else if (invoiceExpiration < now) { - if (item.ispaid) { - color = '#37c0a1'; - } else { - color = '#FF0000'; - } - } - } else if (item.value / 100000000 < 0) { - color = BlueApp.settings.foregroundColor; - } - - return { - fontWeight: '600', - fontSize: 16, - color: color, - }; + renderItem = item => { + return ; }; render() { @@ -462,110 +395,8 @@ export default class WalletTransactions extends Component { refreshControl={ this.refreshTransactions()} refreshing={this.state.isTransactionsLoading} />} data={this.state.dataSource} keyExtractor={this._keyExtractor} - renderItem={rowData => { - return ( - { - // is it lightning refill tx? - if (rowData.item.category === 'receive' && rowData.item.confirmations < 3) { - return ( - - - - ); - } - - if (rowData.item.type && rowData.item.type === 'bitcoind_tx') { - return ( - - - - ); - } - if (rowData.item.type === 'paid_invoice') { - // is it lightning offchain payment? - return ( - - - - ); - } - - if (rowData.item.type === 'user_invoice' || rowData.item.type === 'payment_request') { - if (!rowData.item.ispaid) { - const currentDate = new Date(); - const now = (currentDate.getTime() / 1000) | 0; - const invoiceExpiration = rowData.item.timestamp + rowData.item.expire_time; - if (invoiceExpiration < now) { - return ( - - - - ); - } - } else { - return ( - - - - ); - } - } - - if (!rowData.item.confirmations) { - return ( - - - - ); - } else if (rowData.item.value < 0) { - return ( - - - - ); - } else { - return ( - - - - ); - } - })()} - title={loc.transactionTimeToReadable(rowData.item.received)} - subtitle={ - (rowData.item.confirmations < 7 ? loc.transactions.list.conf + ': ' + rowData.item.confirmations + ' ' : '') + - this.txMemo(rowData.item.hash) + - (rowData.item.memo || '') - } - onPress={() => { - if (rowData.item.hash) { - navigate('TransactionDetails', { - hash: rowData.item.hash, - }); - } else if ( - rowData.item.type === 'user_invoice' || - rowData.item.type === 'payment_request' || - rowData.item.type === 'paid_invoice' - ) { - this.props.navigation.navigate('LNDViewInvoice', { - invoice: rowData.item, - fromWallet: this.state.wallet, - isModal: false, - }); - } - }} - badge={{ - value: 3, - textStyle: { color: 'orange' }, - containerStyle: { marginTop: 0 }, - }} - hideChevron - rightTitle={this.rowTitle(rowData.item)} - rightTitleStyle={this.rowTitleStyle(rowData.item)} - /> - ); - }} + initialNumToRender={10} + renderItem={this.renderItem} />