Merge branch 'master' into receiveview

This commit is contained in:
marcosrdz 2021-04-21 08:24:13 -04:00
commit e23bc398b8
10 changed files with 158 additions and 157 deletions

View file

@ -6,12 +6,12 @@ import {
useInstalled, useInstalled,
transferCurrentComplicationUserInfo, transferCurrentComplicationUserInfo,
} from 'react-native-watch-connectivity'; } from 'react-native-watch-connectivity';
import { InteractionManager } from 'react-native';
import { Chain } from './models/bitcoinUnits'; import { Chain } from './models/bitcoinUnits';
import loc, { formatBalance, transactionTimeToReadable } from './loc'; import loc, { formatBalance, transactionTimeToReadable } from './loc';
import { BlueStorageContext } from './blue_modules/storage-context'; import { BlueStorageContext } from './blue_modules/storage-context';
import Notifications from './blue_modules/notifications'; import Notifications from './blue_modules/notifications';
import { FiatUnit } from './models/fiatUnit'; import { FiatUnit } from './models/fiatUnit';
import { MultisigHDWallet } from './class';
function WatchConnectivity() { function WatchConnectivity() {
const { walletsInitialized, wallets, fetchWalletTransactions, saveToDisk, txMetadata, preferredFiatCurrency } = useContext( const { walletsInitialized, wallets, fetchWalletTransactions, saveToDisk, txMetadata, preferredFiatCurrency } = useContext(
@ -106,7 +106,7 @@ function WatchConnectivity() {
} }
}; };
const sendWalletsToWatch = () => { const sendWalletsToWatch = async () => {
if (!Array.isArray(wallets)) { if (!Array.isArray(wallets)) {
console.log('No Wallets set to sync with Watch app. Exiting...'); console.log('No Wallets set to sync with Watch app. Exiting...');
return; return;
@ -116,100 +116,102 @@ function WatchConnectivity() {
return; return;
} }
return InteractionManager.runAfterInteractions(async () => { const walletsToProcess = [];
const walletsToProcess = [];
for (const wallet of wallets) { for (const wallet of wallets) {
let receiveAddress; let receiveAddress;
if (wallet.getAddressAsync) { if (wallet.getAddressAsync) {
if (wallet.chain === Chain.ONCHAIN) { if (wallet.chain === Chain.ONCHAIN) {
try { try {
receiveAddress = await wallet.getAddressAsync(); receiveAddress = await wallet.getAddressAsync();
} catch (_) {} } catch (_) {}
if (!receiveAddress) { if (!receiveAddress) {
// either sleep expired or getAddressAsync threw an exception // either sleep expired or getAddressAsync threw an exception
receiveAddress = wallet._getExternalAddressByIndex(wallet.next_free_address_index); receiveAddress = wallet._getExternalAddressByIndex(wallet.next_free_address_index);
} }
} else if (wallet.chain === Chain.OFFCHAIN) { } else if (wallet.chain === Chain.OFFCHAIN) {
try { try {
await wallet.getAddressAsync(); await wallet.getAddressAsync();
receiveAddress = wallet.getAddress(); receiveAddress = wallet.getAddress();
} catch (_) {} } catch (_) {}
if (!receiveAddress) { if (!receiveAddress) {
// either sleep expired or getAddressAsync threw an exception // either sleep expired or getAddressAsync threw an exception
receiveAddress = wallet.getAddress(); receiveAddress = wallet.getAddress();
}
} }
} }
const transactions = wallet.getTransactions(10); }
const watchTransactions = []; const transactions = wallet.getTransactions(10);
for (const transaction of transactions) { const watchTransactions = [];
let type = 'pendingConfirmation'; for (const transaction of transactions) {
let memo = ''; let type = 'pendingConfirmation';
let amount = 0; let memo = '';
let amount = 0;
if ('confirmations' in transaction && !(transaction.confirmations > 0)) { if ('confirmations' in transaction && !(transaction.confirmations > 0)) {
type = 'pendingConfirmation';
} else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
type = 'pendingConfirmation'; type = 'pendingConfirmation';
} else if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') { } else if (invoiceExpiration < now) {
const currentDate = new Date(); if (transaction.ispaid) {
const now = (currentDate.getTime() / 1000) | 0; type = 'received';
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
type = 'pendingConfirmation';
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
type = 'received';
} else {
type = 'sent';
}
}
} else if (transaction.value / 100000000 < 0) {
type = 'sent';
} else {
type = 'received';
}
if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
amount = isNaN(transaction.value) ? '0' : amount;
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else {
amount = loc.lnd.expired;
}
} else { } else {
type = 'sent';
}
}
} else if (transaction.value / 100000000 < 0) {
type = 'sent';
} else {
type = 'received';
}
if (transaction.type === 'user_invoice' || transaction.type === 'payment_request') {
amount = isNaN(transaction.value) ? '0' : amount;
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = transaction.timestamp + transaction.expire_time;
if (invoiceExpiration > now) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else if (invoiceExpiration < now) {
if (transaction.ispaid) {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else {
amount = loc.lnd.expired;
} }
} else { } else {
amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString(); amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} }
if (txMetadata[transaction.hash] && txMetadata[transaction.hash].memo) { } else {
memo = txMetadata[transaction.hash].memo; amount = formatBalance(transaction.value, wallet.getPreferredBalanceUnit(), true).toString();
} else if (transaction.memo) {
memo = transaction.memo;
}
const watchTX = { type, amount, memo, time: transactionTimeToReadable(transaction.received) };
watchTransactions.push(watchTX);
} }
walletsToProcess.push({ if (txMetadata[transaction.hash] && txMetadata[transaction.hash].memo) {
label: wallet.getLabel(), memo = txMetadata[transaction.hash].memo;
balance: formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true), } else if (transaction.memo) {
type: wallet.type, memo = transaction.memo;
preferredBalanceUnit: wallet.getPreferredBalanceUnit(), }
receiveAddress: receiveAddress, const watchTX = { type, amount, memo, time: transactionTimeToReadable(transaction.received) };
transactions: watchTransactions, watchTransactions.push(watchTX);
xpub: wallet.getXpub() ? wallet.getXpub() : wallet.getSecret(),
hideBalance: wallet.hideBalance,
});
} }
updateApplicationContext({ wallets: walletsToProcess, randomID: Math.floor(Math.random() * 11) });
}); const walletInformation = {
label: wallet.getLabel(),
balance: formatBalance(Number(wallet.getBalance()), wallet.getPreferredBalanceUnit(), true),
type: wallet.type,
preferredBalanceUnit: wallet.getPreferredBalanceUnit(),
receiveAddress: receiveAddress,
transactions: watchTransactions,
hideBalance: wallet.hideBalance,
};
if (wallet.chain === Chain.ONCHAIN && wallet.type !== MultisigHDWallet.type) {
walletInformation.push({ xpub: wallet.getXpub() ? wallet.getXpub() : wallet.getSecret() });
}
walletsToProcess.push(walletInformation);
}
updateApplicationContext({ wallets: walletsToProcess, randomID: Math.floor(Math.random() * 11) });
}; };
return null; return null;

