mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-23 23:27:26 +01:00
Merge branch 'master' into electrum-improve
This commit is contained in:
commit
4089933dbe
37 changed files with 3287 additions and 2579 deletions
|
@ -67,4 +67,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
|||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
[version]
|
||||
^0.85.0
|
||||
^0.86.0
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -54,3 +54,7 @@ buck-out/
|
|||
|
||||
# Bundle artifact
|
||||
*.jsbundle
|
||||
|
||||
#BlueWallet
|
||||
release-notes.json
|
||||
release-notes.txt
|
|
@ -4,7 +4,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon, Button, FormLabel, FormInput, Text, Header, List, ListItem } from 'react-native-elements';
|
||||
import { Icon, FormLabel, FormInput, Text, Header, List, ListItem } from 'react-native-elements';
|
||||
import {
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
|
@ -16,9 +16,9 @@ import {
|
|||
Dimensions,
|
||||
Image,
|
||||
SafeAreaView,
|
||||
InputAccessoryView,
|
||||
Clipboard,
|
||||
Platform,
|
||||
LayoutAnimation,
|
||||
TextInput,
|
||||
} from 'react-native';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
|
@ -44,10 +44,11 @@ if (aspectRatio > 1.6) {
|
|||
|
||||
export class BlueButton extends Component {
|
||||
render() {
|
||||
const disabled = this.props.hasOwnProperty('disabled');
|
||||
let backgroundColor = '#ccddf9';
|
||||
if (disabled === true) {
|
||||
backgroundColor = '#99a0ab';
|
||||
let fontColor = '#0c2550';
|
||||
if (this.props.hasOwnProperty('disabled') && this.props.disabled === true) {
|
||||
backgroundColor = '#eef0f4';
|
||||
fontColor = '#9aa0aa';
|
||||
}
|
||||
return (
|
||||
<TouchableOpacity
|
||||
|
@ -55,7 +56,7 @@ export class BlueButton extends Component {
|
|||
flex: 1,
|
||||
borderWidth: 0.7,
|
||||
borderColor: 'transparent',
|
||||
backgroundColor: this.props.hasOwnProperty('backgroundColor') ? this.props.backgroundColor : backgroundColor,
|
||||
backgroundColor: backgroundColor,
|
||||
minHeight: 45,
|
||||
height: 45,
|
||||
maxHeight: 45,
|
||||
|
@ -68,7 +69,7 @@ export class BlueButton extends Component {
|
|||
>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'center', alignItems: 'center' }}>
|
||||
{this.props.icon && <Icon name={this.props.icon.name} type={this.props.icon.type} color={this.props.icon.color} />}
|
||||
{this.props.title && <Text style={{ marginHorizontal: 8, fontSize: 16, color: '#0c2550' }}>{this.props.title}</Text>}
|
||||
{this.props.title && <Text style={{ marginHorizontal: 8, fontSize: 16, color: fontColor }}>{this.props.title}</Text>}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
@ -145,26 +146,18 @@ export class LightningButton extends Component {
|
|||
|
||||
export class BlueButtonLink extends Component {
|
||||
render() {
|
||||
// eslint-disable-next-line
|
||||
this.props.buttonStyle = this.props.buttonStyle || {};
|
||||
|
||||
return (
|
||||
<Button
|
||||
activeOpacity={0.1}
|
||||
delayPressIn={0}
|
||||
{...this.props}
|
||||
<TouchableOpacity
|
||||
style={{
|
||||
marginTop: 20,
|
||||
borderWidth: 0.7,
|
||||
borderColor: 'transparent',
|
||||
minHeight: 60,
|
||||
minWidth: 100,
|
||||
height: 60,
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
buttonStyle={{
|
||||
height: 45,
|
||||
width: width / 1.5,
|
||||
}}
|
||||
backgroundColor="transparent"
|
||||
color="#0c2550"
|
||||
/>
|
||||
{...this.props}
|
||||
>
|
||||
<Text style={{ color: '#0c2550', textAlign: 'center', fontSize: 16 }}>{this.props.title}</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -208,36 +201,32 @@ export class BlueCopyTextToClipboard extends Component {
|
|||
text: '',
|
||||
};
|
||||
|
||||
state = { hasTappedText: false };
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (Platform.OS === 'android') UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
|
||||
constructor(props) {
|
||||
super(props);
|
||||
if (Platform.OS === 'android') {
|
||||
UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
|
||||
}
|
||||
this.state = { hasTappedText: false, address: props.text };
|
||||
}
|
||||
|
||||
copyToClipboard = () => {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring, () => {
|
||||
this.setState({ hasTappedText: true }, () => {
|
||||
Clipboard.setString(this.props.text);
|
||||
this.setState({ address: loc.wallets.xpub.copiedToClipboard }, () => {
|
||||
setTimeout(() => {
|
||||
LayoutAnimation.configureNext(LayoutAnimation.Presets.spring);
|
||||
this.setState({ hasTappedText: false });
|
||||
this.setState({ hasTappedText: false, address: this.props.text });
|
||||
}, 1000);
|
||||
});
|
||||
this.setState({ hasTappedText: true });
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{ justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
|
||||
<TouchableOpacity onPress={this.copyToClipboard} disabled={this.state.hasTappedText}>
|
||||
<Text style={styleCopyTextToClipboard.address} numberOfLines={0}>
|
||||
{this.props.text}
|
||||
</Text>
|
||||
{this.state.hasTappedText && (
|
||||
<Text style={styleCopyTextToClipboard.address} numberOfLines={0}>
|
||||
{loc.wallets.xpub.copiedToClipboard}
|
||||
</Text>
|
||||
)}
|
||||
<Animated.Text style={styleCopyTextToClipboard.address} numberOfLines={0}>
|
||||
{this.state.address}
|
||||
</Animated.Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
|
@ -555,6 +544,27 @@ export class BlueList extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export class BlueUseAllFundsButton extends Component {
|
||||
static InputAccessoryViewID = 'useMaxInputAccessoryViewID';
|
||||
static propTypes = {
|
||||
wallet: PropTypes.shape().isRequired,
|
||||
onUseAllPressed: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<InputAccessoryView nativeID={BlueUseAllFundsButton.InputAccessoryViewID}>
|
||||
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Text style={{ color: '#9aa0aa', fontSize: 16, marginHorizontal: 8 }}>
|
||||
Total: {this.props.wallet.getBalance()} {BitcoinUnit.BTC}
|
||||
</Text>
|
||||
<BlueButtonLink title="Use All" onPress={this.props.onUseAllPressed} />
|
||||
</View>
|
||||
</InputAccessoryView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueLoading extends Component {
|
||||
render() {
|
||||
return (
|
||||
|
@ -580,7 +590,7 @@ const stylesBlueIcon = StyleSheet.create({
|
|||
paddingHorizontal: 14,
|
||||
paddingTop: 8,
|
||||
},
|
||||
boxIncomming: {
|
||||
boxIncoming: {
|
||||
position: 'relative',
|
||||
},
|
||||
ball: {
|
||||
|
@ -589,14 +599,14 @@ const stylesBlueIcon = StyleSheet.create({
|
|||
borderRadius: 15,
|
||||
backgroundColor: '#ccddf9',
|
||||
},
|
||||
ballIncomming: {
|
||||
ballIncoming: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
backgroundColor: '#d2f8d6',
|
||||
transform: [{ rotate: '-45deg' }],
|
||||
},
|
||||
ballIncommingWithoutRotate: {
|
||||
ballIncomingWithoutRotate: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
|
@ -659,12 +669,12 @@ export class BluePlusIcon extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export class BlueTransactionIncommingIcon extends Component {
|
||||
export class BlueTransactionIncomingIcon extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.ballIncomming}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ballIncoming}>
|
||||
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#37c0a1" iconStyle={{ left: 0, top: 8 }} />
|
||||
</View>
|
||||
</View>
|
||||
|
@ -677,7 +687,7 @@ export class BlueTransactionPendingIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ball}>
|
||||
<Icon
|
||||
{...this.props}
|
||||
|
@ -698,7 +708,7 @@ export class BlueTransactionExpiredIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ballOutgoingWithoutRotate}>
|
||||
<Icon {...this.props} name="hourglass-end" size={16} type="font-awesome" color="#d0021b" iconStyle={{ left: 0, top: 6 }} />
|
||||
</View>
|
||||
|
@ -712,8 +722,8 @@ export class BlueTransactionOnchainIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.ballIncomming}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ballIncoming}>
|
||||
<Icon
|
||||
{...this.props}
|
||||
name="link"
|
||||
|
@ -733,7 +743,7 @@ export class BlueTransactionOffchainIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ballOutgoingWithoutRotate}>
|
||||
<Icon {...this.props} name="bolt" size={16} type="font-awesome" color="#d0021b" iconStyle={{ left: 0, top: 7 }} />
|
||||
</View>
|
||||
|
@ -747,8 +757,8 @@ export class BlueTransactionOffchainIncomingIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.ballIncommingWithoutRotate}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ballIncomingWithoutRotate}>
|
||||
<Icon {...this.props} name="bolt" size={16} type="font-awesome" color="#37c0a1" iconStyle={{ left: 0, top: 7 }} />
|
||||
</View>
|
||||
</View>
|
||||
|
@ -761,7 +771,7 @@ export class BlueTransactionOutgoingIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.boxIncoming}>
|
||||
<View style={stylesBlueIcon.ballOutgoing}>
|
||||
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#d0021b" iconStyle={{ left: 0, top: 8 }} />
|
||||
</View>
|
||||
|
@ -987,6 +997,386 @@ 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 (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.item.type && this.props.item.type === 'bitcoind_tx') {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOnchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (this.props.item.type === 'paid_invoice') {
|
||||
// is it lightning offchain payment?
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionExpiredIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIncomingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.props.item.confirmations) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
} else if (this.props.item.value < 0) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOutgoingIcon />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionIncomingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
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 = BlueApp.getWallets().filter(wallet => {
|
||||
if (typeof wallet === 'object') {
|
||||
if (wallet.hasOwnProperty('secret')) {
|
||||
return wallet.getSecret() === this.props.item.fromWallet;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (lightningWallet.length === 1) {
|
||||
NavigationService.navigate('LNDViewInvoice', {
|
||||
invoice: this.props.item,
|
||||
fromWallet: lightningWallet[0],
|
||||
isModal: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<BlueListItem
|
||||
avatar={this.avatar()}
|
||||
title={loc.transactionTimeToReadable(this.props.item.received)}
|
||||
subtitle={this.subtitle()}
|
||||
onPress={this.onPress}
|
||||
badge={{
|
||||
value: 3,
|
||||
textStyle: { color: 'orange' },
|
||||
containerStyle: { marginTop: 0 },
|
||||
}}
|
||||
hideChevron
|
||||
rightTitle={this.rowTitle()}
|
||||
rightTitleStyle={this.rowTitleStyle()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueListTransactionItem 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 (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.props.item.type && this.props.item.type === 'bitcoind_tx') {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOnchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (this.props.item.type === 'paid_invoice') {
|
||||
// is it lightning offchain payment?
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionExpiredIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIncomingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.props.item.confirmations) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
} else if (this.props.item.value < 0) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOutgoingIcon />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionIncomingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
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 = BlueApp.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 (
|
||||
<BlueListItem
|
||||
avatar={this.avatar()}
|
||||
title={loc.transactionTimeToReadable(this.props.item.received)}
|
||||
subtitle={this.subtitle()}
|
||||
onPress={this.onPress}
|
||||
badge={{
|
||||
value: 3,
|
||||
textStyle: { color: 'orange' },
|
||||
containerStyle: { marginTop: 0 },
|
||||
}}
|
||||
hideChevron
|
||||
rightTitle={this.rowTitle()}
|
||||
rightTitleStyle={this.rowTitleStyle()}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const sliderWidth = width * 1;
|
||||
const itemWidth = width * 0.82;
|
||||
const sliderHeight = 190;
|
||||
|
@ -1003,12 +1393,17 @@ export class WalletsCarousel extends Component {
|
|||
|
||||
_renderItem({ item, index }) {
|
||||
let scaleValue = new Animated.Value(1.0);
|
||||
|
||||
let props = { duration: 50 };
|
||||
if (Platform.OS === 'android') {
|
||||
props['useNativeDriver'] = true;
|
||||
}
|
||||
this.onPressedIn = () => {
|
||||
Animated.spring(scaleValue, { toValue: 0.9, duration: 100, useNativeDriver: Platform.OS === 'android' }).start();
|
||||
props.toValue = 0.9;
|
||||
Animated.spring(scaleValue, props).start();
|
||||
};
|
||||
this.onPressedOut = () => {
|
||||
Animated.spring(scaleValue, { toValue: 1.0, duration: 100, useNativeDriver: Platform.OS === 'android' }).start();
|
||||
props.toValue = 1.0;
|
||||
Animated.spring(scaleValue, props).start();
|
||||
};
|
||||
|
||||
if (!item) {
|
||||
|
@ -1262,7 +1657,6 @@ export class BlueBitcoinAmount extends Component {
|
|||
ref={textInput => (this.textInput = textInput)}
|
||||
editable={!this.props.isLoading && !this.props.disabled}
|
||||
value={amount}
|
||||
autoFocus={this.props.pointerEvents !== 'none'}
|
||||
placeholderTextColor={this.props.disabled ? '#99a0ab' : '#0f5cc0'}
|
||||
style={{
|
||||
color: this.props.disabled ? '#99a0ab' : '#0f5cc0',
|
||||
|
|
|
@ -2,7 +2,7 @@ import { createStackNavigator, createAppContainer } from 'react-navigation';
|
|||
|
||||
import Settings from './screen/settings/settings';
|
||||
import About from './screen/settings/about';
|
||||
import Releasenotes from './screen/settings/releasenotes';
|
||||
import ReleaseNotes from './screen/settings/releasenotes';
|
||||
import Selftest from './screen/selftest';
|
||||
import Language from './screen/settings/language';
|
||||
import Currency from './screen/settings/currency';
|
||||
|
@ -87,9 +87,9 @@ const WalletsStackNavigator = createStackNavigator(
|
|||
screen: About,
|
||||
path: 'About',
|
||||
},
|
||||
Releasenotes: {
|
||||
screen: Releasenotes,
|
||||
path: 'Releasenotes',
|
||||
ReleaseNotes: {
|
||||
screen: ReleaseNotes,
|
||||
path: 'ReleaseNotes',
|
||||
},
|
||||
Selftest: {
|
||||
screen: Selftest,
|
||||
|
@ -185,6 +185,15 @@ const CreateWalletStackNavigator = createStackNavigator({
|
|||
},
|
||||
});
|
||||
|
||||
const LightningScanInvoiceStackNavigator = createStackNavigator({
|
||||
ScanLndInvoice: {
|
||||
screen: ScanLndInvoice,
|
||||
},
|
||||
Success: {
|
||||
screen: Success,
|
||||
},
|
||||
});
|
||||
|
||||
const MainBottomTabs = createStackNavigator(
|
||||
{
|
||||
Wallets: {
|
||||
|
@ -241,7 +250,10 @@ const MainBottomTabs = createStackNavigator(
|
|||
},
|
||||
},
|
||||
ScanLndInvoice: {
|
||||
screen: ScanLndInvoice,
|
||||
screen: LightningScanInvoiceStackNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
ScanQrAddress: {
|
||||
screen: sendScanQrAddress,
|
||||
|
|
|
@ -108,7 +108,10 @@
|
|||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/legacy_multidex_aapt_derived_proguard_rules" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/legacy_multidex_main_dex_list" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/linked_res_for_bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint_jar" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
|
||||
|
|
6
index.js
6
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 ? <WalletMigrate onComplete={() => this.setIsMigratingData()} /> : <App />;
|
||||
return this.state.isMigratingData ? <WalletMigrate onComplete={this.setIsMigratingData} /> : <App />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
|
||||
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
|
||||
|
@ -42,6 +43,7 @@
|
|||
2DCD954D1E0B4F2C00145EB5 /* BlueWalletTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* BlueWalletTests.m */; };
|
||||
2DF0FFEE2056DD460020B375 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DAD3EA31DF850E9000B6D8A /* libReact.a */; };
|
||||
2F707BDB2EF14D17AF9A2908 /* libReactNativePermissions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DD63E4B5C8344BB9880C9EC /* libReactNativePermissions.a */; };
|
||||
34582CAA4AD140F7B80C961A /* libTcpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */; };
|
||||
34CC55B441594DBB95AD1B50 /* Octicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E8E8CE89B3D142C6A8A56C34 /* Octicons.ttf */; };
|
||||
3EEBC6F85642487DA7C4EE35 /* AntDesign.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C4496FB303574862B40A878A /* AntDesign.ttf */; };
|
||||
4D6390DDA5B7485F91A6C750 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2654894D4DE44A4C8F71773D /* CoreData.framework */; };
|
||||
|
@ -79,7 +81,6 @@
|
|||
ED2971652150620600B7C4FE /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED2971642150620600B7C4FE /* JavaScriptCore.framework */; };
|
||||
F21429E1449249038A7F3444 /* FontAwesome.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 334051161886419EA186F4BA /* FontAwesome.ttf */; };
|
||||
FBB34FB8F9B248A89346FE61 /* libRNDeviceInfo-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6EB3338E347F4AFAA8C85C04 /* libRNDeviceInfo-tvOS.a */; };
|
||||
34582CAA4AD140F7B80C961A /* libTcpSockets.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -524,6 +525,13 @@
|
|||
remoteGlobalIDString = 32D980DD1BE9F11C00FA27E5;
|
||||
remoteInfo = RCTQRCodeLocalImage;
|
||||
};
|
||||
B47720652202510900DD0E81 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 910283A2A9EB4D00902DE78E /* TcpSockets.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 134814201AA4EA6300B7C361;
|
||||
remoteInfo = TcpSockets;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -579,8 +587,10 @@
|
|||
7EA61BC8FF6E4AD2A67F1557 /* RCTQRCodeLocalImage.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTQRCodeLocalImage.xcodeproj; path = "../node_modules/@remobile/react-native-qrcode-local-image/ios/RCTQRCodeLocalImage.xcodeproj"; sourceTree = "<group>"; };
|
||||
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
|
||||
8637D4B5E14D443A9031DA95 /* libRNFS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNFS.a; sourceTree = "<group>"; };
|
||||
910283A2A9EB4D00902DE78E /* TcpSockets.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = TcpSockets.xcodeproj; path = "../node_modules/react-native-tcp/ios/TcpSockets.xcodeproj"; sourceTree = "<group>"; };
|
||||
94565BFC6A0C4235B3EC7B01 /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSVG.a; sourceTree = "<group>"; };
|
||||
95208B2A05884A76B5BB99C0 /* libRCTGoogleAnalyticsBridge.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTGoogleAnalyticsBridge.a; sourceTree = "<group>"; };
|
||||
9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libTcpSockets.a; sourceTree = "<group>"; };
|
||||
9EA3788F4C6643B7B0182587 /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
|
||||
9F1F51A83D044F3BB26A35FC /* libRNSVG-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNSVG-tvOS.a"; sourceTree = "<group>"; };
|
||||
A71D2FDE64CF4F729C7298EA /* RNFS.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNFS.xcodeproj; path = "../node_modules/react-native-fs/RNFS.xcodeproj"; sourceTree = "<group>"; };
|
||||
|
@ -613,8 +623,6 @@
|
|||
F9065403A26440679749C7AA /* BVLinearGradient.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = BVLinearGradient.xcodeproj; path = "../node_modules/react-native-linear-gradient/BVLinearGradient.xcodeproj"; sourceTree = "<group>"; };
|
||||
FC98DC24A81A463AB8B2E6B1 /* libRNImagePicker.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNImagePicker.a; sourceTree = "<group>"; };
|
||||
FD7977067E1A496F94D8B1B7 /* libRNDeviceInfo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNDeviceInfo.a; sourceTree = "<group>"; };
|
||||
910283A2A9EB4D00902DE78E /* TcpSockets.xcodeproj */ = {isa = PBXFileReference; name = "TcpSockets.xcodeproj"; path = "../node_modules/react-native-tcp/ios/TcpSockets.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
|
||||
9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */ = {isa = PBXFileReference; name = "libTcpSockets.a"; path = "libTcpSockets.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -976,6 +984,7 @@
|
|||
E7078D2FED444DA4B0BD57F9 /* libRCTWKWebView.a */,
|
||||
FC98DC24A81A463AB8B2E6B1 /* libRNImagePicker.a */,
|
||||
B642AFB13483418CAB6FF25E /* libRCTQRCodeLocalImage.a */,
|
||||
9DF4E6C040764E4BA1ACC1EB /* libTcpSockets.a */,
|
||||
);
|
||||
name = "Recovered References";
|
||||
sourceTree = "<group>";
|
||||
|
@ -1123,6 +1132,14 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B47720622202510900DD0E81 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B47720662202510900DD0E81 /* libTcpSockets.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -1356,6 +1373,10 @@
|
|||
ProductGroup = B40FE5CC21FAD27D005D5578 /* Products */;
|
||||
ProjectRef = 9EA3788F4C6643B7B0182587 /* RNVectorIcons.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = B47720622202510900DD0E81 /* Products */;
|
||||
ProjectRef = 910283A2A9EB4D00902DE78E /* TcpSockets.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
|
@ -1795,6 +1816,13 @@
|
|||
remoteRef = B4327F5021FC1B9300F7ADFA /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
B47720662202510900DD0E81 /* libTcpSockets.a */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = archive.ar;
|
||||
path = libTcpSockets.a;
|
||||
remoteRef = B47720652202510900DD0E81 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
|
@ -2111,7 +2139,7 @@
|
|||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet;
|
||||
PRODUCT_NAME = BlueWallet;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
@ -2153,7 +2181,7 @@
|
|||
"-ObjC",
|
||||
"-lc++",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.bluewallet.bluewallet;
|
||||
PRODUCT_NAME = BlueWallet;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
moduleName:@"BlueWallet"
|
||||
initialProperties:nil
|
||||
launchOptions:launchOptions];
|
||||
rootView.backgroundColor = [UIColor blackColor];
|
||||
rootView.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
||||
UIViewController *rootViewController = [UIViewController new];
|
||||
|
|
|
@ -56,9 +56,11 @@
|
|||
<key>NSCalendarsUsageDescription</key>
|
||||
<string>This alert should not show up as we do not require this data</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>In order to quickly scan the recipient's address, we need your permission to use the camera to scan their QR Code.</string>
|
||||
<string>In order to quickly scan the recipient's address, we need your permission to use the camera to scan their QR Code.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>This alert should not show up as we do not require this data</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>This alert should not show up as we do not require this data</string>
|
||||
<key>NSMotionUsageDescription</key>
|
||||
<string>This alert should not show up as we do not require this data</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
|
@ -67,8 +69,6 @@
|
|||
<string>In order to import an image for scanning, we need your permission to access your photo library.</string>
|
||||
<key>NSSpeechRecognitionUsageDescription</key>
|
||||
<string>This alert should not show up as we do not require this data</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>This alert should not show up as we do not require this data</string>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>AntDesign.ttf</string>
|
||||
|
|
|
@ -217,6 +217,7 @@ module.exports = {
|
|||
refill_lnd_balance: 'Lade deine Lightning Wallet auf',
|
||||
refill: 'Aufladen',
|
||||
withdraw: 'Abheben',
|
||||
sameWalletAsInvoiceError: 'Du kannst nicht die Rechnung mit der Wallet begleichen, die du für die Erstellung dieser Rechnung verwendet hast.',
|
||||
sameWalletAsInvoiceError:
|
||||
'Du kannst nicht die Rechnung mit der Wallet begleichen, die du für die Erstellung dieser Rechnung verwendet hast.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ export const FiatUnit = Object.freeze({
|
|||
INR: { endPointKey: 'INR', symbol: '₹', locale: 'hi-HN' },
|
||||
JPY: { endPointKey: 'JPY', symbol: '¥', locale: 'ja-JP' },
|
||||
MXN: { endPointKey: 'MXN', symbol: '$', locale: 'es-MX' },
|
||||
MYR: { endPointKey: 'MYR', symbol: 'RM', locale: 'ms-MY' },
|
||||
PLN: { endPointKey: 'PLN', symbol: 'zł', locale: 'pl-PL' },
|
||||
RUB: { endPointKey: 'RUB', symbol: '₽', locale: 'ru-RU' },
|
||||
SGD: { endPointKey: 'SGD', symbol: 'S$', locale: 'zh-SG' },
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import Frisbee from 'frisbee';
|
||||
|
||||
export class NetworkTransactionFee {
|
||||
static StorageKey = 'NetworkTransactionFee';
|
||||
|
||||
constructor(fastestFee = 1, halfHourFee = 1, hourFee = 1) {
|
||||
this.fastestFee = fastestFee;
|
||||
this.halfHourFee = halfHourFee;
|
||||
|
|
4471
package-lock.json
generated
4471
package-lock.json
generated
File diff suppressed because it is too large
Load diff
28
package.json
28
package.json
|
@ -4,7 +4,7 @@
|
|||
"devDependencies": {
|
||||
"babel-eslint": "^10.0.1",
|
||||
"babel-jest": "^24.0.0",
|
||||
"eslint": "^5.12.1",
|
||||
"eslint": "^5.13.0",
|
||||
"eslint-plugin-babel": "^5.3.0",
|
||||
"eslint-plugin-import": "^2.15.0",
|
||||
"eslint-plugin-node": "^8.0.1",
|
||||
|
@ -47,31 +47,31 @@
|
|||
"crypto-js": "^3.1.9-1",
|
||||
"dayjs": "^1.8.0",
|
||||
"electrum-client": "git+https://github.com/Overtorment/node-electrum-client.git",
|
||||
"eslint-config-prettier": "^3.6.0",
|
||||
"eslint-config-prettier": "^4.0.0",
|
||||
"eslint-config-standard": "^12.0.0",
|
||||
"eslint-config-standard-react": "^7.0.2",
|
||||
"eslint-plugin-prettier": "^3.0.1",
|
||||
"eslint-plugin-standard": "^4.0.0",
|
||||
"frisbee": "^1.6.4",
|
||||
"frisbee": "^2.0.5",
|
||||
"intl": "^1.2.5",
|
||||
"mocha": "^5.2.0",
|
||||
"node-libs-react-native": "^1.0.1",
|
||||
"path-browserify": "0.0.0",
|
||||
"prettier": "^1.16.1",
|
||||
"path-browserify": "^1.0.0",
|
||||
"prettier": "^1.16.3",
|
||||
"process": "^0.11.10",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.7.0",
|
||||
"react-localization": "^1.0.10",
|
||||
"react-native": "^0.58.1",
|
||||
"react-native-camera": "^1.9.2",
|
||||
"react-native-camera": "^1.10.0",
|
||||
"react-native-custom-qr-codes": "^2.0.0",
|
||||
"react-native-device-info": "^0.25.1",
|
||||
"react-native-device-info": "^0.26.1",
|
||||
"react-native-elements": "^0.19.0",
|
||||
"react-native-flexi-radio-button": "^0.2.2",
|
||||
"react-native-fs": "^2.13.3",
|
||||
"react-native-gesture-handler": "^1.0.15",
|
||||
"react-native-google-analytics-bridge": "^7.0.0",
|
||||
"react-native-haptic-feedback": "^1.4.2",
|
||||
"react-native-haptic-feedback": "^1.5.0",
|
||||
"react-native-image-picker": "^0.28.0",
|
||||
"react-native-level-fs": "^3.0.1",
|
||||
"react-native-linear-gradient": "^2.5.3",
|
||||
|
@ -81,20 +81,20 @@
|
|||
"react-native-qrcode": "^0.2.7",
|
||||
"react-native-randombytes": "^3.5.2",
|
||||
"react-native-rate": "^1.1.6",
|
||||
"react-native-sentry": "^0.40.2",
|
||||
"react-native-sentry": "^0.41.1",
|
||||
"react-native-snap-carousel": "^3.7.5",
|
||||
"react-native-sortable-list": "0.0.22",
|
||||
"react-native-svg": "^9.0.4",
|
||||
"react-native-svg": "^9.1.1",
|
||||
"react-native-tcp": "^3.3.0",
|
||||
"react-native-vector-icons": "^6.2.0",
|
||||
"react-native-webview": "^3.2.1",
|
||||
"react-native-webview": "4.1.0",
|
||||
"react-native-wkwebview-reborn": "^2.0.0",
|
||||
"react-navigation": "^3.0.9",
|
||||
"react-navigation": "^3.1.2",
|
||||
"react-test-render": "^1.1.1",
|
||||
"readable-stream": "^1.1.14",
|
||||
"readable-stream": "^3.1.1",
|
||||
"request-promise-native": "^1.0.5",
|
||||
"secure-random": "^1.1.1",
|
||||
"stream-browserify": "^1.0.0",
|
||||
"stream-browserify": "^2.0.2",
|
||||
"util": "^0.11.1",
|
||||
"wif": "^2.0.1"
|
||||
},
|
||||
|
|
|
@ -495,7 +495,7 @@ export default class Browser extends Component {
|
|||
|
||||
Browser.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
getParam: PropTypes.function,
|
||||
getParam: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -116,7 +116,7 @@ export default class LNDCreateInvoice extends Component {
|
|||
|
||||
LNDCreateInvoice.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
}),
|
||||
|
|
|
@ -82,8 +82,8 @@ export default class LNDViewAdditionalInvoiceInformation extends Component {
|
|||
|
||||
LNDViewAdditionalInvoiceInformation.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -236,9 +236,9 @@ export default class LNDViewInvoice extends Component {
|
|||
|
||||
LNDViewInvoice.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -83,10 +83,10 @@ export default class ManageFunds extends Component {
|
|||
|
||||
ManageFunds.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
fromSecret: PropTypes.string,
|
||||
|
|
|
@ -72,12 +72,6 @@ export default class ScanLndInvoice extends React.Component {
|
|||
|
||||
processInvoice = data => {
|
||||
this.setState({ isLoading: true }, async () => {
|
||||
if (this.ignoreRead) return;
|
||||
this.ignoreRead = true;
|
||||
setTimeout(() => {
|
||||
this.ignoreRead = false;
|
||||
}, 6000);
|
||||
|
||||
if (!this.state.fromWallet) {
|
||||
alert('Before paying a Lightning invoice, you must first add a Lightning wallet.');
|
||||
return this.props.navigation.goBack();
|
||||
|
@ -149,11 +143,8 @@ export default class ScanLndInvoice extends React.Component {
|
|||
return alert(loc.lnd.sameWalletAsInvoiceError);
|
||||
}
|
||||
|
||||
let start = +new Date();
|
||||
let end;
|
||||
try {
|
||||
await fromWallet.payInvoice(this.state.invoice, this.state.decoded.num_satoshis);
|
||||
end = +new Date();
|
||||
} catch (Err) {
|
||||
console.log(Err.message);
|
||||
this.setState({ isLoading: false });
|
||||
|
@ -161,11 +152,12 @@ export default class ScanLndInvoice extends React.Component {
|
|||
return alert('Error');
|
||||
}
|
||||
|
||||
console.log('payInvoice took', (end - start) / 1000, 'sec');
|
||||
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs
|
||||
|
||||
alert('Success');
|
||||
this.props.navigation.goBack();
|
||||
this.props.navigation.navigate('Success', {
|
||||
amount: this.state.decoded.num_satoshis,
|
||||
amountUnit: BitcoinUnit.SATS,
|
||||
invoiceDescription: this.state.decoded.description,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -237,6 +229,7 @@ export default class ScanLndInvoice extends React.Component {
|
|||
)}
|
||||
<BlueSpacing20 />
|
||||
<BlueSpacing20 />
|
||||
<BlueCard>
|
||||
{this.state.isLoading ? (
|
||||
<View>
|
||||
<ActivityIndicator />
|
||||
|
@ -256,6 +249,7 @@ export default class ScanLndInvoice extends React.Component {
|
|||
/>
|
||||
)}
|
||||
</BlueCard>
|
||||
</BlueCard>
|
||||
</SafeBlueArea>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
|
@ -264,10 +258,10 @@ export default class ScanLndInvoice extends React.Component {
|
|||
|
||||
ScanLndInvoice.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
|
|
|
@ -10,7 +10,6 @@ import {
|
|||
BlueButtonLink,
|
||||
BlueNavigationStyle,
|
||||
is,
|
||||
BlueSpacing20,
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
/** @type {AppStorage} */
|
||||
|
@ -107,7 +106,6 @@ export default class ReceiveDetails extends Component {
|
|||
});
|
||||
}}
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'share-alternative',
|
||||
|
@ -130,8 +128,8 @@ export default class ReceiveDetails extends Component {
|
|||
|
||||
ReceiveDetails.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
address: PropTypes.string,
|
||||
|
|
|
@ -146,10 +146,10 @@ const styles = StyleSheet.create({
|
|||
|
||||
Confirm.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
amount: PropTypes.string,
|
||||
|
|
|
@ -108,10 +108,10 @@ const styles = StyleSheet.create({
|
|||
|
||||
SendCreate.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
amount: PropTypes.string,
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
StyleSheet,
|
||||
Platform,
|
||||
Slider,
|
||||
AsyncStorage,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
|
@ -71,13 +72,14 @@ export default class SendDetails extends Component {
|
|||
fromAddress,
|
||||
fromWallet,
|
||||
fromSecret,
|
||||
isLoading: true,
|
||||
isLoading: false,
|
||||
address,
|
||||
memo,
|
||||
fee: 1,
|
||||
networkTransactionFees: new NetworkTransactionFee(1, 1, 1),
|
||||
feeSliderValue: 1,
|
||||
bip70TransactionExpiration: null,
|
||||
renderWalletSelectionButtonHidden: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -91,7 +93,7 @@ export default class SendDetails extends Component {
|
|||
const dataWithoutSchema = data.replace('bitcoin:', '');
|
||||
if (btcAddressRx.test(dataWithoutSchema) || dataWithoutSchema.indexOf('bc1') === 0) {
|
||||
this.setState({
|
||||
address: data,
|
||||
address: dataWithoutSchema,
|
||||
bip70TransactionExpiration: null,
|
||||
isLoading: false,
|
||||
});
|
||||
|
@ -126,20 +128,27 @@ export default class SendDetails extends Component {
|
|||
};
|
||||
|
||||
async componentDidMount() {
|
||||
let recommendedFees = await NetworkTransactionFees.recommendedFees().catch(response => {
|
||||
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
|
||||
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide);
|
||||
try {
|
||||
const cachedNetworkTransactionFees = JSON.parse(await AsyncStorage.getItem(NetworkTransactionFee.StorageKey));
|
||||
|
||||
if (cachedNetworkTransactionFees && cachedNetworkTransactionFees.hasOwnProperty('halfHourFee')) {
|
||||
this.setState({
|
||||
fee: response.halfHourFee,
|
||||
networkTransactionFees: response,
|
||||
feeSliderValue: response.halfHourFee,
|
||||
isLoading: false,
|
||||
fee: cachedNetworkTransactionFees.halfHourFee,
|
||||
networkTransactionFees: cachedNetworkTransactionFees,
|
||||
feeSliderValue: cachedNetworkTransactionFees.halfHourFee,
|
||||
});
|
||||
});
|
||||
if (recommendedFees) {
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
let recommendedFees = await NetworkTransactionFees.recommendedFees();
|
||||
if (recommendedFees && recommendedFees.hasOwnProperty('halfHourFee')) {
|
||||
await AsyncStorage.setItem(NetworkTransactionFee.StorageKey, JSON.stringify(recommendedFees));
|
||||
this.setState({
|
||||
fee: recommendedFees.halfHourFee,
|
||||
networkTransactionFees: recommendedFees,
|
||||
feeSliderValue: recommendedFees.halfHourFee,
|
||||
isLoading: false,
|
||||
});
|
||||
|
||||
if (this.props.navigation.state.params.uri) {
|
||||
|
@ -148,16 +157,34 @@ export default class SendDetails extends Component {
|
|||
} else {
|
||||
try {
|
||||
const { address, amount, memo } = this.decodeBitcoinUri(this.props.navigation.getParam('uri'));
|
||||
this.setState({ address, amount, memo });
|
||||
this.setState({ address, amount, memo, isLoading: false });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
this.setState({ isLoading: false });
|
||||
alert('Error: Unable to decode Bitcoin address');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.setState({ isLoading: false });
|
||||
}
|
||||
} else {
|
||||
this.setState({ isLoading: false });
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.keyboardDidShowListener.remove();
|
||||
this.keyboardDidHideListener.remove();
|
||||
}
|
||||
|
||||
_keyboardDidShow = () => {
|
||||
this.setState({ renderWalletSelectionButtonHidden: true });
|
||||
};
|
||||
|
||||
_keyboardDidHide = () => {
|
||||
this.setState({ renderWalletSelectionButtonHidden: false });
|
||||
};
|
||||
|
||||
decodeBitcoinUri(uri) {
|
||||
try {
|
||||
let amount = '';
|
||||
|
@ -382,9 +409,9 @@ export default class SendDetails extends Component {
|
|||
}
|
||||
|
||||
onWalletSelect = wallet => {
|
||||
this.setState({ fromAddress: wallet.getAddress(), fromSecret: wallet.getSecret(), fromWallet: wallet }, () =>
|
||||
this.props.navigation.goBack(null),
|
||||
);
|
||||
this.setState({ fromAddress: wallet.getAddress(), fromSecret: wallet.getSecret(), fromWallet: wallet }, () => {
|
||||
this.props.navigation.pop();
|
||||
});
|
||||
};
|
||||
|
||||
renderFeeSelectionModal = () => {
|
||||
|
@ -392,7 +419,13 @@ export default class SendDetails extends Component {
|
|||
<Modal
|
||||
isVisible={this.state.isFeeSelectionModalVisible}
|
||||
style={styles.bottomModal}
|
||||
onBackdropPress={() => this.setState({ isFeeSelectionModalVisible: false })}
|
||||
onBackdropPress={() => {
|
||||
if (this.state.fee < 1 || this.state.feeSliderValue < 1) {
|
||||
this.setState({ fee: Number(1), feeSliderValue: Number(1) });
|
||||
}
|
||||
Keyboard.dismiss();
|
||||
this.setState({ isFeeSelectionModalVisible: false });
|
||||
}}
|
||||
>
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
|
||||
<View style={styles.modalContent}>
|
||||
|
@ -403,12 +436,14 @@ export default class SendDetails extends Component {
|
|||
this.textInput = ref;
|
||||
}}
|
||||
value={this.state.fee.toString()}
|
||||
onEndEditing={() => {
|
||||
if (this.state.fee < 1 || this.state.feeSliderValue < 1) {
|
||||
this.setState({ fee: Number(1), feeSliderValue: Number(1) });
|
||||
}
|
||||
}}
|
||||
onChangeText={value => {
|
||||
let newValue = value.replace(/\D/g, '');
|
||||
if (newValue.length === 0) {
|
||||
newValue = 1;
|
||||
}
|
||||
this.setState({ fee: newValue, feeSliderValue: newValue });
|
||||
this.setState({ fee: Number(newValue), feeSliderValue: Number(newValue) });
|
||||
}}
|
||||
maxLength={9}
|
||||
editable={!this.state.isLoading}
|
||||
|
@ -466,6 +501,7 @@ export default class SendDetails extends Component {
|
|||
};
|
||||
|
||||
renderWalletSelectionButton = () => {
|
||||
if (this.state.renderWalletSelectionButtonHidden) return;
|
||||
return (
|
||||
<View style={{ marginBottom: 24, alignItems: 'center' }}>
|
||||
{!this.state.isLoading && (
|
||||
|
@ -500,7 +536,6 @@ export default class SendDetails extends Component {
|
|||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<View style={{ flex: 1, justifyContent: 'space-between' }}>
|
||||
|
@ -620,7 +655,7 @@ const styles = StyleSheet.create({
|
|||
|
||||
SendDetails.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.func,
|
||||
pop: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
|
|
|
@ -16,10 +16,12 @@ export default class CameraExample extends React.Component {
|
|||
};
|
||||
|
||||
onBarCodeScanned(ret) {
|
||||
console.warn(ret);
|
||||
if (this.state.isLoading) return;
|
||||
this.setState({ isLoading: true }, () => {
|
||||
const onBarScanned = this.props.navigation.getParam('onBarScanned');
|
||||
this.props.navigation.goBack();
|
||||
onBarScanned(ret.data);
|
||||
this.props.navigation.goBack(null);
|
||||
});
|
||||
} // end
|
||||
|
||||
componentDidMount() {
|
||||
|
|
|
@ -18,7 +18,9 @@ export default class Success extends Component {
|
|||
|
||||
this.state = {
|
||||
amount: props.navigation.getParam('amount'),
|
||||
fee: props.navigation.getParam('fee'),
|
||||
fee: props.navigation.getParam('fee') || 0,
|
||||
amountUnit: props.navigation.getParam('amountUnit') || BitcoinUnit.BTC,
|
||||
invoiceDescription: props.navigation.getParam('invoiceDescription') || '',
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,9 +53,10 @@ export default class Success extends Component {
|
|||
alignSelf: 'flex-end',
|
||||
}}
|
||||
>
|
||||
{' ' + BitcoinUnit.BTC}
|
||||
{' ' + this.state.amountUnit}
|
||||
</Text>
|
||||
</View>
|
||||
{this.state.fee > 0 && (
|
||||
<Text
|
||||
style={{
|
||||
color: '#37c0a1',
|
||||
|
@ -66,6 +69,22 @@ export default class Success extends Component {
|
|||
>
|
||||
{loc.send.create.fee}: {loc.formatBalance(this.state.fee, BitcoinUnit.SATS)}
|
||||
</Text>
|
||||
)}
|
||||
{this.state.fee <= 0 && (
|
||||
<Text
|
||||
numberOfLines={0}
|
||||
style={{
|
||||
color: '#37c0a1',
|
||||
fontSize: 14,
|
||||
marginHorizontal: 4,
|
||||
paddingBottom: 6,
|
||||
fontWeight: '500',
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
>
|
||||
{this.state.invoiceDescription}
|
||||
</Text>
|
||||
)}
|
||||
</BlueCard>
|
||||
<View
|
||||
style={{
|
||||
|
@ -87,7 +106,6 @@ export default class Success extends Component {
|
|||
this.props.navigation.dismiss();
|
||||
}}
|
||||
title={loc.send.success.done}
|
||||
style={{ maxWidth: 263, paddingHorizontal: 56 }}
|
||||
/>
|
||||
</BlueCard>
|
||||
</SafeBlueArea>
|
||||
|
@ -97,10 +115,10 @@ export default class Success extends Component {
|
|||
|
||||
Success.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
amount: PropTypes.string,
|
||||
|
|
|
@ -129,7 +129,7 @@ export default class About extends Component {
|
|||
|
||||
<BlueButton
|
||||
onPress={() => {
|
||||
this.props.navigation.navigate('Releasenotes');
|
||||
this.props.navigation.navigate('ReleaseNotes');
|
||||
}}
|
||||
title="Release notes"
|
||||
/>
|
||||
|
|
|
@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
|
|||
/** @type {AppStorage} */
|
||||
const notes = require('../../release-notes');
|
||||
|
||||
export default class Releasenotes extends Component {
|
||||
export default class ReleaseNotes extends Component {
|
||||
static navigationOptions = () => ({
|
||||
...BlueNavigationStyle(),
|
||||
title: 'Release notes',
|
||||
|
@ -43,7 +43,7 @@ export default class Releasenotes extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
Releasenotes.propTypes = {
|
||||
ReleaseNotes.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func,
|
||||
goBack: PropTypes.func,
|
||||
|
|
|
@ -234,7 +234,7 @@ export default class SendCreate extends Component {
|
|||
|
||||
SendCreate.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
|
|
|
@ -191,7 +191,7 @@ export default class RBF extends Component {
|
|||
|
||||
RBF.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
|
|
|
@ -89,9 +89,11 @@ export default class TransactionsDetails extends Component {
|
|||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<BlueHeaderDefaultSub leftText={loc.transactions.details.title} rightComponent={null} />
|
||||
<ScrollView style={{ flex: 1 }}>
|
||||
<BlueCard>
|
||||
{(() => {
|
||||
if (this.state.tx.confirmations === 0 && this.state.wallet && this.state.wallet.allowRBF()) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<BlueButton
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate('RBF', {
|
||||
|
@ -100,11 +102,12 @@ export default class TransactionsDetails extends Component {
|
|||
}
|
||||
title="Replace-By-Fee (RBF)"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
|
||||
<BlueCard>
|
||||
{(() => {
|
||||
if (BlueApp.tx_metadata[this.state.tx.hash]) {
|
||||
if (BlueApp.tx_metadata[this.state.tx.hash]['memo']) {
|
||||
|
@ -176,14 +179,14 @@ export default class TransactionsDetails extends Component {
|
|||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{this.state.tx.hasOwnProperty('block_height') && this.state.block_height > 0 && (
|
||||
{this.state.tx.hasOwnProperty('block_height') && this.state.tx.block_height > 0 && (
|
||||
<React.Fragment>
|
||||
<BlueText style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Block Height</BlueText>
|
||||
<BlueText style={{ marginBottom: 26, color: 'grey' }}>{this.state.tx.block_height}</BlueText>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{this.state.tx.hasOwnProperty('confirmations') && (
|
||||
{this.state.tx.hasOwnProperty('confirmations') && this.state.tx.confirmations > 0 && (
|
||||
<React.Fragment>
|
||||
<BlueText style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Confirmations</BlueText>
|
||||
<BlueText style={{ marginBottom: 26, color: 'grey' }}>{this.state.tx.confirmations}</BlueText>
|
||||
|
@ -197,7 +200,7 @@ export default class TransactionsDetails extends Component {
|
|||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{this.state.tx.hasOwnProperty('outputs') && (
|
||||
{this.state.tx.hasOwnProperty('outputs') && this.state.tx.outputs.length > 0 && (
|
||||
<React.Fragment>
|
||||
<BlueText style={{ fontSize: 16, fontWeight: '500', marginBottom: 4 }}>Outputs</BlueText>
|
||||
<BlueText style={{ marginBottom: 26, color: 'grey' }}>{this.state.tx.outputs.length}</BlueText>
|
||||
|
@ -212,7 +215,7 @@ export default class TransactionsDetails extends Component {
|
|||
|
||||
TransactionsDetails.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
|
|
|
@ -72,7 +72,7 @@ export default class WalletsAdd extends Component {
|
|||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1, paddingTop: 40 }}>
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false} style={{ flex: 1 }}>
|
||||
<BlueCard>
|
||||
<BlueFormLabel>{loc.wallets.add.wallet_name}</BlueFormLabel>
|
||||
<View
|
||||
|
|
|
@ -107,7 +107,7 @@ export default class BuyBitcoin extends Component {
|
|||
|
||||
BuyBitcoin.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
goBack: PropTypes.func,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
address: PropTypes.string,
|
||||
|
|
|
@ -215,6 +215,9 @@ export default class WalletsImport extends Component {
|
|||
this.setLabel(text);
|
||||
}}
|
||||
/>
|
||||
</KeyboardAvoidingView>
|
||||
</TouchableWithoutFeedback>
|
||||
|
||||
<BlueSpacing20 />
|
||||
<View
|
||||
style={{
|
||||
|
@ -245,8 +248,6 @@ export default class WalletsImport extends Component {
|
|||
}}
|
||||
/>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</TouchableWithoutFeedback>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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, BlueListTransactionItem } from '../../BlueComponents';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { NavigationEvents } from 'react-navigation';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
|
@ -232,60 +218,9 @@ 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,
|
||||
};
|
||||
};
|
||||
_renderItem = data => <BlueListTransactionItem item={data.item} itemPriceUnit={data.item.walletPreferredBalanceUnit} />;
|
||||
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
@ -338,117 +273,7 @@ export default class WalletsList extends Component {
|
|||
data={this.state.dataSource}
|
||||
extraData={this.state.dataSource}
|
||||
keyExtractor={this._keyExtractor}
|
||||
renderItem={rowData => {
|
||||
return (
|
||||
<BlueListItem
|
||||
avatar={(() => {
|
||||
// is it lightning refill tx?
|
||||
if (rowData.item.category === 'receive' && rowData.item.confirmations < 3) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (rowData.item.type && rowData.item.type === 'bitcoind_tx') {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOnchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (rowData.item.type === 'paid_invoice') {
|
||||
// is it lightning offchain payment?
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionExpiredIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIncomingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rowData.item.confirmations) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
} else if (rowData.item.value < 0) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOutgoingIcon />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionIncommingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
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}
|
||||
/>
|
||||
</BlueList>
|
||||
</ScrollView>
|
||||
|
|
|
@ -28,6 +28,7 @@ export default class ScanQrWif extends React.Component {
|
|||
};
|
||||
|
||||
async onBarCodeScanned(ret) {
|
||||
this.setState({ isLoading: true });
|
||||
if (+new Date() - this.lastTimeIveBeenHere < 6000) {
|
||||
this.lastTimeIveBeenHere = +new Date();
|
||||
return;
|
||||
|
@ -57,16 +58,17 @@ export default class ScanQrWif extends React.Component {
|
|||
ret.data = wif.encode(0x80, decryptedKey.privateKey, decryptedKey.compressed);
|
||||
} catch (e) {
|
||||
console.log(e.message);
|
||||
this.setState({ message: false });
|
||||
this.setState({ message: false, isLoading: false });
|
||||
return alert(loc.wallets.scanQrWif.bad_password);
|
||||
}
|
||||
|
||||
this.setState({ message: false });
|
||||
this.setState({ message: false, isLoading: false });
|
||||
}
|
||||
|
||||
for (let w of BlueApp.wallets) {
|
||||
if (w.getSecret() === ret.data) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
|
@ -78,10 +80,10 @@ export default class ScanQrWif extends React.Component {
|
|||
for (let w of BlueApp.wallets) {
|
||||
if (w.getSecret() === hd.getSecret()) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
this.setState({ isLoading: true });
|
||||
await hd.fetchTransactions();
|
||||
if (hd.getTransactions().length !== 0) {
|
||||
await hd.fetchBalance();
|
||||
|
@ -91,6 +93,7 @@ export default class ScanQrWif extends React.Component {
|
|||
alert(loc.wallets.import.success);
|
||||
this.props.navigation.popToTop();
|
||||
setTimeout(() => EV(EV.enum.WALLETS_COUNT_CHANGED), 500);
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +106,7 @@ export default class ScanQrWif extends React.Component {
|
|||
for (let w of BlueApp.wallets) {
|
||||
if (w.getSecret() === hd.getSecret()) {
|
||||
// lookig for duplicates
|
||||
this.setState({ isLoading: false });
|
||||
return alert(loc.wallets.scanQrWif.wallet_already_exists); // duplicate, not adding
|
||||
}
|
||||
}
|
||||
|
@ -115,6 +119,7 @@ export default class ScanQrWif extends React.Component {
|
|||
alert(loc.wallets.import.success);
|
||||
this.props.navigation.popToTop();
|
||||
setTimeout(() => EV(EV.enum.WALLETS_COUNT_CHANGED), 500);
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
// nope
|
||||
|
@ -130,6 +135,7 @@ export default class ScanQrWif extends React.Component {
|
|||
await lnd.fetchBalance();
|
||||
} catch (Err) {
|
||||
console.log(Err);
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -138,6 +144,7 @@ export default class ScanQrWif extends React.Component {
|
|||
this.props.navigation.popToTop();
|
||||
alert(loc.wallets.import.success);
|
||||
setTimeout(() => EV(EV.enum.WALLETS_COUNT_CHANGED), 500);
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
// nope
|
||||
|
@ -165,6 +172,7 @@ export default class ScanQrWif extends React.Component {
|
|||
await watchOnly.fetchTransactions();
|
||||
await BlueApp.saveToDisk();
|
||||
setTimeout(() => EV(EV.enum.WALLETS_COUNT_CHANGED), 500);
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
// nope
|
||||
|
@ -176,6 +184,7 @@ export default class ScanQrWif extends React.Component {
|
|||
|
||||
if (newWallet.getAddress() === false || newLegacyWallet.getAddress() === false) {
|
||||
alert(loc.wallets.scanQrWif.bad_wif);
|
||||
this.setState({ isLoading: false });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -196,7 +205,7 @@ export default class ScanQrWif extends React.Component {
|
|||
alert(loc.wallets.scanQrWif.imported_wif + ret.data + loc.wallets.scanQrWif.with_address + newWallet.getAddress());
|
||||
}
|
||||
await BlueApp.saveToDisk();
|
||||
this.props.navigation.popToTop();
|
||||
this.props.navigation.dismiss();
|
||||
setTimeout(() => EV(EV.enum.WALLETS_COUNT_CHANGED), 500);
|
||||
} // end
|
||||
|
||||
|
@ -210,7 +219,7 @@ export default class ScanQrWif extends React.Component {
|
|||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<View style={{ flex: 1, paddingTop: 20, justifyContent: 'center', alignContent: 'center' }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
|
@ -275,6 +284,7 @@ ScanQrWif.propTypes = {
|
|||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.func,
|
||||
popToTop: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -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';
|
||||
|
@ -272,13 +259,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 = () => {
|
||||
|
@ -308,55 +288,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 <BlueTransactionListItem item={item.item} itemPriceUnit={this.state.wallet.getPreferredBalanceUnit()} />;
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -416,8 +349,9 @@ export default class WalletTransactions extends Component {
|
|||
<FlatList
|
||||
ListHeaderComponent={this.renderListHeaderComponent}
|
||||
ListEmptyComponent={
|
||||
<View style={{ top: 50, minHeight: 200 }}>
|
||||
<View style={{ top: 50, minHeight: 200, paddingHorizontal: 16 }}>
|
||||
<Text
|
||||
numberOfLines={0}
|
||||
style={{
|
||||
fontSize: 18,
|
||||
color: '#9aa0aa',
|
||||
|
@ -425,7 +359,7 @@ export default class WalletTransactions extends Component {
|
|||
}}
|
||||
>
|
||||
{(this.isLightning() &&
|
||||
'Lightning wallet should be used for your daily\ntransactions. Fees are unfairly cheap and\nspeed is blazing fast.') ||
|
||||
'Lightning wallet should be used for your daily transactions. Fees are unfairly cheap and speed is blazing fast.') ||
|
||||
loc.wallets.list.empty_txs1}
|
||||
</Text>
|
||||
<Text
|
||||
|
@ -435,7 +369,7 @@ export default class WalletTransactions extends Component {
|
|||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
{(this.isLightning() && '\nTo start using it tap on "manage funds"\nand topup your balance') ||
|
||||
{(this.isLightning() && '\nTo start using it tap on "manage funds" and topup your balance') ||
|
||||
loc.wallets.list.empty_txs2}
|
||||
</Text>
|
||||
|
||||
|
@ -465,110 +399,8 @@ export default class WalletTransactions extends Component {
|
|||
refreshControl={<RefreshControl onRefresh={() => this.refreshTransactions()} refreshing={this.state.isTransactionsLoading} />}
|
||||
data={this.state.dataSource}
|
||||
keyExtractor={this._keyExtractor}
|
||||
renderItem={rowData => {
|
||||
return (
|
||||
<BlueListItem
|
||||
avatar={(() => {
|
||||
// is it lightning refill tx?
|
||||
if (rowData.item.category === 'receive' && rowData.item.confirmations < 3) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (rowData.item.type && rowData.item.type === 'bitcoind_tx') {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOnchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
if (rowData.item.type === 'paid_invoice') {
|
||||
// is it lightning offchain payment?
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionExpiredIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOffchainIncomingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rowData.item.confirmations) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionPendingIcon />
|
||||
</View>
|
||||
);
|
||||
} else if (rowData.item.value < 0) {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionOutgoingIcon />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View style={{ width: 25 }}>
|
||||
<BlueTransactionIncommingIcon />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
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}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
|
|
Loading…
Add table
Reference in a new issue