View file

@ -37,6 +37,13 @@ export class AbstractWallet {
this._utxoMetadata = {}; this._utxoMetadata = {};
} }
/**
* @returns {number} Timestamp (millisecsec) of when last transactions were fetched from the network
*/
getLastTxFetch() {
return this._lastTxFetch;
}
getID() { getID() {
return createHash('sha256').update(this.getSecret()).digest().toString('hex'); return createHash('sha256').update(this.getSecret()).digest().toString('hex');
} }

View file

@ -16,6 +16,14 @@ export class WatchOnlyWallet extends LegacyWallet {
this.masterFingerprint = false; this.masterFingerprint = false;
} }
/**
* @inheritDoc
*/
getLastTxFetch() {
if (this._hdWalletInstance) return this._hdWalletInstance.getLastTxFetch();
return super.getLastTxFetch();
}
allowSend() { allowSend() {
return this.useWithHardwareWalletEnabled() && this.isHd() && this._hdWalletInstance.allowSend(); return this.useWithHardwareWalletEnabled() && this.isHd() && this._hdWalletInstance.allowSend();
} }

View file

@ -271,8 +271,6 @@ PODS:
- React-Core - React-Core
- react-native-safe-area-context (3.2.0): - react-native-safe-area-context (3.2.0):
- React-Core - React-Core
- react-native-slider (3.0.3):
- React
- react-native-tcp-socket (3.7.1): - react-native-tcp-socket (3.7.1):
- CocoaAsyncSocket - CocoaAsyncSocket
- React - React
@ -384,7 +382,7 @@ PODS:
- RNSentry (2.4.0): - RNSentry (2.4.0):
- React-Core - React-Core
- Sentry (= 6.1.4) - Sentry (= 6.1.4)
- RNShare (5.1.6): - RNShare (5.1.7):
- React-Core - React-Core
- RNSVG (12.1.0): - RNSVG (12.1.0):
- React - React
@ -453,7 +451,6 @@ DEPENDENCIES:
- react-native-is-catalyst (from `../node_modules/react-native-is-catalyst`) - react-native-is-catalyst (from `../node_modules/react-native-is-catalyst`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`) - react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- "react-native-slider (from `../node_modules/@react-native-community/slider`)"
- react-native-tcp-socket (from `../node_modules/react-native-tcp-socket`) - react-native-tcp-socket (from `../node_modules/react-native-tcp-socket`)
- react-native-webview (from `../node_modules/react-native-webview`) - react-native-webview (from `../node_modules/react-native-webview`)
- react-native-widget-center (from `../node_modules/react-native-widget-center`) - react-native-widget-center (from `../node_modules/react-native-widget-center`)
@ -572,8 +569,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-randombytes" :path: "../node_modules/react-native-randombytes"
react-native-safe-area-context: react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context" :path: "../node_modules/react-native-safe-area-context"
react-native-slider:
:path: "../node_modules/@react-native-community/slider"
react-native-tcp-socket: react-native-tcp-socket:
:path: "../node_modules/react-native-tcp-socket" :path: "../node_modules/react-native-tcp-socket"
react-native-webview: react-native-webview:
@ -705,7 +700,6 @@ SPEC CHECKSUMS:
react-native-is-catalyst: 52ee70e0123c82419dd4ce47dc4cc94b22467512 react-native-is-catalyst: 52ee70e0123c82419dd4ce47dc4cc94b22467512
react-native-randombytes: 45ae693012df24c9a07a5e578b3b567c01468581 react-native-randombytes: 45ae693012df24c9a07a5e578b3b567c01468581
react-native-safe-area-context: e471852c5ed67eea4b10c5d9d43c1cebae3b231d react-native-safe-area-context: e471852c5ed67eea4b10c5d9d43c1cebae3b231d
react-native-slider: b733e17fdd31186707146debf1f04b5d94aa1a93
react-native-tcp-socket: 96a4f104cdcc9c6621aafe92937f163d88447c5b react-native-tcp-socket: 96a4f104cdcc9c6621aafe92937f163d88447c5b
react-native-webview: 30f048378c6cee522ed9bbbedbc34acb21e58188 react-native-webview: 30f048378c6cee522ed9bbbedbc34acb21e58188
react-native-widget-center: 0f81d17beb163e7fb5848b06754d7d277fe7d99a react-native-widget-center: 0f81d17beb163e7fb5848b06754d7d277fe7d99a
@ -740,7 +734,7 @@ SPEC CHECKSUMS:
RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
RNSecureKeyStore: f1ad870e53806453039f650720d2845c678d89c8 RNSecureKeyStore: f1ad870e53806453039f650720d2845c678d89c8
RNSentry: b0d55027200c96f52e26b9bfb20296d47fc5051d RNSentry: b0d55027200c96f52e26b9bfb20296d47fc5051d
RNShare: 2db8b0346a4859f83d15528602ed5b6120a0452a RNShare: 503c37af86611beadccba46156fcc42170c9fb42
RNSVG: ce9d996113475209013317e48b05c21ee988d42e RNSVG: ce9d996113475209013317e48b05c21ee988d42e
RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59 RNVectorIcons: bc69e6a278b14842063605de32bec61f0b251a59
RNWatch: e4c5d19506c94506860032fb68aedd5991beb985 RNWatch: e4c5d19506c94506860032fb68aedd5991beb985

View file

@ -136,12 +136,12 @@
"ask": "Have you saved your wallets backup phrase? This backup phrase is required to access your funds in case you lose this device. Without the backup phrase, your funds will be permanently lost.", "ask": "Have you saved your wallets backup phrase? This backup phrase is required to access your funds in case you lose this device. Without the backup phrase, your funds will be permanently lost.",
"ask_no": "No, I have not", "ask_no": "No, I have not",
"ask_yes": "Yes, I have", "ask_yes": "Yes, I have",
"ok": "OK, I wrote this down.", "ok": "OK, I wrote it down",
"ok_lnd": "OK, I have saved it.", "ok_lnd": "OK, I have saved it",
"text": "Please take a moment to write down this mnemonic phrase on a piece of paper. Its your backup you can use to restore the wallet on another device.", "text": "Please take a moment to write down this mnemonic phrase on a piece of paper.\nIts your backup and you can use it to recover the wallet.",
"text_lnd": "Please save this wallet backup. It allows you to restore the wallet in case of loss.", "text_lnd": "Please save this wallet backup. It allows you to restore the wallet in case of loss.",
"text_lnd2": "This wallet is hosted by BlueWallet.", "text_lnd2": "This wallet is hosted by BlueWallet.",
"title": "Your wallet has been created." "title": "Your wallet has been created"
}, },
"receive": { "receive": {
"details_create": "Create", "details_create": "Create",

5
package-lock.json generated
View file

@ -5812,11 +5812,6 @@
"invariant": "^2.2.4" "invariant": "^2.2.4"
} }
}, },
"@react-native-community/slider": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@react-native-community/slider/-/slider-3.0.3.tgz",
"integrity": "sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw=="
},
"@react-navigation/core": { "@react-navigation/core": {
"version": "5.15.2", "version": "5.15.2",
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.15.2.tgz", "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-5.15.2.tgz",

View file

@ -76,7 +76,6 @@
"@react-native-community/blur": "3.6.0", "@react-native-community/blur": "3.6.0",
"@react-native-community/masked-view": "0.1.10", "@react-native-community/masked-view": "0.1.10",
"@react-native-community/push-notification-ios": "1.8.0", "@react-native-community/push-notification-ios": "1.8.0",
"@react-native-community/slider": "3.0.3",
"@react-navigation/drawer": "5.12.4", "@react-navigation/drawer": "5.12.4",
"@react-navigation/native": "5.9.3", "@react-navigation/native": "5.9.3",
"@react-navigation/stack": "5.14.3", "@react-navigation/stack": "5.14.3",

View file

@ -1,4 +1,4 @@
import React, { useCallback, useState, useContext } from 'react'; import React, { useCallback, useState, useContext, useRef, useEffect } from 'react';
import { ActivityIndicator, FlatList, StyleSheet, View, StatusBar } from 'react-native'; import { ActivityIndicator, FlatList, StyleSheet, View, StatusBar } from 'react-native';
import { useFocusEffect, useNavigation, useRoute, useTheme } from '@react-navigation/native'; import { useFocusEffect, useNavigation, useRoute, useTheme } from '@react-navigation/native';
import Privacy from '../../blue_modules/Privacy'; import Privacy from '../../blue_modules/Privacy';
@ -49,6 +49,8 @@ const WalletAddresses = () => {
const { walletID } = useRoute().params; const { walletID } = useRoute().params;
const addressList = useRef();
const wallet = wallets.find(w => w.getID() === walletID); const wallet = wallets.find(w => w.getID() === walletID);
const balanceUnit = wallet.getPreferredBalanceUnit(); const balanceUnit = wallet.getPreferredBalanceUnit();
@ -65,6 +67,12 @@ const WalletAddresses = () => {
}, },
}); });
useEffect(() => {
if (showAddresses) {
addressList.current.scrollToIndex({ animated: false, index: 0 });
}
}, [showAddresses]);
const getAddresses = () => { const getAddresses = () => {
const addressList = []; const addressList = [];
@ -108,30 +116,22 @@ const WalletAddresses = () => {
return <AddressItem {...item} balanceUnit={balanceUnit} onPress={() => navigateToReceive(item)} />; return <AddressItem {...item} balanceUnit={balanceUnit} onPress={() => navigateToReceive(item)} />;
}; };
const render = () => { return (
if (showAddresses) { <View style={[styles.root, stylesHook.root]}>
return ( <StatusBar barStyle="default" />
<View style={stylesHook.root}> <FlatList
<StatusBar barStyle="default" /> contentContainerStyle={stylesHook.root}
<FlatList ref={addressList}
style={stylesHook.root} data={addresses}
data={addresses} extraData={addresses}
initialNumToRender={20} initialNumToRender={40}
contentInsetAdjustmentBehavior="automatic" renderItem={renderRow}
renderItem={renderRow} ListEmptyComponent={<ActivityIndicator />}
/> centerContent={!showAddresses}
</View> contentInsetAdjustmentBehavior="automatic"
); />
} </View>
);
return (
<View style={[stylesHook.root, styles.loading]}>
<ActivityIndicator />
</View>
);
};
return render();
}; };
WalletAddresses.navigationOptions = navigationStyle({ WalletAddresses.navigationOptions = navigationStyle({
@ -144,22 +144,4 @@ const styles = StyleSheet.create({
root: { root: {
flex: 1, flex: 1,
}, },
loading: {
flex: 1,
justifyContent: 'center',
},
loadMoreButton: {
borderRadius: 9,
minHeight: 49,
paddingHorizontal: 8,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
alignSelf: 'auto',
flexGrow: 1,
marginHorizontal: 16,
},
loadMoreText: {
fontSize: 16,
},
}); });

View file

@ -2,7 +2,7 @@ import React, { useEffect, useState, useCallback, useContext } from 'react';
import { ActivityIndicator, View, BackHandler, Text, ScrollView, StyleSheet, StatusBar, I18nManager } from 'react-native'; import { ActivityIndicator, View, BackHandler, Text, ScrollView, StyleSheet, StatusBar, I18nManager } from 'react-native';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native'; import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import { BlueSpacing20, SafeBlueArea, BlueText, BlueButton } from '../../BlueComponents'; import { SafeBlueArea, BlueButton } from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle'; import navigationStyle from '../../components/navigationStyle';
import Privacy from '../../blue_modules/Privacy'; import Privacy from '../../blue_modules/Privacy';
import loc from '../../loc'; import loc from '../../loc';
@ -71,15 +71,15 @@ const PleaseBackup = () => {
</View> </View>
) : ( ) : (
<SafeBlueArea style={stylesHook.flex}> <SafeBlueArea style={stylesHook.flex}>
<StatusBar barStyle="default" /> <StatusBar barStyle="light-content" />
<ScrollView testID="PleaseBackupScrollView"> <ScrollView contentContainerStyle={styles.flex} testID="PleaseBackupScrollView">
<View style={styles.please}> <View style={styles.please}>
<BlueText style={[styles.successText, stylesHook.successText]}>{loc.pleasebackup.success}</BlueText> <Text style={[styles.pleaseText, stylesHook.pleaseText]}>{loc.pleasebackup.text}</Text>
<BlueText style={[styles.pleaseText, stylesHook.pleaseText]}>{loc.pleasebackup.text}</BlueText> </View>
<View style={styles.list}>
<View style={styles.secret}>{renderSecret()}</View> <View style={styles.secret}>{renderSecret()}</View>
</View>
<BlueSpacing20 /> <View style={styles.bottom}>
<BlueButton testID="PleasebackupOk" onPress={handleBackButton} title={loc.pleasebackup.ok} /> <BlueButton testID="PleasebackupOk" onPress={handleBackButton} title={loc.pleasebackup.ok} />
</View> </View>
</ScrollView> </ScrollView>
@ -103,6 +103,10 @@ const styles = StyleSheet.create({
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
}, },
flex: {
flex: 1,
justifyContent: 'space-around',
},
word: { word: {
marginRight: 8, marginRight: 8,
marginBottom: 8, marginBottom: 8,
@ -115,19 +119,29 @@ const styles = StyleSheet.create({
wortText: { wortText: {
fontWeight: 'bold', fontWeight: 'bold',
textAlign: 'left', textAlign: 'left',
fontSize: 17,
}, },
please: { please: {
alignItems: 'center', flexGrow: 1,
paddingHorizontal: 16, paddingHorizontal: 16,
}, },
list: {
flexGrow: 8,
paddingHorizontal: 16,
},
bottom: {
flexGrow: 2,
alignItems: 'center',
justifyContent: 'center',
},
successText: { successText: {
textAlign: 'center', textAlign: 'center',
fontWeight: 'bold', fontWeight: 'bold',
}, },
pleaseText: { pleaseText: {
paddingBottom: 10, marginVertical: 16,
paddingRight: 0, fontSize: 16,
paddingLeft: 0, fontWeight: '500',
}, },
secret: { secret: {
flexWrap: 'wrap', flexWrap: 'wrap',

View file

@ -149,7 +149,7 @@ const WalletTransactions = () => {
// refresh transactions if it never hasn't been done. It could be a fresh imported wallet // refresh transactions if it never hasn't been done. It could be a fresh imported wallet
useEffect(() => { useEffect(() => {
if (wallet._lastTxFetch === 0) { if (wallet.getLastTxFetch() === 0) {
refreshTransactions(); refreshTransactions();
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps