mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 15:04:50 +01:00
Merge branch 'master' into DK-danish-language-support
This commit is contained in:
commit
d4666e7b94
64 changed files with 2633 additions and 798 deletions
1
App.js
1
App.js
|
@ -1,7 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Linking } from 'react-native';
|
||||
import { NavigationActions } from 'react-navigation';
|
||||
|
||||
import MainBottomTabs from './MainBottomTabs';
|
||||
|
||||
export default class App extends React.Component {
|
||||
|
|
21
App.test.js
21
App.test.js
|
@ -6,6 +6,7 @@ import Settings from './screen/settings/settings';
|
|||
import Selftest from './screen/selftest';
|
||||
import { BlueHeader } from './BlueComponents';
|
||||
import MockStorage from './MockStorage';
|
||||
import { FiatUnit } from './models/fiatUnit';
|
||||
global.crypto = require('crypto'); // shall be used by tests under nodejs CLI, but not in RN environment
|
||||
let assert = require('assert');
|
||||
jest.mock('react-native-custom-qr-codes', () => 'Video');
|
||||
|
@ -74,7 +75,7 @@ it('BlueHeader works', () => {
|
|||
expect(rendered).toBeTruthy();
|
||||
});
|
||||
|
||||
it.skip('Settings work', () => {
|
||||
it('Settings work', () => {
|
||||
const rendered = TestRenderer.create(<Settings />).toJSON();
|
||||
expect(rendered).toBeTruthy();
|
||||
});
|
||||
|
@ -302,10 +303,24 @@ describe('currency', () => {
|
|||
AsyncStorage.storageCache = {}; // cleanup from other tests
|
||||
let currency = require('./currency');
|
||||
await currency.startUpdater();
|
||||
let cur = AsyncStorage.storageCache[AppStorage.CURRENCY];
|
||||
let cur = AsyncStorage.storageCache[AppStorage.EXCHANGE_RATES];
|
||||
cur = JSON.parse(cur);
|
||||
assert.ok(Number.isInteger(cur[currency.STRUCT.LAST_UPDATED]));
|
||||
assert.ok(cur[currency.STRUCT.LAST_UPDATED] > 0);
|
||||
assert.ok(cur[currency.STRUCT.BTC_USD] > 0);
|
||||
assert.ok(cur['BTC_USD'] > 0);
|
||||
|
||||
// now, setting other currency as default
|
||||
AsyncStorage.storageCache[AppStorage.PREFERRED_CURRENCY] = JSON.stringify(FiatUnit.JPY);
|
||||
await currency.startUpdater();
|
||||
cur = JSON.parse(AsyncStorage.storageCache[AppStorage.EXCHANGE_RATES]);
|
||||
assert.ok(cur['BTC_JPY'] > 0);
|
||||
|
||||
// now setting with a proper setter
|
||||
await currency.setPrefferedCurrency(FiatUnit.EUR);
|
||||
await currency.startUpdater();
|
||||
let preferred = await currency.getPreferredCurrency();
|
||||
assert.equal(preferred.endPointKey, 'EUR');
|
||||
cur = JSON.parse(AsyncStorage.storageCache[AppStorage.EXCHANGE_RATES]);
|
||||
assert.ok(cur['BTC_EUR'] > 0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -536,6 +536,12 @@ const stylesBlueIcon = StyleSheet.create({
|
|||
backgroundColor: '#d2f8d6',
|
||||
transform: [{ rotate: '-45deg' }],
|
||||
},
|
||||
ballIncommingWithoutRotate: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
backgroundColor: '#d2f8d6',
|
||||
},
|
||||
ballReceive: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
|
@ -550,6 +556,12 @@ const stylesBlueIcon = StyleSheet.create({
|
|||
backgroundColor: '#f8d2d2',
|
||||
transform: [{ rotate: '225deg' }],
|
||||
},
|
||||
ballOutgoingWithoutRotate: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
backgroundColor: '#f8d2d2',
|
||||
},
|
||||
ballTransparrent: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
|
@ -622,6 +634,20 @@ export class BlueTransactionPendingIcon extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export class BlueTransactionExpiredIcon extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.ballOutgoingWithoutRotate}>
|
||||
<Icon {...this.props} name="hourglass-end" size={16} type="font-awesome" color="#d0021b" iconStyle={{ left: 0, top: 6 }} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class BlueTransactionOnchainIcon extends Component {
|
||||
render() {
|
||||
return (
|
||||
|
@ -648,15 +674,8 @@ export class BlueTransactionOffchainIcon extends Component {
|
|||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.ballOutgoing}>
|
||||
<Icon
|
||||
{...this.props}
|
||||
name="bolt"
|
||||
size={16}
|
||||
type="font-awesome"
|
||||
color="#d0021b"
|
||||
iconStyle={{ left: 0, top: 7, transform: [{ rotate: '155deg' }] }}
|
||||
/>
|
||||
<View style={stylesBlueIcon.ballOutgoingWithoutRotate}>
|
||||
<Icon {...this.props} name="bolt" size={16} type="font-awesome" color="#d0021b" iconStyle={{ left: 0, top: 7 }} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -669,15 +688,8 @@ export class BlueTransactionOffchainIncomingIcon extends Component {
|
|||
return (
|
||||
<View {...this.props}>
|
||||
<View style={stylesBlueIcon.boxIncomming}>
|
||||
<View style={stylesBlueIcon.ballIncomming}>
|
||||
<Icon
|
||||
{...this.props}
|
||||
name="bolt"
|
||||
size={16}
|
||||
type="font-awesome"
|
||||
color="#37c0a1"
|
||||
iconStyle={{ left: 0, top: 7, transform: [{ rotate: '45deg' }] }}
|
||||
/>
|
||||
<View style={stylesBlueIcon.ballIncommingWithoutRotate}>
|
||||
<Icon {...this.props} name="bolt" size={16} type="font-awesome" color="#37c0a1" iconStyle={{ left: 0, top: 7 }} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -705,28 +717,26 @@ export class BlueReceiveButtonIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<TouchableOpacity {...this.props}>
|
||||
<View>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
minWidth: 110,
|
||||
minHeight: 40,
|
||||
position: 'relative',
|
||||
backgroundColor: '#ccddf9',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 130,
|
||||
backgroundColor: '#ccddf9',
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
minWidth: 30,
|
||||
minHeight: 30,
|
||||
left: 5,
|
||||
backgroundColor: 'transparent',
|
||||
transform: [{ rotate: '-45deg' }],
|
||||
alignItems: 'center',
|
||||
marginBottom: -11,
|
||||
}}
|
||||
>
|
||||
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#2f5fb3" iconStyle={{ left: 5, top: 12 }} />
|
||||
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#2f5fb3" />
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
|
@ -737,7 +747,7 @@ export class BlueReceiveButtonIcon extends Component {
|
|||
backgroundColor: 'transparent',
|
||||
}}
|
||||
>
|
||||
{loc.receive.header.toLowerCase()}
|
||||
{loc.receive.header}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -750,18 +760,15 @@ export class BlueSendButtonIcon extends Component {
|
|||
render() {
|
||||
return (
|
||||
<TouchableOpacity {...this.props}>
|
||||
<View>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
width: 110,
|
||||
height: 40,
|
||||
backgroundColor: '#ccddf9',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 15,
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
minWidth: 130,
|
||||
backgroundColor: '#ccddf9',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
minWidth: 30,
|
||||
|
@ -769,9 +776,10 @@ export class BlueSendButtonIcon extends Component {
|
|||
left: 5,
|
||||
backgroundColor: 'transparent',
|
||||
transform: [{ rotate: '225deg' }],
|
||||
marginBottom: 11,
|
||||
}}
|
||||
>
|
||||
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#2f5fb3" iconStyle={{ left: 2, top: 6 }} />
|
||||
<Icon {...this.props} name="arrow-down" size={16} type="font-awesome" color="#2f5fb3" />
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
|
@ -781,7 +789,7 @@ export class BlueSendButtonIcon extends Component {
|
|||
backgroundColor: 'transparent',
|
||||
}}
|
||||
>
|
||||
{loc.send.header.toLowerCase()}
|
||||
{loc.send.header}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -794,22 +802,21 @@ export class ManageFundsBigButton extends Component {
|
|||
render() {
|
||||
return (
|
||||
<TouchableOpacity {...this.props}>
|
||||
<View>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
minWidth: 160,
|
||||
minHeight: 40,
|
||||
backgroundColor: '#ccddf9',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
width: 168,
|
||||
backgroundColor: '#ccddf9',
|
||||
}}
|
||||
>
|
||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
minWidth: 30,
|
||||
minHeight: 30,
|
||||
right: 5,
|
||||
backgroundColor: 'transparent',
|
||||
transform: [{ rotate: '90deg' }],
|
||||
marginHorizontal: 10,
|
||||
}}
|
||||
>
|
||||
<Icon {...this.props} name="link" size={16} type="font-awesome" color="#2f5fb3" />
|
||||
|
@ -1109,47 +1116,65 @@ export class BlueBitcoinAmount extends Component {
|
|||
amount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||
onChangeText: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
unit: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
unit: BitcoinUnit.BTC,
|
||||
};
|
||||
|
||||
render() {
|
||||
const amount = typeof this.props.amount === 'number' ? this.props.amount.toString() : this.props.amount;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'center', paddingTop: 16, paddingBottom: 16 }}>
|
||||
<TextInput
|
||||
keyboardType="numeric"
|
||||
onChangeText={text => this.props.onChangeText(text.replace(',', '.'))}
|
||||
placeholder="0"
|
||||
maxLength={10}
|
||||
editable={!this.props.isLoading && !this.props.disabled}
|
||||
value={amount}
|
||||
placeholderTextColor={this.props.disabled ? '#99a0ab' : '#0f5cc0'}
|
||||
style={{
|
||||
color: this.props.disabled ? '#99a0ab' : '#0f5cc0',
|
||||
fontSize: 36,
|
||||
fontWeight: '600',
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: this.props.disabled ? '#99a0ab' : '#0f5cc0',
|
||||
fontSize: 16,
|
||||
marginHorizontal: 4,
|
||||
paddingBottom: 6,
|
||||
fontWeight: '600',
|
||||
alignSelf: 'flex-end',
|
||||
}}
|
||||
>
|
||||
{' ' + BitcoinUnit.BTC}
|
||||
</Text>
|
||||
<TouchableWithoutFeedback disabled={this.props.pointerEvents === 'none'} onPress={() => this.textInput.focus()}>
|
||||
<View>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'center', paddingTop: 16, paddingBottom: 16 }}>
|
||||
<TextInput
|
||||
keyboardType="numeric"
|
||||
onChangeText={text =>
|
||||
this.props.onChangeText(
|
||||
this.props.unit === BitcoinUnit.BTC
|
||||
? text.replace(new RegExp('[^0-9.]'), '', '.')
|
||||
: text.replace(new RegExp('[^0-9]'), ''),
|
||||
)
|
||||
}
|
||||
placeholder="0"
|
||||
maxLength={10}
|
||||
ref={textInput => (this.textInput = textInput)}
|
||||
editable={!this.props.isLoading && !this.props.disabled}
|
||||
value={amount}
|
||||
placeholderTextColor={this.props.disabled ? '#99a0ab' : '#0f5cc0'}
|
||||
style={{
|
||||
color: this.props.disabled ? '#99a0ab' : '#0f5cc0',
|
||||
fontSize: 36,
|
||||
fontWeight: '600',
|
||||
}}
|
||||
{...this.props}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: this.props.disabled ? '#99a0ab' : '#0f5cc0',
|
||||
fontSize: 16,
|
||||
marginHorizontal: 4,
|
||||
paddingBottom: 6,
|
||||
fontWeight: '600',
|
||||
alignSelf: 'flex-end',
|
||||
}}
|
||||
>
|
||||
{' ' + this.props.unit}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ alignItems: 'center', marginBottom: 22, marginTop: 4 }}>
|
||||
<Text style={{ fontSize: 18, color: '#d4d4d4', fontWeight: '600' }}>
|
||||
{loc.formatBalance(
|
||||
this.props.unit === BitcoinUnit.BTC ? amount || 0 : loc.formatBalanceWithoutSuffix(amount || 0, BitcoinUnit.BTC),
|
||||
BitcoinUnit.LOCAL_CURRENCY,
|
||||
)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ alignItems: 'center', marginBottom: 22, marginTop: 4 }}>
|
||||
<Text style={{ fontSize: 18, color: '#d4d4d4', fontWeight: '600' }}>
|
||||
{loc.formatBalance(amount || 0, BitcoinUnit.LOCAL_CURRENCY)}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ it('can convert witness to address', () => {
|
|||
|
||||
address = SegwitBech32Wallet.witnessToAddress('035c618df829af694cb99e664ce1b34f80ad2c3b49bcd0d9c0b1836c66b2d25fd8');
|
||||
assert.equal(address, 'bc1quhnve8q4tk3unhmjts7ymxv8cd6w9xv8wy29uv');
|
||||
|
||||
address = SegwitBech32Wallet.scriptPubKeyToAddress('00144d757460da5fcaf84cc22f3847faaa1078e84f6a');
|
||||
assert.equal(address, 'bc1qf46hgcx6tl90snxz9uuy0742zpuwsnm27ysdh7');
|
||||
});
|
||||
|
||||
it('can create a Segwit HD (BIP49)', async function() {
|
||||
|
|
|
@ -6,12 +6,6 @@ let assert = require('assert');
|
|||
describe('LightningCustodianWallet', () => {
|
||||
let l1 = new LightningCustodianWallet();
|
||||
|
||||
it.skip('can issue wallet credentials', async () => {
|
||||
let l0 = new LightningCustodianWallet();
|
||||
await l0.createAccount();
|
||||
console.log(l0.getSecret());
|
||||
});
|
||||
|
||||
it('can create, auth and getbtc', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 * 1000;
|
||||
assert.ok(l1.refill_addressess.length === 0);
|
||||
|
@ -207,7 +201,12 @@ describe('LightningCustodianWallet', () => {
|
|||
assert.ok(invoices2[0].description);
|
||||
assert.equal(invoices2[0].description, 'test memo');
|
||||
assert.ok(invoices2[0].payment_request);
|
||||
assert.ok(invoices2[0].timestamp);
|
||||
assert.ok(invoices2[0].expire_time);
|
||||
assert.equal(invoices2[0].amt, 1);
|
||||
for (let inv of invoices2) {
|
||||
assert.equal(inv.type, 'user_invoice');
|
||||
}
|
||||
|
||||
await lOld.fetchBalance();
|
||||
let oldBalance = lOld.balance;
|
||||
|
@ -248,4 +247,69 @@ describe('LightningCustodianWallet', () => {
|
|||
assert.equal(lOld.balance - oldBalance, 1);
|
||||
assert.equal(lNew.balance, 0);
|
||||
});
|
||||
|
||||
it('can pay free amount (tip) invoice', async function() {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100 * 1000;
|
||||
if (!process.env.BLITZHUB) {
|
||||
console.error('process.env.BLITZHUB not set, skipped');
|
||||
return;
|
||||
}
|
||||
|
||||
// fetchig invoice from tippin.me :
|
||||
|
||||
const api = new Frisbee({
|
||||
baseURI: 'https://tippin.me',
|
||||
});
|
||||
const res = await api.post('/lndreq/newinvoice.php', {
|
||||
headers: {
|
||||
Origin: 'https://tippin.me',
|
||||
'Accept-Encoding': 'gzip, deflate, br',
|
||||
'Accept-Language': 'en-GB,en-US;q=0.9,en;q=0.8',
|
||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
Accept: 'application/json, text/javascript, */*; q=0.01',
|
||||
},
|
||||
body: 'userid=1188&username=overtorment&istaco=0&customAmnt=0&customMemo=',
|
||||
});
|
||||
|
||||
let json;
|
||||
let invoice;
|
||||
if (res && res.body && (json = JSON.parse(res.body)) && json.message) {
|
||||
invoice = json.message;
|
||||
} else {
|
||||
throw new Error('tippin.me problem: ' + JSON.stringify(res));
|
||||
}
|
||||
|
||||
// --> use to pay specific invoice
|
||||
// invoice =
|
||||
// 'lnbc1pwrp35spp5z62nvj8yw6luq7ns4a8utpwn2qkkdwdt0ludwm54wjeazk2xv5wsdpu235hqurfdcsx7an9wf6x7undv4h8ggpgw35hqurfdchx6eff9p6nzvfc8q5scqzysxqyz5vqj8xq6wz6dezmunw6qxleuw67ensjnt3fldltrmmkvzurge0dczpn94fkwwh7hkh5wqrhsvfegtvhswn252hn6uw5kx99dyumz4v5n9sp337py2';
|
||||
|
||||
let l2 = new LightningCustodianWallet();
|
||||
l2.setSecret(process.env.BLITZHUB);
|
||||
await l2.authorize();
|
||||
await l2.fetchTransactions();
|
||||
await l2.fetchBalance();
|
||||
let oldBalance = +l2.balance;
|
||||
let txLen = l2.transactions_raw.length;
|
||||
|
||||
let decoded = await l2.decodeInvoice(invoice);
|
||||
assert.ok(decoded.payment_hash);
|
||||
assert.ok(decoded.description);
|
||||
assert.equal(+decoded.num_satoshis, 0);
|
||||
|
||||
await l2.checkRouteInvoice(invoice);
|
||||
|
||||
let start = +new Date();
|
||||
await l2.payInvoice(invoice, 3);
|
||||
let end = +new Date();
|
||||
if ((end - start) / 1000 > 9) {
|
||||
console.warn('payInvoice took', (end - start) / 1000, 'sec');
|
||||
}
|
||||
|
||||
await l2.fetchTransactions();
|
||||
assert.equal(l2.transactions_raw.length, txLen + 1);
|
||||
// transactions became more after paying an invoice
|
||||
|
||||
await l2.fetchBalance();
|
||||
assert.equal(oldBalance - l2.balance, 3);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -35,6 +35,9 @@ import Success from './screen/send/success';
|
|||
|
||||
import ManageFunds from './screen/lnd/manageFunds';
|
||||
import ScanLndInvoice from './screen/lnd/scanLndInvoice';
|
||||
import LNDCreateInvoice from './screen/lnd/lndCreateInvoice';
|
||||
import LNDViewInvoice from './screen/lnd/lndViewInvoice';
|
||||
import LNDViewAdditionalInvoiceInformation from './screen/lnd/lndViewAdditionalInvoiceInformation';
|
||||
|
||||
const ReorderWalletsStackNavigator = createStackNavigator({
|
||||
ReorderWallets: {
|
||||
|
@ -130,6 +133,55 @@ const CreateTransactionStackNavigator = createStackNavigator({
|
|||
},
|
||||
});
|
||||
|
||||
const ManageFundsStackNavigator = createStackNavigator({
|
||||
ManageFunds: {
|
||||
screen: ManageFunds,
|
||||
},
|
||||
SelectWallet: {
|
||||
screen: SelectWallet,
|
||||
},
|
||||
SendDetails: {
|
||||
screen: CreateTransactionStackNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const LNDViewInvoiceStackNavigator = createStackNavigator({
|
||||
LNDViewInvoice: {
|
||||
screen: LNDViewInvoice,
|
||||
swipeEnabled: false,
|
||||
gesturesEnabled: false,
|
||||
},
|
||||
LNDViewAdditionalInvoiceInformation: {
|
||||
screen: LNDViewAdditionalInvoiceInformation,
|
||||
},
|
||||
});
|
||||
|
||||
const LNDCreateInvoiceStackNavigator = createStackNavigator({
|
||||
LNDCreateInvoice: {
|
||||
screen: LNDCreateInvoice,
|
||||
},
|
||||
LNDViewInvoice: {
|
||||
screen: LNDViewInvoice,
|
||||
swipeEnabled: false,
|
||||
gesturesEnabled: false,
|
||||
},
|
||||
LNDViewAdditionalInvoiceInformation: {
|
||||
screen: LNDViewAdditionalInvoiceInformation,
|
||||
},
|
||||
});
|
||||
|
||||
const CreateWalletStackNavigator = createStackNavigator({
|
||||
AddWallet: {
|
||||
screen: AddWallet,
|
||||
},
|
||||
ImportWallet: {
|
||||
screen: ImportWallet,
|
||||
},
|
||||
});
|
||||
|
||||
const MainBottomTabs = createStackNavigator(
|
||||
{
|
||||
Wallets: {
|
||||
|
@ -140,10 +192,10 @@ const MainBottomTabs = createStackNavigator(
|
|||
},
|
||||
},
|
||||
AddWallet: {
|
||||
screen: AddWallet,
|
||||
},
|
||||
ImportWallet: {
|
||||
screen: ImportWallet,
|
||||
screen: CreateWalletStackNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
ScanQrWif: {
|
||||
screen: scanQrWif,
|
||||
|
@ -180,7 +232,10 @@ const MainBottomTabs = createStackNavigator(
|
|||
// LND:
|
||||
|
||||
ManageFunds: {
|
||||
screen: ManageFunds,
|
||||
screen: ManageFundsStackNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
ScanLndInvoice: {
|
||||
screen: ScanLndInvoice,
|
||||
|
@ -194,11 +249,17 @@ const MainBottomTabs = createStackNavigator(
|
|||
header: null,
|
||||
},
|
||||
},
|
||||
|
||||
// Select Wallet. Mostly for deeplinking
|
||||
|
||||
SelectWallet: {
|
||||
screen: SelectWallet,
|
||||
LNDCreateInvoice: {
|
||||
screen: LNDCreateInvoiceStackNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
LNDViewExistingInvoice: {
|
||||
screen: LNDViewInvoiceStackNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -102,8 +102,8 @@ android {
|
|||
applicationId "io.bluewallet.bluewallet"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 12
|
||||
versionName "3.4.0"
|
||||
versionCode 15
|
||||
versionName "3.5.5"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="bitcoin" />
|
||||
<data android:scheme="lightning" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||
|
|
|
@ -112,4 +112,9 @@
|
|||
<androidx.activity/>
|
||||
<com.android.tools.apkparser/>
|
||||
<com.android.tools.pixelprobe/>
|
||||
<androidx.textclassifier/>
|
||||
<androidx.remotecallback/>
|
||||
<com.android.tools.chunkio/>
|
||||
<com.android.tools.fakeadbserver/>
|
||||
<androidx.savedstate/>
|
||||
</metadata>
|
||||
|
|
10
android/metadata/en-US/changelogs/14.txt
Normal file
10
android/metadata/en-US/changelogs/14.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
v3.5.0
|
||||
------
|
||||
|
||||
ADD: Create LND invoice
|
||||
ADD: Ability to show wallet XPUB in options
|
||||
ADD: translations for german (DE)
|
||||
ADD: Set receive amount & label
|
||||
ADD: Added more Fiat currencies
|
||||
ADD: help text in lighning settings
|
||||
ADD: CZ locale
|
9
android/metadata/en-US/changelogs/15.txt
Normal file
9
android/metadata/en-US/changelogs/15.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
v3.5.5
|
||||
------
|
||||
|
||||
ADD: pay zero-amount (tip) invoices
|
||||
ADD: lightning withdrawal through zigzag
|
||||
ADD: Thai translation
|
||||
ADD: Dutch translation
|
||||
ADD: Added Singapore Dollars
|
||||
ADD: Added AUD, VEF, and ZAR fiats.
|
|
@ -14,9 +14,9 @@ let encryption = require('../encryption');
|
|||
export class AppStorage {
|
||||
static FLAG_ENCRYPTED = 'data_encrypted';
|
||||
static LANG = 'lang';
|
||||
static CURRENCY = 'currency';
|
||||
static EXCHANGE_RATES = 'currency';
|
||||
static LNDHUB = 'lndhub';
|
||||
static PREFERREDCURRENCY = 'preferredCurrency';
|
||||
static PREFERRED_CURRENCY = 'preferredCurrency';
|
||||
|
||||
constructor() {
|
||||
/** {Array.<AbstractWallet>} */
|
||||
|
@ -174,8 +174,10 @@ export class AppStorage {
|
|||
break;
|
||||
}
|
||||
// done
|
||||
this.wallets.push(unserializedWallet);
|
||||
this.tx_metadata = data.tx_metadata;
|
||||
if (!this.wallets.some(wallet => wallet.getSecret() === unserializedWallet.secret)) {
|
||||
this.wallets.push(unserializedWallet);
|
||||
this.tx_metadata = data.tx_metadata;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -290,11 +292,23 @@ export class AppStorage {
|
|||
for (let wallet of this.wallets) {
|
||||
if (c++ === index) {
|
||||
await wallet.fetchTransactions();
|
||||
if (wallet.fetchPendingTransactions) {
|
||||
await wallet.fetchPendingTransactions();
|
||||
}
|
||||
if (wallet.fetchUserInvoices) {
|
||||
await wallet.fetchUserInvoices();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let wallet of this.wallets) {
|
||||
await wallet.fetchTransactions();
|
||||
if (wallet.fetchPendingTransactions) {
|
||||
await wallet.fetchPendingTransactions();
|
||||
}
|
||||
if (wallet.fetchUserInvoices) {
|
||||
await wallet.fetchUserInvoices();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,9 +102,9 @@ export class LightningCustodianWallet extends LegacyWallet {
|
|||
this.secret = 'lndhub://' + json.login + ':' + json.password;
|
||||
}
|
||||
|
||||
async payInvoice(invoice) {
|
||||
async payInvoice(invoice, freeAmount = 0) {
|
||||
let response = await this._api.post('/payinvoice', {
|
||||
body: { invoice: invoice },
|
||||
body: { invoice: invoice, amount: freeAmount },
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json',
|
||||
|
@ -145,12 +145,24 @@ export class LightningCustodianWallet extends LegacyWallet {
|
|||
throw new Error('API error: ' + json.message + ' (code ' + json.code + ')');
|
||||
}
|
||||
|
||||
this.user_invoices_raw = json;
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basically the same as this.getUserInvoices() but saves invoices list
|
||||
* to internal variable
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async fetchUserInvoices() {
|
||||
await this.getUserInvoices();
|
||||
}
|
||||
|
||||
async addInvoice(amt, memo) {
|
||||
let response = await this._api.post('/addinvoice', {
|
||||
body: { amt: amt + '', memo: encodeURIComponent(memo) },
|
||||
body: { amt: amt + '', memo: memo },
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json',
|
||||
|
@ -306,8 +318,9 @@ export class LightningCustodianWallet extends LegacyWallet {
|
|||
getTransactions() {
|
||||
let txs = [];
|
||||
this.pending_transactions_raw = this.pending_transactions_raw || [];
|
||||
this.user_invoices_raw = this.user_invoices_raw || [];
|
||||
this.transactions_raw = this.transactions_raw || [];
|
||||
txs = txs.concat(this.pending_transactions_raw, this.transactions_raw.slice().reverse()); // slice so array is cloned
|
||||
txs = txs.concat(this.pending_transactions_raw.slice(), this.transactions_raw.slice().reverse(), this.user_invoices_raw.slice()); // slice so array is cloned
|
||||
// transforming to how wallets/list screen expects it
|
||||
for (let tx of txs) {
|
||||
if (tx.amount) {
|
||||
|
@ -325,13 +338,21 @@ export class LightningCustodianWallet extends LegacyWallet {
|
|||
|
||||
if (tx.type === 'paid_invoice') {
|
||||
tx.memo = tx.memo || 'Lightning payment';
|
||||
if (tx.value > 0) tx.value = (tx.value * 1 + tx.fee * 1) * -1;
|
||||
// outer code expects spending transactions to of negative value
|
||||
}
|
||||
|
||||
if (tx.type === 'bitcoind_tx') {
|
||||
tx.memo = 'On-chain transaction';
|
||||
}
|
||||
|
||||
tx.received = new Date(tx.timestamp * 1000).toString(); // TODO once api is ready
|
||||
if (tx.type === 'user_invoice') {
|
||||
// incoming ln tx
|
||||
tx.value = parseInt(tx.amt);
|
||||
tx.memo = tx.description || 'Lightning invoice';
|
||||
}
|
||||
|
||||
tx.received = new Date(tx.timestamp * 1000).toString();
|
||||
}
|
||||
return txs.sort(function(a, b) {
|
||||
return b.timestamp - a.timestamp;
|
||||
|
@ -497,7 +518,7 @@ export class LightningCustodianWallet extends LegacyWallet {
|
|||
}
|
||||
|
||||
allowReceive() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,4 +27,10 @@ export class SegwitBech32Wallet extends LegacyWallet {
|
|||
const scriptPubKey = bitcoin.script.witnessPubKeyHash.output.encode(pubKeyHash);
|
||||
return bitcoin.address.fromOutputScript(scriptPubKey, bitcoin.networks.bitcoin);
|
||||
}
|
||||
|
||||
static scriptPubKeyToAddress(scriptPubKey) {
|
||||
const bitcoin = require('bitcoinjs-lib');
|
||||
const scriptPubKey2 = Buffer.from(scriptPubKey, 'hex');
|
||||
return bitcoin.address.fromOutputScript(scriptPubKey2, bitcoin.networks.bitcoin);
|
||||
}
|
||||
}
|
||||
|
|
111
currency.js
111
currency.js
|
@ -4,37 +4,46 @@ import { AppStorage } from './class';
|
|||
import { FiatUnit } from './models/fiatUnit';
|
||||
let BigNumber = require('bignumber.js');
|
||||
let preferredFiatCurrency = FiatUnit.USD;
|
||||
let lang = {};
|
||||
// let btcusd = 6500; // default
|
||||
let exchangeRates = {};
|
||||
|
||||
const STRUCT = {
|
||||
LAST_UPDATED: 'LAST_UPDATED',
|
||||
BTC_USD: 'BTC_USD',
|
||||
BTC_EUR: 'BTC_EUR',
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves to storage preferred currency, whole object
|
||||
* from `./models/fiatUnit`
|
||||
*
|
||||
* @param item {Object} one of the values in `./models/fiatUnit`
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function setPrefferedCurrency(item) {
|
||||
await AsyncStorage.setItem(AppStorage.PREFERRED_CURRENCY, JSON.stringify(item));
|
||||
}
|
||||
|
||||
async function getPreferredCurrency() {
|
||||
return JSON.parse(await AsyncStorage.getItem(AppStorage.PREFERRED_CURRENCY));
|
||||
}
|
||||
|
||||
async function updateExchangeRate() {
|
||||
let preferredFiatCurrency;
|
||||
try {
|
||||
preferredFiatCurrency = JSON.parse(await AsyncStorage.getItem(AppStorage.PREFERREDCURRENCY));
|
||||
if (preferredFiatCurrency === null) {
|
||||
throw Error();
|
||||
}
|
||||
} catch (_error) {
|
||||
preferredFiatCurrency = FiatUnit.USD;
|
||||
}
|
||||
if (+new Date() - lang[STRUCT.LAST_UPDATED] <= 30 * 60 * 1000) {
|
||||
if (+new Date() - exchangeRates[STRUCT.LAST_UPDATED] <= 30 * 60 * 1000) {
|
||||
// not updating too often
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
preferredFiatCurrency = JSON.parse(await AsyncStorage.getItem(AppStorage.PREFERRED_CURRENCY));
|
||||
} catch (_) {}
|
||||
preferredFiatCurrency = preferredFiatCurrency || FiatUnit.USD;
|
||||
|
||||
let json;
|
||||
try {
|
||||
const api = new Frisbee({
|
||||
baseURI: 'https://www.bitstamp.net',
|
||||
baseURI: 'https://api.coindesk.com',
|
||||
});
|
||||
let response = await api.get('/api/v2/ticker/' + preferredFiatCurrency.endPointKey);
|
||||
json = response.body;
|
||||
if (typeof json === 'undefined' || typeof json.last === 'undefined') {
|
||||
let response = await api.get('/v1/bpi/currentprice/' + preferredFiatCurrency.endPointKey + '.json');
|
||||
json = JSON.parse(response.body);
|
||||
if (!json || !json.bpi || !json.bpi[preferredFiatCurrency.endPointKey] || !json.bpi[preferredFiatCurrency.endPointKey].rate_float) {
|
||||
throw new Error('Could not update currency rate: ' + response.err);
|
||||
}
|
||||
} catch (Err) {
|
||||
|
@ -42,53 +51,51 @@ async function updateExchangeRate() {
|
|||
return;
|
||||
}
|
||||
|
||||
lang[STRUCT.LAST_UPDATED] = +new Date();
|
||||
lang[STRUCT[preferredFiatCurrency.storageKey]] = json.last * 1;
|
||||
await AsyncStorage.setItem(AppStorage.CURRENCY, JSON.stringify(lang));
|
||||
exchangeRates[STRUCT.LAST_UPDATED] = +new Date();
|
||||
exchangeRates['BTC_' + preferredFiatCurrency.endPointKey] = json.bpi[preferredFiatCurrency.endPointKey].rate_float * 1;
|
||||
await AsyncStorage.setItem(AppStorage.EXCHANGE_RATES, JSON.stringify(exchangeRates));
|
||||
await AsyncStorage.setItem(AppStorage.PREFERRED_CURRENCY, JSON.stringify(preferredFiatCurrency));
|
||||
}
|
||||
|
||||
async function startUpdater(force = false) {
|
||||
if (force) {
|
||||
const lang = JSON.parse(await AsyncStorage.getItem(AppStorage.CURRENCY));
|
||||
delete lang[STRUCT.LAST_UPDATED];
|
||||
await AsyncStorage.setItem(AppStorage.CURRENCY, JSON.stringify(lang));
|
||||
try {
|
||||
preferredFiatCurrency = JSON.parse(await AsyncStorage.getItem(AppStorage.PREFERREDCURRENCY));
|
||||
if (preferredFiatCurrency === null) {
|
||||
throw Error();
|
||||
}
|
||||
} catch (_error) {
|
||||
preferredFiatCurrency = FiatUnit.USD;
|
||||
}
|
||||
let interval = false;
|
||||
async function startUpdater() {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
exchangeRates[STRUCT.LAST_UPDATED] = 0;
|
||||
}
|
||||
lang = await AsyncStorage.getItem(AppStorage.CURRENCY);
|
||||
try {
|
||||
lang = JSON.parse(lang);
|
||||
} catch (Err) {
|
||||
lang = {};
|
||||
}
|
||||
lang = lang || {};
|
||||
lang[STRUCT.LAST_UPDATED] = lang[STRUCT.LAST_UPDATED] || 0;
|
||||
lang[STRUCT[preferredFiatCurrency.storageKey]] = lang[STRUCT[preferredFiatCurrency.storageKey]] || 6500;
|
||||
setInterval(() => updateExchangeRate(), 2 * 60 * 100);
|
||||
|
||||
interval = setInterval(() => updateExchangeRate(), 2 * 60 * 100);
|
||||
return updateExchangeRate();
|
||||
}
|
||||
|
||||
function satoshiToLocalCurrency(satoshi) {
|
||||
if (!lang[STRUCT[preferredFiatCurrency.storageKey]]) return satoshi;
|
||||
if (!exchangeRates['BTC_' + preferredFiatCurrency.endPointKey]) return satoshi;
|
||||
|
||||
let b = new BigNumber(satoshi);
|
||||
b = b
|
||||
.dividedBy(100000000)
|
||||
.multipliedBy(lang[STRUCT[preferredFiatCurrency.storageKey]])
|
||||
.multipliedBy(exchangeRates['BTC_' + preferredFiatCurrency.endPointKey])
|
||||
.toString(10);
|
||||
b = parseFloat(b).toFixed(2);
|
||||
|
||||
const formatter = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: preferredFiatCurrency.formatterValue,
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
let formatter;
|
||||
|
||||
try {
|
||||
formatter = new Intl.NumberFormat(preferredFiatCurrency.locale, {
|
||||
style: 'currency',
|
||||
currency: preferredFiatCurrency.endPointKey,
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
console.log(error);
|
||||
formatter = new Intl.NumberFormat(FiatUnit.USD.locale, {
|
||||
style: 'currency',
|
||||
currency: preferredFiatCurrency.endPointKey,
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
}
|
||||
|
||||
return formatter.format(b);
|
||||
}
|
||||
|
||||
|
@ -111,3 +118,5 @@ module.exports.STRUCT = STRUCT;
|
|||
module.exports.satoshiToLocalCurrency = satoshiToLocalCurrency;
|
||||
module.exports.satoshiToBTC = satoshiToBTC;
|
||||
module.exports.BTCToLocalCurrency = BTCToLocalCurrency;
|
||||
module.exports.setPrefferedCurrency = setPrefferedCurrency;
|
||||
module.exports.getPreferredCurrency = getPreferredCurrency;
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>3.4.0</string>
|
||||
<string>3.5.6</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -33,7 +33,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>168</string>
|
||||
<string>216</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
@ -56,7 +56,7 @@
|
|||
<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>NSMotionUsageDescription</key>
|
||||
|
|
|
@ -1 +1 @@
|
|||
2018 BlueWallet Services S.R.L.
|
||||
2019 BlueWallet Services S.R.L.
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
ADD: Persist the preferred unit per wallet.
|
||||
ADD: Deeplinking for bitcoin, lightning
|
||||
ADD: Added fee in tx details
|
||||
ADD: Fiat Currency in settings panel
|
||||
ADD: Select Wallet on Send screen
|
||||
ADD: Currency settings panel (eur, usd)
|
||||
FIX: Disabled autocorrect when importing wallet (security issue)
|
||||
FIX: amount display bug
|
||||
ADD: spend bip44 (legacy HD wallets)
|
||||
FIX: BIP44 mnemonic QR correctly imported
|
||||
ADD: haptic feedback when the user only has 1 wallet
|
||||
v3.5.5
|
||||
------
|
||||
|
||||
ADD: pay zero-amount (tip) invoices
|
||||
ADD: lightning withdrawal through zigzag
|
||||
ADD: Thai translation
|
||||
ADD: Dutch translation
|
||||
ADD: Added Singapore Dollars
|
||||
ADD: Added AUD, VEF, and ZAR fiats.
|
||||
FIX: Loading indicator when creating a wallet
|
||||
FIX: Changelly link
|
||||
Fix and improve pt-BR translation
|
||||
FIX: Cannot click on Lightning transactions #196
|
||||
FIX: Fixed a clipping issue in lightning settings
|
||||
FIX: fixed a margin issue in about that caused clipping
|
||||
FIX: Changed invoice description field to label
|
||||
FIX: Updated transaction buttons maximum width
|
||||
FIX: Main Buttons layout #204
|
||||
FIX: Add topup indication on wallet selection #207
|
||||
FIX: Invoice QR code wrong scale #203
|
||||
FIX: Don't allow user to pay for an invoice created with the same wallet.
|
||||
FIX: If. balance was not a string, app would crash.
|
||||
FIX: Changed language selection screen to FlatList
|
||||
FIX: Made amount tap area larger
|
||||
FIX: Fixed an issue in currency settings where the checkmark wouldn't be in the correct preference
|
37
ios/fastlane/metadata/pt-PT/description.txt
Normal file
37
ios/fastlane/metadata/pt-PT/description.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
Guardar, enviar e receber bitcoin com uma carteira focada na segurança e simplicidade.
|
||||
|
||||
Na Blue Wallet você possui as suas chaves privadas. Uma carteira Bitcoin focada nos usuários.
|
||||
|
||||
Você pode instantaneamente transacionar com qualquer pessoa no mundo e transformar o sistema financeiro diretamente do seu bolso.
|
||||
|
||||
Crie carteiras Bitcoin ilimitadas e gratuitamente, ou acesse as suas carteiras existentes através do seu dispositivo iOS. É simples e rápido.
|
||||
|
||||
As funcionalidades disponíveis:
|
||||
|
||||
1 - Segurança por design
|
||||
|
||||
Open Source
|
||||
Este aplicativo tem licença MIT, pode construir e lança-lo você mesmo! Feito em ReactNative
|
||||
|
||||
Negação plausível
|
||||
Senha falsa que decripta wallets falsas. Para casos especias onde possa ser obrigado a revelar a sua senha, pode revelar a senha falsa, mantenha as suas bitcoin protegidas
|
||||
|
||||
Encriptação completa
|
||||
Construída em cima da multi-camada de encritação do iOS, A BlueWallet encripta tudo com uma adicional senha de usuário
|
||||
|
||||
Carteiras SegWit e HD
|
||||
SegWit suportado (Ajuda a diminuir os fees ainda mais) e carteiras HD activadas
|
||||
|
||||
2 - Focada na sua experiência
|
||||
|
||||
Esteja em control
|
||||
As chaves privadas nunca saiem do celular, você controla as suas chaves privadas
|
||||
|
||||
Fees flexíveis
|
||||
A começar em 1 Satoshi. Não page a mais por transações
|
||||
|
||||
Substituição de Fee (RBF)
|
||||
Acelere as suas transações aumentendo o fee (BIP125). Pode também alterar o endereço de destinatário em transações não confirmadas
|
||||
|
||||
Carteira Sentinela
|
||||
Carteira de "assitir apenas", observe o seu armazenamento externo de Bitcoin sem ter de lhe tocar
|
1
ios/fastlane/metadata/pt-PT/keywords.txt
Normal file
1
ios/fastlane/metadata/pt-PT/keywords.txt
Normal file
|
@ -0,0 +1 @@
|
|||
bitcoin,wallet,segwit,crypto,blockchain,btc,cryptocurrency,wallet,bread,samourai,lightning,ethereum
|
1
ios/fastlane/metadata/pt-PT/marketing_url.txt
Normal file
1
ios/fastlane/metadata/pt-PT/marketing_url.txt
Normal file
|
@ -0,0 +1 @@
|
|||
|
1
ios/fastlane/metadata/pt-PT/name.txt
Normal file
1
ios/fastlane/metadata/pt-PT/name.txt
Normal file
|
@ -0,0 +1 @@
|
|||
BlueWallet - Bitcoin wallet
|
1
ios/fastlane/metadata/pt-PT/privacy_url.txt
Normal file
1
ios/fastlane/metadata/pt-PT/privacy_url.txt
Normal file
|
@ -0,0 +1 @@
|
|||
http://www.bluewallet.io/privacy.txt
|
10
ios/fastlane/metadata/pt-PT/promotional_text.txt
Normal file
10
ios/fastlane/metadata/pt-PT/promotional_text.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
Features
|
||||
|
||||
* Open Source
|
||||
* Full encryption
|
||||
* Plausible deniability
|
||||
* Flexible fees
|
||||
* Replace-By-Fee (RBF)
|
||||
* SegWit
|
||||
* Watch-only (Sentinel) wallets
|
||||
* Lightning network
|
1
ios/fastlane/metadata/pt-PT/release_notes.txt
Symbolic link
1
ios/fastlane/metadata/pt-PT/release_notes.txt
Symbolic link
|
@ -0,0 +1 @@
|
|||
../en-US/release_notes.txt
|
1
ios/fastlane/metadata/pt-PT/subtitle.txt
Normal file
1
ios/fastlane/metadata/pt-PT/subtitle.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Bitcoin & Lightning
|
1
ios/fastlane/metadata/pt-PT/support_url.txt
Normal file
1
ios/fastlane/metadata/pt-PT/support_url.txt
Normal file
|
@ -0,0 +1 @@
|
|||
https://github.com/BlueWallet/BlueWallet/issues
|
213
loc/cs_CZ.js
Normal file
213
loc/cs_CZ.js
Normal file
|
@ -0,0 +1,213 @@
|
|||
module.exports = {
|
||||
_: {
|
||||
storage_is_encrypted: 'Vaše úložiště je zašifrované. Zadejte heslo k odemčení',
|
||||
enter_password: 'Zadejte heslo',
|
||||
bad_password: 'Špatné heslo, prosím zkuste to znovu',
|
||||
months_ago: 'měsíců',
|
||||
days_ago: 'dní',
|
||||
hours_ago: 'hodin',
|
||||
minutes_ago: 'minut',
|
||||
never: 'nikdy',
|
||||
},
|
||||
wallets: {
|
||||
select_wallet: 'Vyberte peněženku',
|
||||
options: 'možnosti',
|
||||
list: {
|
||||
app_name: 'Blue Wallet',
|
||||
title: 'peněženky',
|
||||
header: 'Peněženka reprezentuje pár tajného (privátního) klíče a adresy' + 'kterou můžete sdílet, abyste získali mince',
|
||||
add: 'Přidat peněženku',
|
||||
create_a_wallet: 'Vytvořit peněženku',
|
||||
create_a_wallet1: 'Je to zdarma a můžete vytvořit',
|
||||
create_a_wallet2: 'tolik, kolik budete chtít',
|
||||
latest_transaction: 'poslední transakce',
|
||||
empty_txs1: 'Zde budou zobrazeny vaše transakce,',
|
||||
empty_txs2: 'zatím žádné',
|
||||
tap_here_to_buy: 'Klikněte zde pro zakoupení Bitcoinu',
|
||||
},
|
||||
reorder: {
|
||||
title: 'Seřadit peěženky',
|
||||
},
|
||||
add: {
|
||||
title: 'přidat peněženku',
|
||||
description:
|
||||
'Můžete naskenovat zálohovoanou papírovou peněženku (WIF - Wallet Import Format), nevo vytvořit novou peněženku. Segwit peněženky jsou podporovány standardně.',
|
||||
scan: 'Skenovat',
|
||||
create: 'Vytvořit',
|
||||
label_new_segwit: 'Nová SegWit',
|
||||
label_new_lightning: 'Nová Lightning',
|
||||
wallet_name: 'název peněženky',
|
||||
wallet_type: 'typ',
|
||||
or: 'nebo',
|
||||
import_wallet: 'Importovat peněženku',
|
||||
imported: 'Importována',
|
||||
coming_soon: 'Již brzy',
|
||||
lightning: 'Lightning',
|
||||
bitcoin: 'Bitcoin',
|
||||
},
|
||||
details: {
|
||||
title: 'Peněženka',
|
||||
address: 'Adresa',
|
||||
type: 'Typ',
|
||||
label: 'Popisek',
|
||||
destination: 'cíl',
|
||||
description: 'Popis',
|
||||
are_you_sure: 'Jste si jistý?',
|
||||
yes_delete: 'Ano, smazat',
|
||||
no_cancel: 'Ne, zrušit',
|
||||
delete: 'Smazat',
|
||||
save: 'Uložit',
|
||||
delete_this_wallet: 'Smazat peněženku',
|
||||
export_backup: 'Exportovat / zálohovat',
|
||||
buy_bitcoin: 'Koupit Bitcoin',
|
||||
show_xpub: 'Ukázat XPUB',
|
||||
},
|
||||
export: {
|
||||
title: 'exportovat peněženku',
|
||||
},
|
||||
xpub: {
|
||||
title: 'XPUB peněženky',
|
||||
copiedToClipboard: 'Zkopírováno do schránky.',
|
||||
},
|
||||
import: {
|
||||
title: 'importovat',
|
||||
explanation:
|
||||
'Zadejte zde svůj mnemonic seed, privátní klíč, WIF, nebo cokoliv co máte. BlueWallet se pokusí uhodnout správný formát a naimportovat vaší peněženku',
|
||||
imported: 'Importováno',
|
||||
error: 'Chyba při importu. Prosím ujistěte se, že poskytnutá data jsou správná.',
|
||||
success: 'Úspěch',
|
||||
do_import: 'Importovat',
|
||||
scan_qr: 'nebo raději naskenovat QR kód?',
|
||||
},
|
||||
scanQrWif: {
|
||||
go_back: 'Zpět',
|
||||
cancel: 'Zrušit',
|
||||
decoding: 'Dekóduji',
|
||||
input_password: 'Vložte heslo',
|
||||
password_explain: 'Toto je BIP38 zašifrovaný privátní klíč',
|
||||
bad_password: 'Špatné heslo',
|
||||
wallet_already_exists: 'Tato peněženka již existuje',
|
||||
bad_wif: 'Špatný WIF',
|
||||
imported_wif: 'Importovaný WIF ',
|
||||
with_address: ' s adresou ',
|
||||
imported_segwit: 'Importovaná SegWit',
|
||||
imported_legacy: 'Importovaná Legacy',
|
||||
imported_watchonly: 'Importovaná Watch-only',
|
||||
},
|
||||
},
|
||||
transactions: {
|
||||
list: {
|
||||
tabBarLabel: 'Transakce',
|
||||
title: 'transakce',
|
||||
description: 'Seznam příchozích a odchozích transakcí vašich peněženek',
|
||||
conf: 'potvrzení',
|
||||
},
|
||||
details: {
|
||||
title: 'Transakce',
|
||||
from: 'Input',
|
||||
to: 'Output',
|
||||
copy: 'Kopírovat',
|
||||
transaction_details: 'Detaily transakce',
|
||||
show_in_block_explorer: 'Ukázat v block exploreru',
|
||||
},
|
||||
},
|
||||
send: {
|
||||
header: 'Poslat',
|
||||
details: {
|
||||
title: 'vytvořit transakci',
|
||||
amount_field_is_not_valid: 'Čáskta není správně vyplněna',
|
||||
fee_field_is_not_valid: 'Poplatek není správně vyplněn',
|
||||
address_field_is_not_valid: 'Adresa není správně vyplněna',
|
||||
total_exceeds_balance: 'Částka, kterou se snažíte poslat, přesahuje dostupný zůstatek.',
|
||||
create_tx_error: 'Nastala chyba při vytváření transakce. Prosím ujistěte se, že adresa je platná.',
|
||||
address: 'adresa',
|
||||
amount_placeholder: 'částka k odeslání (v BTC)',
|
||||
fee_placeholder: 'plus transakční poplatek (v BTC)',
|
||||
note_placeholder: 'poznámka pro sebe',
|
||||
cancel: 'Zrušit',
|
||||
scan: 'Skenovat',
|
||||
send: 'Poslat',
|
||||
create: 'Vytvořit',
|
||||
remaining_balance: 'Zbývající zůstatek',
|
||||
},
|
||||
confirm: {
|
||||
header: 'Potvrdit',
|
||||
sendNow: 'Poslat hned',
|
||||
},
|
||||
success: {
|
||||
done: 'Hotovo',
|
||||
},
|
||||
create: {
|
||||
details: 'Detaily',
|
||||
title: 'vytvořit transakci',
|
||||
error: 'Chyba při vytváření transakce. Nesprávná adresa nebo částka?',
|
||||
go_back: 'Zpět',
|
||||
this_is_hex: 'Toto je vaše transakce, podepsána a připravena k odeslání do sítě.',
|
||||
to: 'To',
|
||||
amount: 'Částka',
|
||||
fee: 'Poplatek',
|
||||
tx_size: 'velikost transakce',
|
||||
satoshi_per_byte: 'Satoshi/byte',
|
||||
memo: 'Popisek',
|
||||
broadcast: 'Odeslat do sítě',
|
||||
not_enough_fee: 'Nedostatečný poplatek. Zvyšte poplatek.',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: 'Přijmout',
|
||||
details: {
|
||||
title: 'Sdílejte tuto adresu s plátcem',
|
||||
share: 'sdílet',
|
||||
copiedToClipboard: 'Zkopírováno do schránky.',
|
||||
label: 'Popis',
|
||||
setAmount: 'Přijmout částku...',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: 'Koupit Bitcoin',
|
||||
tap_your_address: 'Klikněte na svojí adresu pro zkopírování do schránky:',
|
||||
copied: 'Zkopírováno do schránky.',
|
||||
},
|
||||
settings: {
|
||||
header: 'nastavení',
|
||||
plausible_deniability: 'Plausible deniability...',
|
||||
storage_not_encrypted: 'Uložiště: nezašifrováno',
|
||||
storage_encrypted: 'Úložiště: zašifrováno',
|
||||
password: 'Heslo',
|
||||
password_explain: 'Vytořte si heslo k zašifrování úložiště.',
|
||||
retype_password: 'Heslo znovu',
|
||||
passwords_do_not_match: 'Hesla se neshodují',
|
||||
encrypt_storage: 'Zašifrovat úložiště',
|
||||
about: 'O BlueWallet',
|
||||
language: 'Jazyk',
|
||||
currency: 'Měna',
|
||||
},
|
||||
plausibledeniability: {
|
||||
title: 'Plausible Deniability',
|
||||
help:
|
||||
'Za určitých okolností můžete být donuceni k prozrazení vašeho hesla.' +
|
||||
'K zajištění bezpečností vašich prostředků, BlueWallet může vytvořit' +
|
||||
'další zašifrované úložiště s rozdílný heslem. V případě potřeby' +
|
||||
'můžete toto heslo dát třetí straně. Pokud bude zadáno do BlueWallet,' +
|
||||
'odemkne nové "falešné" úložiště. Toto bude vypadat legitimně, ale' +
|
||||
'udrží vaše pravé hlavní úložiště v bezpečí.',
|
||||
help2: 'Nové úložiště bude plně funkční, můžete na něj uložit minimální částku, aby vypadalo více uvěřitelně.',
|
||||
create_fake_storage: 'Vytvořit falešné zašifrované úložiště',
|
||||
go_back: 'Zpět',
|
||||
create_password: 'Vytvořit heslo',
|
||||
create_password_explanation: 'Heslo k falešnému úložišti nesmí být stejné jako heslo k hlavnímu úložišti',
|
||||
password_should_not_match: 'Heslo k falešnému úložišti nesmí být stejné jako heslo k hlavnímu úložišti',
|
||||
retype_password: 'Heslo znovu',
|
||||
passwords_do_not_match: 'Hesla se neshodují, zkuste to znovu',
|
||||
success: 'Úspěch',
|
||||
},
|
||||
lnd: {
|
||||
title: 'spravovat zůstatek',
|
||||
choose_source_wallet: 'Vyberte zdrojovou peněženku',
|
||||
refill_lnd_balance: 'Doplnit zůstatek na Lightning peněžence',
|
||||
refill: 'Doplnit',
|
||||
withdraw: 'Vybrat',
|
||||
expired: 'Expirováno',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
|
@ -15,10 +15,11 @@ module.exports = {
|
|||
list: {
|
||||
app_name: 'Blue Wallet',
|
||||
title: 'Wallets',
|
||||
header: 'Eine Wallet (Brieftasche) spiegelt ein Paar von kryptographischen Schlüssel wider. Einen geheimen und eine Adresse als öffentlichen Schlüssel. Letztern kann man zum Erhalt von Bitcoin teilen.',
|
||||
header:
|
||||
'Eine Wallet (Brieftasche) spiegelt ein Paar von kryptographischen Schlüssel wider. Einen geheimen und eine Adresse als öffentlichen Schlüssel. Letztern kann man zum Erhalt von Bitcoin teilen.',
|
||||
add: 'Wallet hinzufügen',
|
||||
create_a_wallet: 'Wallet erstellen',
|
||||
create_a_wallet1: "Es ist kostenlos und du kannst",
|
||||
create_a_wallet1: 'Es ist kostenlos und du kannst',
|
||||
create_a_wallet2: 'so viele erstellen, wie du möchtest',
|
||||
latest_transaction: 'Lezte Transaktion',
|
||||
empty_txs1: 'Deine Transaktionen erscheinen hier',
|
||||
|
@ -72,7 +73,7 @@ module.exports = {
|
|||
import: {
|
||||
title: 'Importieren',
|
||||
explanation:
|
||||
"Gib hier deine mnemonische Phrase, deinen privaten Schlüssel, WIF oder worüber du auch immer verfügst ein. BlueWallet wird bestmöglich dein Format interpretieren und die Wallet importieren",
|
||||
'Gib hier deine mnemonische Phrase, deinen privaten Schlüssel, WIF oder worüber du auch immer verfügst ein. BlueWallet wird bestmöglich dein Format interpretieren und die Wallet importieren',
|
||||
imported: 'Importiert',
|
||||
error: 'Fehler beim Import. Ist die Eingabe korrekt?',
|
||||
success: 'Erfolg',
|
||||
|
@ -209,5 +210,6 @@ module.exports = {
|
|||
refill_lnd_balance: 'Fülle deine Lightning Wallet auf',
|
||||
refill: 'Auffüllen',
|
||||
withdraw: 'Abheben',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -74,7 +74,7 @@ module.exports = {
|
|||
explanation:
|
||||
"Write here your mnemonic, private key, WIF, or anything you've got. BlueWallet will do its best to guess the correct format and import your wallet",
|
||||
imported: 'Imported',
|
||||
error: 'Failed to import. Is the event valid?',
|
||||
error: 'Failed to import. Please, make sure that the provided data is valid.',
|
||||
success: 'Success',
|
||||
do_import: 'Import',
|
||||
scan_qr: 'or scan QR code instead?',
|
||||
|
@ -187,7 +187,7 @@ module.exports = {
|
|||
help:
|
||||
'Under certain circumstances, you might be forced to disclose a ' +
|
||||
'password. To keep your coins safe, BlueWallet can create another ' +
|
||||
'encrypted storage, with a different password. Under the pressure, ' +
|
||||
'encrypted storage, with a different password. Under pressure, ' +
|
||||
'you can disclose this password to a 3rd party. If entered in ' +
|
||||
"BlueWallet, it will unlock new 'fake' storage. This will seem " +
|
||||
'legit to a 3rd party, but will secretly keep your main storage ' +
|
||||
|
@ -208,5 +208,7 @@ module.exports = {
|
|||
refill_lnd_balance: 'Refill Lightning wallet balance',
|
||||
refill: 'Refill',
|
||||
withdraw: 'Withdraw',
|
||||
expired: 'Expired',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -210,5 +210,7 @@ module.exports = {
|
|||
refill_lnd_balance: 'Rellenar el balance de la billetera Lightning',
|
||||
refill: 'Rellenar',
|
||||
withdraw: 'Retirar',
|
||||
expired: 'Expirado',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
||||
|
|
215
loc/fr_FR.js
Normal file
215
loc/fr_FR.js
Normal file
|
@ -0,0 +1,215 @@
|
|||
module.exports = {
|
||||
_: {
|
||||
storage_is_encrypted: 'L\'espace de stockage est chiffré. Mot de passe requis pour le déchiffrer.',
|
||||
enter_password: 'Saisir mot de passe',
|
||||
bad_password: 'Mauvais mot de passe, ré-essayer',
|
||||
months_ago: 'mois',
|
||||
days_ago: 'jours',
|
||||
hours_ago: 'heures',
|
||||
minutes_ago: 'minutes',
|
||||
never: 'jamais',
|
||||
},
|
||||
wallets: {
|
||||
select_wallet: 'Choix du portefeuille',
|
||||
options: 'options',
|
||||
list: {
|
||||
app_name: 'Blue Wallet',
|
||||
title: 'portefeuilles',
|
||||
header: 'Un portefeuille represente une paire de clées (publique/privée) et une adresse que vous pouvez partager pour recevoir des transactions.',
|
||||
add: 'Ajouter un portefeuille',
|
||||
create_a_wallet: 'Créer un portefeuille',
|
||||
create_a_wallet1: "C\'est gratuit et vous pouvez en créer",
|
||||
create_a_wallet2: 'autant que vous souhaitez',
|
||||
latest_transaction: 'dernière transaction',
|
||||
empty_txs1: 'Vos transactions apparaîtront ici,',
|
||||
empty_txs2: 'Aucune pour le moment',
|
||||
tap_here_to_buy: 'Cliquez ici pour acheter du Bitcoin',
|
||||
},
|
||||
reorder: {
|
||||
title: 'Trier vos portefeuilles',
|
||||
},
|
||||
add: {
|
||||
title: 'ajouter un portefeuille',
|
||||
description:
|
||||
'Vous pouvez soit scanner et importer un paper wallet (au format WIF - Wallet Import Format), ou créer un nouveau portefeuille. Compatible avec Segwit par defaut.',
|
||||
scan: 'Scanner',
|
||||
create: 'Créer',
|
||||
label_new_segwit: 'Nouveau SegWit',
|
||||
label_new_lightning: 'Nouveau Lightning',
|
||||
wallet_name: 'nom du portefeuille',
|
||||
wallet_type: 'type',
|
||||
or: 'ou',
|
||||
import_wallet: 'Importer un portefeuille',
|
||||
imported: 'Importé',
|
||||
coming_soon: 'Bientôt',
|
||||
lightning: 'Lightning',
|
||||
bitcoin: 'Bitcoin',
|
||||
},
|
||||
details: {
|
||||
title: 'Portefeuille',
|
||||
address: 'Adresse',
|
||||
type: 'Type',
|
||||
label: 'Libelé',
|
||||
destination: 'destination',
|
||||
description: 'description',
|
||||
are_you_sure: 'Êtes vous sur?',
|
||||
yes_delete: 'Oui, supprimer',
|
||||
no_cancel: 'Non, annuler',
|
||||
delete: 'Supprimer',
|
||||
save: 'Sauvegarder',
|
||||
delete_this_wallet: 'Supprimer ce portefeuille',
|
||||
export_backup: 'Exporter / sauvegarder',
|
||||
buy_bitcoin: 'Acheter du Bitcoin',
|
||||
show_xpub: 'Afficher XPUB du portefeuille',
|
||||
},
|
||||
export: {
|
||||
title: 'export du portefeuille',
|
||||
},
|
||||
xpub: {
|
||||
title: 'XPUB portefeuille',
|
||||
copiedToClipboard: 'Copié dans le presse-papiers.',
|
||||
},
|
||||
import: {
|
||||
title: 'importer',
|
||||
explanation:
|
||||
"Write here your mnemonic, private key, WIF, or anything you've got. BlueWallet will do its best to guess the correct format and import your wallet",
|
||||
imported: 'Importé',
|
||||
error: 'Échec de l\'import. Merci, de vérifier que les données saisies sont valides.',
|
||||
success: 'Succès',
|
||||
do_import: 'Importer',
|
||||
scan_qr: 'ou scaner un QR code',
|
||||
},
|
||||
scanQrWif: {
|
||||
go_back: 'Retour',
|
||||
cancel: 'Annuler',
|
||||
decoding: 'Déchiffrage',
|
||||
input_password: 'Saisir mot de passe',
|
||||
password_explain: 'Ceci est une clée privée chiffrée avec BIP38',
|
||||
bad_password: 'Mauvais mot de passe',
|
||||
wallet_already_exists: 'Ce portefeuille existe déjà',
|
||||
bad_wif: 'Mauvais WIF',
|
||||
imported_wif: 'WIF Importé',
|
||||
with_address: ' avec adresse ',
|
||||
imported_segwit: 'SegWit Importé',
|
||||
imported_legacy: 'Legacy Importé',
|
||||
imported_watchonly: 'Monitoring Importé',
|
||||
},
|
||||
},
|
||||
transactions: {
|
||||
list: {
|
||||
tabBarLabel: 'Transactions',
|
||||
title: 'transactions',
|
||||
description: 'Une liste des transactions entrentes et sortantes de vos portefeuilles',
|
||||
conf: 'conf',
|
||||
},
|
||||
details: {
|
||||
title: 'Transaction',
|
||||
from: 'De',
|
||||
to: 'À',
|
||||
copy: 'Copier',
|
||||
transaction_details: 'Détails de la transaction',
|
||||
show_in_block_explorer: 'Afficher dans le "block explorer"',
|
||||
},
|
||||
},
|
||||
send: {
|
||||
header: 'Envoyer',
|
||||
details: {
|
||||
title: 'créer une transaction',
|
||||
amount_field_is_not_valid: 'Champ montant invalide',
|
||||
fee_field_is_not_valid: 'Champ frais invalide',
|
||||
address_field_is_not_valid: 'Champ adresse invalide',
|
||||
total_exceeds_balance: 'Le montant à envoyer excède le montant disponible.',
|
||||
create_tx_error: 'There was an error creating the transaction. Please, make sure the address is valid.',
|
||||
address: 'adresse',
|
||||
amount_placeholder: 'montant à envoyer (en BTC)',
|
||||
fee_placeholder: 'plus frais de transaction (en BTC)',
|
||||
note_placeholder: 'note (optionnelle)',
|
||||
cancel: 'Annuler',
|
||||
scan: 'Scanner',
|
||||
send: 'Envoyer',
|
||||
create: 'Créer',
|
||||
remaining_balance: 'Balance restante',
|
||||
},
|
||||
confirm: {
|
||||
header: 'Confirmer',
|
||||
sendNow: 'Envoyer maintenant',
|
||||
},
|
||||
success: {
|
||||
done: 'Terminé',
|
||||
},
|
||||
create: {
|
||||
details: 'Details',
|
||||
title: 'créer une transaction',
|
||||
error: 'Erreur creating transaction. Invalid address or send amount?',
|
||||
go_back: 'Retour',
|
||||
this_is_hex: 'This is transaction hex, signed and ready to be broadcast to the network.',
|
||||
to: 'À',
|
||||
amount: 'Montant',
|
||||
fee: 'Frais',
|
||||
tx_size: 'Taille de la Transaction (TX size)',
|
||||
satoshi_per_byte: 'Satoshi par byte',
|
||||
memo: 'Memo',
|
||||
broadcast: 'Broadcast',
|
||||
not_enough_fee: 'Frais insufisants. Veuillez augmenter les frais',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: 'Recevoir',
|
||||
details: {
|
||||
title: 'Partager cette adresse avec le destinataire',
|
||||
share: 'partager',
|
||||
copiedToClipboard: 'Copier dans le presse-papiers.',
|
||||
label: 'Description',
|
||||
setAmount: 'Revevoir avec montant',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: 'Acheter du Bitcoin',
|
||||
tap_your_address: 'Cliquez votre adresse pour la copier:',
|
||||
copied: 'Copié dans le presse-papiers!',
|
||||
},
|
||||
settings: {
|
||||
header: 'réglages',
|
||||
plausible_deniability: 'Déni plausible...',
|
||||
storage_not_encrypted: 'Stockage: non chiffré',
|
||||
storage_encrypted: 'Stockage: chiffré',
|
||||
password: 'Mot de passe',
|
||||
password_explain: 'Créer le mot de passe utilisé pour déchiffrer l\'espace de stockage principal',
|
||||
retype_password: 'Re-saisir votre mot de passe',
|
||||
passwords_do_not_match: 'Les mots de passe ne correspondent pas',
|
||||
encrypt_storage: 'Chiffrer le stockage',
|
||||
about: 'À propos',
|
||||
language: 'Langue',
|
||||
currency: 'Devise',
|
||||
},
|
||||
plausibledeniability: {
|
||||
title: 'Déni plausible',
|
||||
help:
|
||||
'Dans certaines circonstances, vous serez peut-être forcé par un tiers à communiquer ' +
|
||||
'votre mot de passe. Pour protéger vos biens, BlueWallet permet de créer un autre ' +
|
||||
'espace de stockage, avec un mot de passe différent. Sous la contrainte, ' +
|
||||
'vous pourrez divulger ce mot de passe au tier. Quand il est saisi ' +
|
||||
"BlueWallet, débloquera se 'faux' espace de stockage. Le tiers pourra " +
|
||||
'confondre ces données avec des données légitimes, votre espace de stockage ' +
|
||||
'principal restera sécurisé et hors d\'atteinte.',
|
||||
help2: 'New storage will be fully functional, and you can store some ' + 'minimum amounts there so it looks more believable.',
|
||||
create_fake_storage: 'Créer un faux espace de stockage chiffré',
|
||||
go_back: 'Retour',
|
||||
create_password: 'Créer un mot de passe',
|
||||
create_password_explanation: 'Le mot de passe pour le faux espace de stockage ne doit pas être le même que celui du stockage principal',
|
||||
password_should_not_match: 'Le mot de passe pour le faux espace de stockage ne doit pas être le même que celui du stockage principal',
|
||||
retype_password: 'Confirmation du mot de passe',
|
||||
passwords_do_not_match: 'Vos mot de passe ne sont pas identiques, veillez ré-essayer',
|
||||
success: 'Succès',
|
||||
},
|
||||
lnd: {
|
||||
title: 'gérer vos fonds',
|
||||
choose_source_wallet: 'Choisir un portefeuille source',
|
||||
refill_lnd_balance: 'Déposer des fonds dans votre portfeuille Lightning',
|
||||
refill: 'Déposer des fonds',
|
||||
withdraw: 'Retirer des fonds',
|
||||
expired: 'Expiré',
|
||||
sameWalletAsInvoiceError: 'Vous ne pouvez pas payer une facture avec le même portefeuille utilisé pour la créer.',
|
||||
},
|
||||
};
|
||||
|
26
loc/index.js
26
loc/index.js
|
@ -21,7 +21,19 @@ let strings;
|
|||
locale = locale.split('-');
|
||||
locale = locale[0];
|
||||
console.log('current locale:', locale);
|
||||
if (locale === 'en' || locale === 'ru' || locale === 'ua' || locale === 'es' || locale === 'pt-br' || locale === 'pt-pt' || locale === 'de-de') {
|
||||
if (
|
||||
locale === 'en' ||
|
||||
locale === 'ru' ||
|
||||
locale === 'ua' ||
|
||||
locale === 'es' ||
|
||||
locale === 'fr-fr' ||
|
||||
locale === 'pt-br' ||
|
||||
locale === 'pt-pt' ||
|
||||
locale === 'de-de' ||
|
||||
locale === 'cs-cz' ||
|
||||
locale === 'th-th' ||
|
||||
locale === 'nl-nl'
|
||||
) {
|
||||
locale = locale.replace('-', '_');
|
||||
strings.setLanguage(locale);
|
||||
} else {
|
||||
|
@ -38,7 +50,11 @@ strings = new Localization({
|
|||
pt_pt: require('./pt_PT.js'),
|
||||
es: require('./es.js'),
|
||||
ua: require('./ua.js'),
|
||||
de_de: require('.de_DE.js')
|
||||
de_de: require('./de_DE.js'),
|
||||
cs_cz: require('./cs_CZ.js'),
|
||||
th_th: require('./th_TH.js'),
|
||||
nl_nl: require('./nl_NL.js'),
|
||||
fr_fr: require('./fr_FR.js'),
|
||||
});
|
||||
|
||||
strings.saveLanguage = lang => AsyncStorage.setItem(AppStorage.LANG, lang);
|
||||
|
@ -90,7 +106,7 @@ strings.formatBalance = (balance, toUnit) => {
|
|||
return balance + ' ' + BitcoinUnit.BTC;
|
||||
} else if (toUnit === BitcoinUnit.SATS) {
|
||||
const value = new BigNumber(balance).multipliedBy(100000000);
|
||||
return value.toString() + ' ' + BitcoinUnit.SATS;
|
||||
return new Intl.NumberFormat().format(value.toString()) + ' ' + BitcoinUnit.SATS;
|
||||
} else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) {
|
||||
return currency.BTCToLocalCurrency(balance);
|
||||
}
|
||||
|
@ -111,12 +127,12 @@ strings.formatBalanceWithoutSuffix = (balance, toUnit) => {
|
|||
const value = new BigNumber(balance).dividedBy(100000000).toFixed(8);
|
||||
return removeTrailingZeros(value);
|
||||
} else if (toUnit === BitcoinUnit.SATS) {
|
||||
return balance;
|
||||
return new Intl.NumberFormat().format(balance);
|
||||
} else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) {
|
||||
return currency.satoshiToLocalCurrency(balance);
|
||||
}
|
||||
}
|
||||
return balance;
|
||||
return balance.toString();
|
||||
};
|
||||
|
||||
module.exports = strings;
|
||||
|
|
216
loc/nl_NL.js
Normal file
216
loc/nl_NL.js
Normal file
|
@ -0,0 +1,216 @@
|
|||
module.exports = {
|
||||
_: {
|
||||
storage_is_encrypted: 'Uw opslag is versleuteld. Wachtwoord is vereist om het te ontcijferen',
|
||||
enter_password: 'Voer wachtwoord in',
|
||||
bad_password: 'Verkeerd wachtwoord, probeer opnieuw',
|
||||
months_ago: 'maanden geleden',
|
||||
days_ago: 'dagen geleden',
|
||||
hours_ago: 'uur geleden',
|
||||
minutes_ago: 'minuten geleden',
|
||||
never: 'nooit',
|
||||
},
|
||||
wallets: {
|
||||
select_wallet: 'Selecteer portemonnee',
|
||||
options: 'opties',
|
||||
list: {
|
||||
app_name: 'Blue Wallet',
|
||||
title: 'portemonnees',
|
||||
header: 'Een portemonnee vertegenwoordigt een geheime (privésleutel) en een adres' + 'dat u kunt delen om munten te ontvangen.',
|
||||
add: 'Portemonnee toevoegen',
|
||||
create_a_wallet: 'Portemonnee aanmaken',
|
||||
create_a_wallet1: 'Het is gratis en u kunt er',
|
||||
create_a_wallet2: 'zoveel maken als u wilt',
|
||||
latest_transaction: 'laatste transactie',
|
||||
empty_txs1: 'Uw transacties verschijnen hier,',
|
||||
empty_txs2: 'geen transacties op dit moment',
|
||||
tap_here_to_buy: 'Klik hier om Bitcoin te kopen',
|
||||
},
|
||||
reorder: {
|
||||
title: 'Portemonnees opnieuw ordenen',
|
||||
},
|
||||
add: {
|
||||
title: 'portemonnee toevoegen',
|
||||
description:
|
||||
'U kunt een back-up papieren portemonnee scannen (in WIF - Wallet Import Format) of een nieuwe portemonnee maken. Segwit-wallets worden standaard ondersteund.',
|
||||
scan: 'Scannen',
|
||||
create: 'Aanmaken',
|
||||
label_new_segwit: 'Nieuwe SegWit',
|
||||
label_new_lightning: 'Nieuwe Lightning',
|
||||
wallet_name: 'portemonnee naam',
|
||||
wallet_type: 'type',
|
||||
or: 'of',
|
||||
import_wallet: 'Portemonnee importeren',
|
||||
imported: 'Geïmporteerd',
|
||||
coming_soon: 'Komt binnenkort',
|
||||
lightning: 'Lightning',
|
||||
bitcoin: 'Bitcoin',
|
||||
},
|
||||
details: {
|
||||
title: 'Portemonnee',
|
||||
address: 'Adres',
|
||||
type: 'Type',
|
||||
label: 'Label',
|
||||
destination: 'bestemming',
|
||||
description: 'beschrijving',
|
||||
are_you_sure: 'Weet u het zeker?',
|
||||
yes_delete: 'Ja, verwijderen',
|
||||
no_cancel: 'Nee, annuleren',
|
||||
delete: 'Verwijderen',
|
||||
save: 'Opslaan',
|
||||
delete_this_wallet: 'Verwijder deze portemonnee',
|
||||
export_backup: 'Exporteren / back-up maken',
|
||||
buy_bitcoin: 'Koop Bitcoin',
|
||||
show_xpub: 'Toon portemonnee XPUB',
|
||||
},
|
||||
export: {
|
||||
title: 'portemonnee exporteren',
|
||||
},
|
||||
xpub: {
|
||||
title: 'portemonnee XPUB',
|
||||
copiedToClipboard: 'Gekopieerd naar het klembord.',
|
||||
},
|
||||
import: {
|
||||
title: 'importeren',
|
||||
explanation:
|
||||
'Schrijf hier uw ezelsbruggetje, privésleutel, WIF, of een ander formaat. BlueWallet zal zijn best doen om het juiste formaat te raden en uw portemonnee te importeren',
|
||||
imported: 'Geïmporteerd',
|
||||
error: 'Importeren mislukt. Zorg ervoor dat de verstrekte gegevens geldig zijn.',
|
||||
success: 'Succes',
|
||||
do_import: 'Importeren',
|
||||
scan_qr: 'of QR-code scannen?',
|
||||
},
|
||||
scanQrWif: {
|
||||
go_back: 'Ga terug',
|
||||
cancel: 'Annuleren',
|
||||
decoding: 'Decoderen',
|
||||
input_password: 'Voer wachtwoord in',
|
||||
password_explain: 'Dit is een BIP38-gecodeerde privésleutel',
|
||||
bad_password: 'Verkeerd wachtwoord',
|
||||
wallet_already_exists: "Zo'n portemonnee bestaat al",
|
||||
bad_wif: 'Verkeerde WIF',
|
||||
imported_wif: 'WIF geïmporteerd ',
|
||||
with_address: ' met adres ',
|
||||
imported_segwit: 'SegWit geïmporteerd',
|
||||
imported_legacy: 'Legacy geïmporteerd',
|
||||
imported_watchonly: 'Watch-only geïmporteerd',
|
||||
},
|
||||
},
|
||||
transactions: {
|
||||
list: {
|
||||
tabBarLabel: 'Transacties',
|
||||
title: 'transacties',
|
||||
description: 'Een lijst met ingaande of uitgaande transacties van uw portemonnee',
|
||||
conf: 'conf',
|
||||
},
|
||||
details: {
|
||||
title: 'Transacties',
|
||||
from: 'Invoer',
|
||||
to: 'Uitgang',
|
||||
copy: 'Kopiëren',
|
||||
transaction_details: 'Transactie details',
|
||||
show_in_block_explorer: 'Weergeven in blokverkenner',
|
||||
},
|
||||
},
|
||||
send: {
|
||||
header: 'Vertuur',
|
||||
details: {
|
||||
title: 'transacties aanmaken',
|
||||
amount_field_is_not_valid: 'Bedrag veld is niet geldig',
|
||||
fee_field_is_not_valid: 'Tarief is niet geldig',
|
||||
address_field_is_not_valid: 'Adresveld is niet geldig',
|
||||
total_exceeds_balance: 'Het verzendingsbedrag overschrijdt het beschikbare saldo.',
|
||||
create_tx_error: 'Er is een fout opgetreden bij het maken van de transactie. Zorg ervoor dat het adres geldig is.',
|
||||
address: 'adres',
|
||||
amount_placeholder: 'te verzenden bedrag (in BTC)',
|
||||
fee_placeholder: 'plus transactie vergoeding (in BTC)',
|
||||
note_placeholder: 'notitie voor mezelf',
|
||||
cancel: 'Annuleren',
|
||||
scan: 'Scannen',
|
||||
send: 'Verzenden',
|
||||
create: 'Aanmaken',
|
||||
remaining_balance: 'Resterende saldo',
|
||||
},
|
||||
confirm: {
|
||||
header: 'Bevestig',
|
||||
sendNow: 'Nu verzenden',
|
||||
},
|
||||
success: {
|
||||
done: 'Klaar',
|
||||
},
|
||||
create: {
|
||||
details: 'Details',
|
||||
title: 'transactie aanmaken',
|
||||
error: 'Fout bij het maken van transactie. Ongeldig adres of bedrag?',
|
||||
go_back: 'Ga terug',
|
||||
this_is_hex: 'Dit is de transactie-hex, ondertekend en klaar om op het netwerk te worden uitgezonden.',
|
||||
to: 'Naar',
|
||||
amount: 'Bedrag',
|
||||
fee: 'Vergoeding',
|
||||
tx_size: 'TX grootte',
|
||||
satoshi_per_byte: 'Satoshi per byte',
|
||||
memo: 'Memo',
|
||||
broadcast: 'Uitzenden',
|
||||
not_enough_fee: 'Niet genoeg vergoeding. Verhoog de vergoeding',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: 'Ontvang',
|
||||
details: {
|
||||
title: 'Deel dit adres met betaler',
|
||||
share: 'delen',
|
||||
copiedToClipboard: 'Gekopieerd naar het klembord.',
|
||||
label: 'Omschrijving',
|
||||
setAmount: 'Ontvang met bedrag',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: 'Koop Bitcoin',
|
||||
tap_your_address: 'Tik op uw adres om het naar het klembord te kopiëren:',
|
||||
copied: 'Gekopieerd naar het klembord!',
|
||||
},
|
||||
settings: {
|
||||
header: 'instellingen',
|
||||
plausible_deniability: 'Plausibele ontkenning...',
|
||||
storage_not_encrypted: 'Opslag: niet versleuteld',
|
||||
storage_encrypted: 'Opslag: versleuteld',
|
||||
password: 'Wachtwoord',
|
||||
password_explain: 'Maak een wachtwoord aan dat u wilt gebruiken om de opslag te versleutelen',
|
||||
retype_password: 'Geef nogmaals het wachtwoord',
|
||||
passwords_do_not_match: 'Wachtwoorden komen niet overeen',
|
||||
encrypt_storage: 'Versleutel opslag',
|
||||
about: 'Over',
|
||||
language: 'Taal',
|
||||
currency: 'Valuta',
|
||||
},
|
||||
plausibledeniability: {
|
||||
title: 'Plausibele ontkenning',
|
||||
help:
|
||||
'Onder bepaalde omstandigheden kunt u worden gedwongen om uw' +
|
||||
' wachtwoord te onthullen. Om uw munten veilig te houden, kan ' +
|
||||
'BlueWallet nog een versleutelde opslag aanmaken, met een ander ' +
|
||||
'wachtwoord. Onder druk kunt u dit wachtwoord bekendmaken aan ' +
|
||||
'de derde partij. Indien ingevoerd in BlueWallet, zal het nieuwe ' +
|
||||
"nep'-opslagruimte worden ontgrendeld. Dit lijkt legitiem voor de " +
|
||||
'derde partij, maar zal uw hoofdopslag met munten niet bekend maken ' +
|
||||
'aan de derde partij',
|
||||
help2:
|
||||
'De nieuwe opslag zal volledig functioneel zijn en u kunt er ' + 'een minimum aantal munten opslaan zodat het geloofwaardig lijkt.',
|
||||
create_fake_storage: 'Nep versleutelde opslag aanmaken',
|
||||
go_back: 'Ga terug',
|
||||
create_password: 'Wachtwoord aanmaken',
|
||||
create_password_explanation: 'Wachtwoord voor nep-opslag hoort niet overeen te komen met wachtwoord voor uw hoofdopslag',
|
||||
password_should_not_match: 'Wachtwoord voor nep-opslag hoort niet overeen te komen met wachtwoord voor uw hoofdopslag',
|
||||
retype_password: 'Herhaal wachtwoord',
|
||||
passwords_do_not_match: 'Wachtwoorden komen niet overeen, probeer het opnieuw',
|
||||
success: 'Succes',
|
||||
},
|
||||
lnd: {
|
||||
title: 'fondsen beheren',
|
||||
choose_source_wallet: 'Kies een bron portemonnee',
|
||||
refill_lnd_balance: 'Vul Lightning-portemonneesaldo bij',
|
||||
refill: 'Bijvullen',
|
||||
withdraw: 'Opvragen',
|
||||
expired: 'Verlopen',
|
||||
sameWalletAsInvoiceError: 'U kunt geen factuur betalen met dezelfde portemonnee die is gebruikt om de factuur te maken.',
|
||||
},
|
||||
};
|
212
loc/pt_BR.js
212
loc/pt_BR.js
|
@ -1,125 +1,125 @@
|
|||
module.exports = {
|
||||
_: {
|
||||
storage_is_encrypted: 'O armazenamento está encriptado. Uma password é necessaria para desencriptar',
|
||||
enter_password: 'Inserir password',
|
||||
bad_password: 'pasword errada, tentar novamente',
|
||||
storage_is_encrypted: 'Os arquivos estão criptografados, é necessária uma senha',
|
||||
enter_password: 'Inserir senha',
|
||||
bad_password: 'Senha errada, tente outra vez',
|
||||
months_ago: 'meses atrás',
|
||||
days_ago: 'dias atrás',
|
||||
hours_ago: 'horas atrás',
|
||||
minutes_ago: 'minutos',
|
||||
never: 'nunca...',
|
||||
minutes_ago: 'minutos atrás',
|
||||
never: 'nunca',
|
||||
},
|
||||
wallets: {
|
||||
options: 'options',
|
||||
select_wallet: 'Select Wallet',
|
||||
options: 'opções',
|
||||
select_wallet: 'Escolher carteira',
|
||||
list: {
|
||||
tabBarLabel: 'Wallets',
|
||||
tabBarLabel: 'Carteiras',
|
||||
app_name: 'Blue Wallet',
|
||||
title: 'Wallets',
|
||||
header: 'Uma wallet representa um par entre um segredo (chave privada) e um endereço' + 'que pode partilhar para receber Bitcoin.',
|
||||
title: 'carteiras',
|
||||
header: 'Uma carteira representa um par composto de uma chave privada e um endereço que você pode .',
|
||||
add: 'adicionar wallet',
|
||||
create_a_wallet: 'Criar uma wallet',
|
||||
create_a_wallet1: 'Gratuito e pode criar',
|
||||
create_a_wallet2: ' quantas quiser',
|
||||
create_a_wallet: 'Criar uma carteira',
|
||||
create_a_wallet1: 'é grátis e você pode criar',
|
||||
create_a_wallet2: 'quantas você quiser',
|
||||
latest_transaction: 'última transação',
|
||||
empty_txs1: 'Suas transações aparecerão aqui',
|
||||
empty_txs2: 'nenhuma de momento',
|
||||
tap_here_to_buy: 'Tap here to buy Bitcoin',
|
||||
empty_txs1: 'Suas transações aparecerão aqui,',
|
||||
empty_txs2: 'nenhuma no momento',
|
||||
tap_here_to_buy: 'Toque aqui para comprar Bitcoin',
|
||||
},
|
||||
reorder: {
|
||||
title: 'Reorder Wallets',
|
||||
title: 'Reordenar carteiras',
|
||||
},
|
||||
add: {
|
||||
title: 'Adicionar Wallet',
|
||||
title: 'criando carteira',
|
||||
description:
|
||||
'Pode fazer um scaneamento de um backup de uma wallet em papel (em WIF - Wallet Import Format), ou criar uma nova wallet. Segwit suportado por defeito.',
|
||||
scan: 'Scanear',
|
||||
'Você pode ler o backup de uma carteira (em WIF - Wallet Import Format) ou criar uma nova. O padrão é criar uma carteira SegWit.',
|
||||
scan: 'Ler backup',
|
||||
create: 'Criar',
|
||||
label_new_segwit: 'Novo SegWit',
|
||||
label_new_lightning: 'Novo Lightning',
|
||||
wallet_name: 'Nome',
|
||||
wallet_type: 'Tipo',
|
||||
label_new_segwit: 'Nova carteira SegWit',
|
||||
label_new_lightning: 'Nova carteira Lightning',
|
||||
wallet_name: 'nome',
|
||||
wallet_type: 'tipo',
|
||||
or: 'ou',
|
||||
import_wallet: 'Importar wallet',
|
||||
import_wallet: 'Importar carteira',
|
||||
imported: 'Importado',
|
||||
coming_soon: 'Brevemente',
|
||||
coming_soon: 'Em breve',
|
||||
lightning: 'Lightning',
|
||||
bitcoin: 'Bitcoin',
|
||||
},
|
||||
details: {
|
||||
title: 'wallet',
|
||||
title: 'Carteira',
|
||||
address: 'Endereço',
|
||||
type: 'Tipo',
|
||||
destination: 'destination',
|
||||
description: 'description',
|
||||
destination: 'destino',
|
||||
description: 'descrição',
|
||||
label: 'Nome',
|
||||
are_you_sure: 'Tem a certeza?',
|
||||
yes_delete: 'Sim, eliminar',
|
||||
are_you_sure: 'Tem certeza?',
|
||||
yes_delete: 'Sim, apagar',
|
||||
no_cancel: 'Não, cancelar',
|
||||
delete_this_wallet: 'Apagar esta wallet',
|
||||
delete_this_wallet: 'Apagar esta carteira',
|
||||
export_backup: 'Exportar / backup',
|
||||
buy_bitcoin: 'Buy Bitcoin',
|
||||
show_xpub: 'Show wallet XPUB',
|
||||
delete: 'Delete',
|
||||
save: 'Save',
|
||||
buy_bitcoin: 'Comprar Bitcoin',
|
||||
show_xpub: 'Ver XPUB',
|
||||
delete: 'Apagar',
|
||||
save: 'Salvar',
|
||||
},
|
||||
export: {
|
||||
title: 'Exportar Wallet',
|
||||
title: 'Exportar carteira',
|
||||
},
|
||||
xpub: {
|
||||
title: 'wallet XPUB',
|
||||
copiedToClipboard: 'copiado para clip board',
|
||||
title: 'XPUB',
|
||||
copiedToClipboard: 'Copiado para a área de transferência',
|
||||
},
|
||||
import: {
|
||||
title: 'importar',
|
||||
explanation:
|
||||
'Escreva aqui sua frase mnemônica, chave privada, WIF, etc. Vamos fazer nosso melhor para importat a sua wallet em qualquer formato',
|
||||
'Escreva aqui sua frase mnemônica, chave privada, WIF, ou o que você tiver. Faremos nosso melhor para adivinhar o formato e importat sua carteira',
|
||||
imported: 'Importada',
|
||||
error: 'Falhou. é um formato válido?',
|
||||
error: 'Erro. Por favor, confira se o formato que você passou é válido.',
|
||||
success: 'Sucesso',
|
||||
do_import: 'Importar',
|
||||
scan_qr: 'ou scan um QR code?',
|
||||
scan_qr: 'ou ler um código QR?',
|
||||
},
|
||||
scanQrWif: {
|
||||
go_back: 'Voltar',
|
||||
cancel: 'Cancelar',
|
||||
decoding: 'Descodificar',
|
||||
input_password: 'Inserir password',
|
||||
password_explain: 'Isto é um BIP38 chave privada encriptada',
|
||||
bad_password: 'Password errada',
|
||||
wallet_already_exists: 'Esta wallet já existe',
|
||||
decoding: 'Decodificar',
|
||||
input_password: 'Inserir senha',
|
||||
password_explain: 'Isto é um chave privada criptografada BIP38',
|
||||
bad_password: 'Senha errada',
|
||||
wallet_already_exists: 'Esta carteira já existe',
|
||||
bad_wif: 'WIF errado',
|
||||
imported_wif: 'WIF transferido ',
|
||||
imported_wif: 'WIF importado ',
|
||||
with_address: ' com endereço ',
|
||||
imported_segwit: 'SegWit transferido',
|
||||
imported_legacy: 'Legacy transferido',
|
||||
imported_watchonly: 'Watch-only importada',
|
||||
imported_segwit: 'Carteira SegWit importada',
|
||||
imported_legacy: 'Carteira antiga importada',
|
||||
imported_watchonly: 'Carteira somente-leitura importada',
|
||||
},
|
||||
},
|
||||
transactions: {
|
||||
list: {
|
||||
tabBarLabel: 'Transações',
|
||||
title: 'Transações',
|
||||
description: 'Uma lista de transações feitas ou recebidas nas suas wallets',
|
||||
description: 'Uma lista de transações feitas ou recebidas nas suas carteiras',
|
||||
conf: 'conf',
|
||||
},
|
||||
details: {
|
||||
title: 'transação',
|
||||
title: 'Transação',
|
||||
from: 'De',
|
||||
to: 'Para',
|
||||
copy: 'Copiar',
|
||||
transaction_details: 'Transaction details',
|
||||
show_in_block_explorer: 'Show in block explorer',
|
||||
transaction_details: 'Detalhes',
|
||||
show_in_block_explorer: 'Mostrar num navegador',
|
||||
},
|
||||
},
|
||||
send: {
|
||||
header: 'Enviar',
|
||||
confirm: {
|
||||
header: 'Confirm',
|
||||
sendNow: 'Send now',
|
||||
header: 'Confirmar',
|
||||
sendNow: 'Enviar agora',
|
||||
},
|
||||
success: {
|
||||
done: 'Done',
|
||||
done: 'Enviado',
|
||||
},
|
||||
details: {
|
||||
title: 'Criar Transacção',
|
||||
|
@ -134,53 +134,53 @@ module.exports = {
|
|||
cancel: 'Cancelar',
|
||||
scan: 'Scanear',
|
||||
create: 'Criar',
|
||||
address: 'Address',
|
||||
total_exceeds_balance: 'The total amount exceeds balance',
|
||||
address: 'Endereço',
|
||||
total_exceeds_balance: 'Valor total excede o saldo disponível',
|
||||
send: 'Send',
|
||||
remaining_balance: 'Saldo restante',
|
||||
},
|
||||
create: {
|
||||
title: 'Criar Transacção',
|
||||
details: 'Details',
|
||||
error: 'Erro ao criar transação. Endereço inválido ou quantia?',
|
||||
details: 'Detalhes',
|
||||
error: 'Erro ao criar transação. Endereço ou valor inválidos?',
|
||||
go_back: 'Voltar',
|
||||
this_is_hex: 'Este é o hex da transação, assinado e pronto para ser difundido para a network. Continuar?',
|
||||
this_is_hex: 'Este é o hex da transação, assinado e pronto para ser divulgado para o mundo. Continuar?',
|
||||
to: 'Para',
|
||||
amount: 'Quantia',
|
||||
amount: 'Valor',
|
||||
fee: 'Taxa',
|
||||
tx_size: 'Tamanho TX',
|
||||
satoshi_per_byte: 'satoshiPerByte',
|
||||
memo: 'Nota pessoal',
|
||||
broadcast: 'Difundir',
|
||||
not_enough_fee: 'Taxa demasiado baixa. Aumente a taxa',
|
||||
tx_size: 'Tamanho',
|
||||
satoshi_per_byte: 'satoshis por byte',
|
||||
memo: 'Nota',
|
||||
broadcast: 'Divulgar',
|
||||
not_enough_fee: 'Taxa muito baixa. Aumente a taxa',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: 'receber',
|
||||
header: 'Receber',
|
||||
details: {
|
||||
title: 'Partilhar este endereço com o pagador',
|
||||
share: 'partilhar',
|
||||
copiedToClipboard: 'copiado para clip board',
|
||||
label: 'Description',
|
||||
setAmount: 'Receive with amount',
|
||||
title: 'Envie este endereço para o pagador',
|
||||
share: 'Compartilhar',
|
||||
copiedToClipboard: 'Copiado para a área de trabalho',
|
||||
label: 'Descrição',
|
||||
setAmount: 'Valor a receber',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: 'Buy Bitcoin',
|
||||
tap_your_address: 'Tap your address to copy it to clipboard:',
|
||||
copied: 'Copied to Clipboard!',
|
||||
header: 'Comprar Bitcoin',
|
||||
tap_your_address: 'Toque seu endereço para copiá-lo para a área de transferência:',
|
||||
copied: 'Copiado!',
|
||||
},
|
||||
settings: {
|
||||
tabBarLabel: 'Definições',
|
||||
tabBarLabel: 'preferências',
|
||||
header: 'definições',
|
||||
plausible_deniability: 'Negação plausível...',
|
||||
storage_not_encrypted: 'Armazenamento: não encriptado',
|
||||
storage_encrypted: 'Armazenamento: encriptado',
|
||||
password: 'Password',
|
||||
password_explain: 'Definir a password para desencriptar o armazenamento',
|
||||
retype_password: 'Inserir password novamente',
|
||||
passwords_do_not_match: 'Passwords não coincidem',
|
||||
encrypt_storage: 'Encriptar',
|
||||
storage_not_encrypted: 'Arquivos: não criptografados',
|
||||
storage_encrypted: 'Arquivos: criptografados',
|
||||
password: 'Senha',
|
||||
password_explain: 'Definir a senha para descriptografar os arquivos',
|
||||
retype_password: 'Inserir senha novamente',
|
||||
passwords_do_not_match: 'Senhas não coincidem',
|
||||
encrypt_storage: 'Criptografar',
|
||||
about: 'Sobre',
|
||||
language: 'Idioma',
|
||||
currency: 'Moeda',
|
||||
|
@ -188,28 +188,30 @@ module.exports = {
|
|||
plausibledeniability: {
|
||||
title: 'Negação plausível',
|
||||
help:
|
||||
'Em algumas circunstâncias, pode ser forçado a relevar uma ' +
|
||||
'password. Para manter as suas moedas seguras, A BlueWallet pode criar outro ' +
|
||||
'armazenamento encriptado, com uma password diferente. Sobre pressão, ' +
|
||||
'pode revelar esta password a um terceiro. Se inserida na ' +
|
||||
'BlueWallet, esta vai abrir um armazenamento "falso". Que vai parecer ' +
|
||||
'legítimo a um terceiro, mas que secretamente vai manter o seu armazenamento principal ' +
|
||||
'com as moedas em segurança.',
|
||||
help2: 'Este novo armazenamento é completamente funcional, e pode guardar ' + 'um valor minímo para parecer mais real.',
|
||||
create_fake_storage: 'Criar armazenamento encriptado FALSO',
|
||||
'Em algumas circunstâncias, você pode ser forçado a revelar uma ' +
|
||||
'senha. Para manter seus bitcoins seguros, A BlueWallet pode criar ' +
|
||||
'uma senha alternativa. Sob pressão, você pode revelar essa senha ao ' +
|
||||
'invés da senha principal. Quando inserida na BlueWallet, esta abrirá ' +
|
||||
'uma interface falsa, que parecerá legítima a um terceiro, enquanto ' +
|
||||
'suas carteiras originais continuarão à salvo em segredo.',
|
||||
help2:
|
||||
'Essa nova interface é completamente funcional e você pode inclusive ' + 'manter nele um valor minímo para que pareça mais real.',
|
||||
create_fake_storage: 'Criar armazenamento criptografada falsa',
|
||||
go_back: 'Voltar',
|
||||
create_password: 'Criar password',
|
||||
create_password_explanation: 'Password para armazenamento FALSO não deve coincidir com o principal',
|
||||
password_should_not_match: 'Password para armazenamento FALSO não deve coincidir com o principal',
|
||||
retype_password: 'Inserir password novamente',
|
||||
passwords_do_not_match: 'Passwords não coincidem, tente novamente',
|
||||
create_password: 'Criar senha',
|
||||
create_password_explanation: 'A senha para a interface falsa não deve coincidir com a principal',
|
||||
password_should_not_match: 'A senha para a interface falsa não deve coincidir com a principal',
|
||||
retype_password: 'Inserir senha novamente',
|
||||
passwords_do_not_match: 'Senhas não coincidem, tente novamente',
|
||||
success: 'Sucesso',
|
||||
},
|
||||
lnd: {
|
||||
title: 'gerenciar fundos',
|
||||
choose_source_wallet: 'Escolha a sua wallet',
|
||||
refill_lnd_balance: 'Carregar o saldo da Lightning wallet',
|
||||
refill: 'Carregar',
|
||||
withdraw: 'Transferir',
|
||||
title: 'manejar fundos',
|
||||
choose_source_wallet: 'Escolha a carteira de origem',
|
||||
refill_lnd_balance: 'Recarregar a carteira Lightning',
|
||||
refill: 'Recarregar',
|
||||
withdraw: 'Sacar',
|
||||
expired: 'Vencido',
|
||||
sameWalletAsInvoiceError: 'Você não pode pagar uma fatura com a mesma carteira que a criou.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -210,5 +210,7 @@ module.exports = {
|
|||
refill_lnd_balance: 'Carregar o saldo da Lightning wallet',
|
||||
refill: 'Carregar',
|
||||
withdraw: 'Transferir',
|
||||
expired: 'Expired',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -211,5 +211,7 @@ module.exports = {
|
|||
refill_lnd_balance: 'Пополнить баланс Lightning кошелька',
|
||||
refill: 'Пополнить',
|
||||
withdraw: 'Вывести',
|
||||
expired: 'Expired',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
||||
|
|
213
loc/th_TH.js
Normal file
213
loc/th_TH.js
Normal file
|
@ -0,0 +1,213 @@
|
|||
module.exports = {
|
||||
_: {
|
||||
storage_is_encrypted: 'ที่เก็บข้อมูลของคุณถูกเข้ารหัส. ต้องการรหัสผ่านเพื่อถอดรหัส',
|
||||
enter_password: 'กรุณาใส่รหัสผ่าน',
|
||||
bad_password: 'รหัสผ่านไม่ถูกต้อง กรุณาใส่รหัสผ่านอีกครั้ง',
|
||||
months_ago: 'เดือนที่แล้ว',
|
||||
days_ago: 'วันที่แล้ว',
|
||||
hours_ago: 'ชั่วโมงที่แล้ว',
|
||||
minutes_ago: 'นาทีที่แล้ว',
|
||||
never: 'ไม่เคย',
|
||||
},
|
||||
wallets: {
|
||||
select_wallet: 'เลือกกระเป๋าสตางค์',
|
||||
options: 'ทางเลือก',
|
||||
list: {
|
||||
app_name: 'บูลวอลเล็ต',
|
||||
title: 'กระเป๋าสตางค์',
|
||||
header: 'กระเป๋าสตางค์คือที่เก็บไพร์เวทคีย์และแอดเดรส' + 'ที่คุณสามารถแชร์เพื่อโอนรับเหรียญ.',
|
||||
add: 'เพิ่มกระเป๋าสตางค์',
|
||||
create_a_wallet: 'สร้างกระเป๋าสตางค์',
|
||||
create_a_wallet1: 'ไม่มีค่าใช้จ่าย และคุณสามารถสร้างกระเป๋าสตางค์',
|
||||
create_a_wallet2: 'ได้มากเท่าที่ต้องการ',
|
||||
latest_transaction: 'ธุรกรรมล่าสุด',
|
||||
empty_txs1: 'ธุรกรรมจะปรากฏที่นี่,',
|
||||
empty_txs2: 'ไม่มี ณ ขณะนี้',
|
||||
tap_here_to_buy: 'กดที่นี่เพื่อซื้อบิตคอยน์',
|
||||
},
|
||||
reorder: {
|
||||
title: 'เปลี่ยนลำดับกระเป๋าสตางค์',
|
||||
},
|
||||
add: {
|
||||
title: 'เพิ่มกระเป๋าสตางค์',
|
||||
description:
|
||||
'คุณสามรถสแกนกระเป๋าสตางค์กระดาษ(ในรูปแบบ WIF - Wallet Import Format), หรือสร้างกระเป๋าสตางค์ใหม่. กระเป๋าสตางค์ใหม่จะใช้ Segwit โดยอัตโนมัติ.',
|
||||
scan: 'สแกน',
|
||||
create: 'สร้าง',
|
||||
label_new_segwit: 'SegWit ใหม่',
|
||||
label_new_lightning: 'ไลท์นิงใหม่',
|
||||
wallet_name: 'ชื่อกระเป๋าสตางค์',
|
||||
wallet_type: 'ชนิด',
|
||||
or: 'หรือ',
|
||||
import_wallet: 'นำเข้ากระเป๋าสตางค์',
|
||||
imported: 'นำเข้าแล้ว',
|
||||
coming_soon: 'เร็วๆนี้',
|
||||
lightning: 'ไลท์นิง',
|
||||
bitcoin: 'บิตคอยน์',
|
||||
},
|
||||
details: {
|
||||
title: 'กระเป๋าสตางค์',
|
||||
address: 'แอดเดรส',
|
||||
type: 'ชนิด',
|
||||
label: 'ป้าย',
|
||||
destination: 'เป้าหมาย',
|
||||
description: 'คำอธิบาย',
|
||||
are_you_sure: 'คุณแน่ใจหรือไม่?',
|
||||
yes_delete: 'ใช่, ลบเลย',
|
||||
no_cancel: 'ไม่ใช่, ยกเลิก',
|
||||
delete: 'ลบ',
|
||||
save: 'เก็บ',
|
||||
delete_this_wallet: 'ลบกระเป๋าสตางค์อันนี้',
|
||||
export_backup: 'ส่งออก / สำรอง',
|
||||
buy_bitcoin: 'ซื้อบิตคอยน์',
|
||||
show_xpub: 'แสดง XPUB ของกระเป๋าสตางค์',
|
||||
},
|
||||
export: {
|
||||
title: 'ส่งออกกระเป๋าสตางค์',
|
||||
},
|
||||
xpub: {
|
||||
title: 'XPUB ของกระเป๋าสตางค์',
|
||||
copiedToClipboard: 'ก๊อปปี้ไปที่คลิปบอร์ดแล้ว.',
|
||||
},
|
||||
import: {
|
||||
title: 'นำเข้า',
|
||||
explanation: 'บันทึกนีโมนิค(สิ่งที่ช่วยให้จำได้), ไพร์เวทคีย์, WIF, และทุกๆอย่าง. บูลวอลเล็ทจะพยายามนำเข้ากระเป๋าสตางค์ของคุณ',
|
||||
imported: 'นำเข้าแล้ว',
|
||||
error: 'ไม่สามารถนำเข้าได้. กรุณาตรวจสอบข้อมูลให้ถูกต้อง.',
|
||||
success: 'สำเร็จ',
|
||||
do_import: 'นำเข้า',
|
||||
scan_qr: 'หรือสแกนรหัสคิวอาร์แทน?',
|
||||
},
|
||||
scanQrWif: {
|
||||
go_back: 'กลับ',
|
||||
cancel: 'ยกเลิก',
|
||||
decoding: 'กำลังถอดรหัส',
|
||||
input_password: 'ใส่รหัสผ่าน',
|
||||
password_explain: 'นี่คือไพร์เวทคีย์ที่เข้ารหัสแบบ BIP38',
|
||||
bad_password: 'รหัสไม่ถูกต้อง',
|
||||
wallet_already_exists: 'กระเป๋าสตางค์นี้มีอยู่แล้ว',
|
||||
bad_wif: 'WIF ไม่ถูกต้อง',
|
||||
imported_wif: 'WIF ที่นำเข้า',
|
||||
with_address: ' ด้วยแอดเดรส ',
|
||||
imported_segwit: 'SegWit ที่นำเข้า',
|
||||
imported_legacy: 'Legacy ที่นำเข้า',
|
||||
imported_watchonly: 'Watch-only ที่นำเข้า',
|
||||
},
|
||||
},
|
||||
transactions: {
|
||||
list: {
|
||||
tabBarLabel: 'ธุรกรรม',
|
||||
title: 'ธุรกรรม',
|
||||
description: 'รายการธุรกรรมเข้าออกของกระเป๋าสตางค์ของคุณ',
|
||||
conf: 'conf',
|
||||
},
|
||||
details: {
|
||||
title: 'ธุรกรรม',
|
||||
from: 'อินพุท',
|
||||
to: 'เอ้าพุท',
|
||||
copy: 'ก๊อปปี้',
|
||||
transaction_details: 'รายละเอียดธุรกรรม',
|
||||
show_in_block_explorer: 'แสดงด้วย block explorer',
|
||||
},
|
||||
},
|
||||
send: {
|
||||
header: 'ส่ง',
|
||||
details: {
|
||||
title: 'สร้างธุรกรรม',
|
||||
amount_field_is_not_valid: 'จำนวนเงินไม่ถูกต้อง',
|
||||
fee_field_is_not_valid: 'ค่าธรรมเนียมไม่ถูกต้อง',
|
||||
address_field_is_not_valid: 'แอดเดรสไม่ถูกต้อง',
|
||||
total_exceeds_balance: 'จำนวนเงินที่จะส่งเกินเงินที่มี.',
|
||||
create_tx_error: 'ไม่สามารถสร้างธุรกรรมได้. กรุณาตรวจสอบแอดเดรสให้ถูกต้อง.',
|
||||
address: 'แอดเดรส',
|
||||
amount_placeholder: 'จำนวนเงินที่ส่ง (หน่วย BTC)',
|
||||
fee_placeholder: 'รวมค่าธรรมเนียม (หน่วย BTC)',
|
||||
note_placeholder: 'หมายเหตุถึงตัวท่านเอง',
|
||||
cancel: 'ยกเลิก',
|
||||
scan: 'สแกน',
|
||||
send: 'ส่ง',
|
||||
create: 'สร้าง',
|
||||
remaining_balance: 'ยอดคงเหลือ',
|
||||
},
|
||||
confirm: {
|
||||
header: 'ยืนยัน',
|
||||
sendNow: 'ส่งเดี๋ยวนี้',
|
||||
},
|
||||
success: {
|
||||
done: 'สำเร็จ',
|
||||
},
|
||||
create: {
|
||||
details: 'รายละเอียด',
|
||||
title: 'สร้างธุรกรรม',
|
||||
error: 'ไม่สามารถสร้างธุรกรรมได้. แอดเดรสไม่ถูกต้อง หรือ จำนวนเงินไม่ถูกต้อง?',
|
||||
go_back: 'กลับ',
|
||||
this_is_hex: 'นี่คือ hex ของธุรกรรม, signed แล้วและพร้อมที่จะบรอดคาซท์ไปยังเน็ตเวิร์ค.',
|
||||
to: 'ถึง',
|
||||
amount: 'จำนวนเงิน',
|
||||
fee: 'ค่าธรรมเนียม',
|
||||
tx_size: 'ขนาดธุรกรรม',
|
||||
satoshi_per_byte: 'ซาโตชิต่อไบท์',
|
||||
memo: 'บันทึกช่วยจำ',
|
||||
broadcast: 'บรอดคาซท์',
|
||||
not_enough_fee: 'ค่าธรรมเนียมไม่เพียงพอ. กรุณาเพิ่มค่าธรรมเนียม',
|
||||
},
|
||||
},
|
||||
receive: {
|
||||
header: 'รับ',
|
||||
details: {
|
||||
title: 'แชร์แอดเดรสนี้กับผู้จ่าย',
|
||||
share: 'แชร์',
|
||||
copiedToClipboard: 'ก๊อปปี้ไปที่คลิปบอร์ดแล้ว.',
|
||||
label: 'คำอธิบาย',
|
||||
setAmount: 'รับด้วยจำนวน',
|
||||
},
|
||||
},
|
||||
buyBitcoin: {
|
||||
header: 'ซื้อบิตคอยน์',
|
||||
tap_your_address: 'กดที่แอดเดรสของคุณเพื่อก๊อปปี้ไปยังคลิปบอร์ด:',
|
||||
copied: 'ก๊อปปี้ไปที่คลิปบอร์ดแล้ว!',
|
||||
},
|
||||
settings: {
|
||||
header: 'ตั้งค่า',
|
||||
plausible_deniability: 'การปฏิเสธที่เป็นไปได้...',
|
||||
storage_not_encrypted: 'ที่เก็บข้อมูล: ยังไม่เข้ารหัส',
|
||||
storage_encrypted: 'ที่เก็บข้อมูล: เข้ารหัสแล้ว',
|
||||
password: 'รหัสผ่าน',
|
||||
password_explain: 'สร้างรหัสผ่านที่จะใช้ในการเข้ารหัสที่เก็บข้อมูล',
|
||||
retype_password: 'ใส่รหัสผ่านอีกครั้ง',
|
||||
passwords_do_not_match: 'รหัสผ่านไม่ตรงกัน',
|
||||
encrypt_storage: 'เข้ารหัสที่เก็บข้อมูล',
|
||||
about: 'เกี่ยวกับ',
|
||||
language: 'ภาษา',
|
||||
currency: 'เงินตรา',
|
||||
},
|
||||
plausibledeniability: {
|
||||
title: 'การปฏิเสธที่เป็นไปได้',
|
||||
help:
|
||||
'ภายใต้บางสถานการ์ณ, คุณอาจจะจำเป็นต้องเปิดเผย' +
|
||||
'รหัสผ่าน. เพื่อเก็บเหรียญให้ปลอดถัย บูลวอลเล็ทสามารถสร้างที่เก็บข้อมูล' +
|
||||
'อีกแห่งหนึ่งโดยใช้รหัสผ่านคนละอัน. ภายใต้สถานการ์ณที่จำเป็น ' +
|
||||
'คุณสามารถเปิดเลยรหัสผ่านนี้กับบุคคลที่สาม. และเมื่อใส่รหัสผ่านนี้ใน ' +
|
||||
'บลูวอลเล็ท ที่เก็บข้อมูลเทียมจะถูกเปิด. และ' +
|
||||
'น่าจะเป็นที่ยอมรับได้ต่อบุคลที่สาม, วิธีนี้จะทำให้ที่เก็บข้อมูลหลักมีความปลอดภัย' +
|
||||
'และเป็นความลับ.',
|
||||
help2: 'ที่เก็บข้อมูลอันใหม่จะทำงานได้สมบูรณ์ และคุณสามารถเก็บจำนวนเงินขั้นต่ำได้ ' + 'โดยที่มีความน่าเชื่อถือ.',
|
||||
create_fake_storage: 'สร้างที่เก็บข้อมูลเทียม',
|
||||
go_back: 'กลับ',
|
||||
create_password: 'สร้างรหัสผ่าน',
|
||||
create_password_explanation: 'รหัสผ่านสำหรับที่เก็บข้อมูลเทียมไม่ควรตรงกับรหัสผ่านที่ใช้กับที่เก็บข้อมูลเทียมจริง',
|
||||
password_should_not_match: 'รหัสผ่านสำหรับที่เก็บข้อมูลเทียมไม่ควรตรงกับรหัสผ่านที่ใช้กับที่เก็บข้อมูลเทียมจริง',
|
||||
retype_password: 'ใส่รหัสผ่านอีกครั้ง ใส่รหัสผ่านอีกครั้ง',
|
||||
passwords_do_not_match: 'รหัสผ่านไม่ตรงกัน ',
|
||||
success: 'Success',
|
||||
},
|
||||
lnd: {
|
||||
title: 'จัดการเงิน',
|
||||
choose_source_wallet: 'เลือกกระเป๋าสตางค์',
|
||||
refill_lnd_balance: 'เติมกระเป๋าสตางค์ไลท์นิง',
|
||||
refill: 'เติม',
|
||||
withdraw: 'ถอน',
|
||||
expired: 'หมดอายุแล้ว',
|
||||
sameWalletAsInvoiceError: 'คุณไม่สามารถจ่ายใบแจ้งหนี้นี้ด้วยกระเป๋าสตางค์อันเดียวกันกับที่ใช้สร้างมัน.',
|
||||
},
|
||||
};
|
|
@ -211,5 +211,7 @@ module.exports = {
|
|||
refill_lnd_balance: 'Збільшити баланс Lightning гаманця',
|
||||
refill: 'Поповнити',
|
||||
withdraw: 'Вивести',
|
||||
expired: 'Expired',
|
||||
sameWalletAsInvoiceError: 'You can not pay an invoice with the same wallet used to create it.',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
export const FiatUnit = Object.freeze({
|
||||
USD: { endPointKey: 'btcusd', storageKey: 'BTC_USD', formatterValue: 'USD', symbol: '$' },
|
||||
EUR: { endPointKey: 'btceur', storageKey: 'BTC_EUR', formatterValue: 'EUR', symbol: '€' },
|
||||
USD: { endPointKey: 'USD', symbol: '$', locale: 'en-US' },
|
||||
AUD: { endPointKey: 'AUD', symbol: '$', locale: 'en-AU' },
|
||||
EUR: { endPointKey: 'EUR', symbol: '€', locale: 'en-EN' },
|
||||
GBP: { endPointKey: 'GBP', symbol: '£', locale: 'en-GB' },
|
||||
RUB: { endPointKey: 'RUB', symbol: '₽', locale: 'ru-RU' },
|
||||
CAD: { endPointKey: 'CAD', symbol: '$', locale: 'en-CA' },
|
||||
CNY: { endPointKey: 'CNY', symbol: '¥', locale: 'zh-CN' },
|
||||
JPY: { endPointKey: 'JPY', symbol: '¥', locale: 'ja-JP' },
|
||||
INR: { endPointKey: 'INR', symbol: '₹', locale: 'hi-HN' },
|
||||
VEF: { endPointKey: 'VEF', symbol: 'Bs.', locale: 'es-VE' },
|
||||
SGD: { endPointKey: 'SGD', symbol: 'S$', locale: 'zh-SG' },
|
||||
ZAR: { endPointKey: 'ZAR', symbol: 'R', locale: 'en-ZA' },
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "BlueWallet",
|
||||
"version": "3.4.0",
|
||||
"version": "3.5.5",
|
||||
"devDependencies": {
|
||||
"babel-eslint": "^8.2.6",
|
||||
"babel-jest": "23.6.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import prompt from 'react-native-prompt-android';
|
||||
|
||||
module.exports = (title, text, isCancelable = true) => {
|
||||
module.exports = (title, text, isCancelable = true, type = 'secure-text') => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const buttons = isCancelable
|
||||
? [
|
||||
|
@ -30,7 +30,7 @@ module.exports = (title, text, isCancelable = true) => {
|
|||
];
|
||||
|
||||
prompt(title, text, buttons, {
|
||||
type: 'secure-text',
|
||||
type: type,
|
||||
cancelable: isCancelable,
|
||||
});
|
||||
});
|
||||
|
|
126
screen/lnd/lndCreateInvoice.js
Normal file
126
screen/lnd/lndCreateInvoice.js
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { ActivityIndicator, View, TextInput, KeyboardAvoidingView, Keyboard, TouchableWithoutFeedback, Text } from 'react-native';
|
||||
import { BlueNavigationStyle, BlueButton, BlueBitcoinAmount } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
let EV = require('../../events');
|
||||
let loc = require('../../loc');
|
||||
|
||||
export default class LNDCreateInvoice extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: loc.receive.header,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
// fallback to first wallet if it exists
|
||||
|
||||
const fromWallet = props.navigation.getParam('fromWallet');
|
||||
this.state = {
|
||||
fromWallet,
|
||||
description: '',
|
||||
isLoading: false,
|
||||
};
|
||||
}
|
||||
|
||||
async createInvoice() {
|
||||
this.setState({ isLoading: true }, async () => {
|
||||
try {
|
||||
const invoiceRequest = await this.state.fromWallet.addInvoice(this.state.amount, this.state.description);
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
|
||||
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
||||
this.props.navigation.navigate('LNDViewInvoice', {
|
||||
invoice: invoiceRequest,
|
||||
fromWallet: this.state.fromWallet,
|
||||
});
|
||||
} catch (_error) {
|
||||
ReactNativeHapticFeedback.trigger('notificationError', false);
|
||||
this.setState({ isLoading: false });
|
||||
alert('Error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
renderCreateButton = () => {
|
||||
return (
|
||||
<View style={{ paddingHorizontal: 56, paddingVertical: 16, alignContent: 'center', backgroundColor: '#FFFFFF' }}>
|
||||
{this.state.isLoading ? (
|
||||
<ActivityIndicator />
|
||||
) : (
|
||||
<BlueButton
|
||||
disabled={!(this.state.description.length > 0 && this.state.amount > 0)}
|
||||
onPress={() => this.createInvoice()}
|
||||
title={loc.send.details.create}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
if (!this.state.fromWallet) {
|
||||
return (
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<Text>System error: Source wallet not found (this should never happen)</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<View style={{ flex: 1, justifyContent: 'space-between' }}>
|
||||
<View style={{ flex: 1, backgroundColor: '#FFFFFF' }}>
|
||||
<KeyboardAvoidingView behavior="position">
|
||||
<BlueBitcoinAmount
|
||||
isLoading={this.state.isLoading}
|
||||
amount={this.state.amount}
|
||||
onChangeText={text => {
|
||||
this.setState({ amount: text });
|
||||
}}
|
||||
disabled={this.state.isLoading}
|
||||
unit={BitcoinUnit.SATS}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
borderColor: '#d2d2d2',
|
||||
borderBottomColor: '#d2d2d2',
|
||||
borderWidth: 1.0,
|
||||
borderBottomWidth: 0.5,
|
||||
backgroundColor: '#f5f5f5',
|
||||
minHeight: 44,
|
||||
height: 44,
|
||||
marginHorizontal: 20,
|
||||
alignItems: 'center',
|
||||
marginVertical: 8,
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<TextInput
|
||||
onChangeText={text => this.setState({ description: text })}
|
||||
placeholder={loc.receive.details.label}
|
||||
value={this.state.description}
|
||||
numberOfLines={1}
|
||||
style={{ flex: 1, marginHorizontal: 8, minHeight: 33 }}
|
||||
editable={!this.state.isLoading}
|
||||
/>
|
||||
</View>
|
||||
{this.renderCreateButton()}
|
||||
</KeyboardAvoidingView>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LNDCreateInvoice.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
navigate: PropTypes.func,
|
||||
getParam: PropTypes.func,
|
||||
}),
|
||||
};
|
101
screen/lnd/lndViewAdditionalInvoiceInformation.js
Normal file
101
screen/lnd/lndViewAdditionalInvoiceInformation.js
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { Animated, StyleSheet, View, TouchableOpacity, Clipboard, Share } from 'react-native';
|
||||
import { BlueLoading, SafeBlueArea, BlueButton, BlueNavigationStyle, BlueText, BlueSpacing20 } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { QRCode } from 'react-native-custom-qr-codes';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
const loc = require('../../loc');
|
||||
|
||||
export default class LNDViewAdditionalInvoiceInformation extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true, () => navigation.dismiss()),
|
||||
title: 'Additional Information',
|
||||
});
|
||||
|
||||
state = { walletInfo: undefined };
|
||||
|
||||
copyToClipboard = () => {
|
||||
this.setState({ addressText: loc.receive.details.copiedToClipboard }, () => {
|
||||
Clipboard.setString(this.state.walletInfo.uris[0]);
|
||||
setTimeout(() => this.setState({ addressText: this.state.walletInfo.uris[0] }), 1000);
|
||||
});
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
const fromWallet = this.props.navigation.getParam('fromWallet');
|
||||
try {
|
||||
await fromWallet.fetchInfo();
|
||||
} catch (_) {
|
||||
alert('Network error');
|
||||
return;
|
||||
}
|
||||
this.setState({ walletInfo: fromWallet.info_raw, addressText: fromWallet.info_raw.uris[0] });
|
||||
}
|
||||
|
||||
render() {
|
||||
if (typeof this.state.walletInfo === 'undefined') {
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<BlueLoading />
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: 16 }}>
|
||||
<QRCode
|
||||
content={this.state.walletInfo.uris[0]}
|
||||
size={300}
|
||||
color={BlueApp.settings.foregroundColor}
|
||||
backgroundColor={BlueApp.settings.brandingColor}
|
||||
logo={require('../../img/qr-code.png')}
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
<BlueText>Open direct channel with this node:</BlueText>
|
||||
<TouchableOpacity onPress={this.copyToClipboard}>
|
||||
<Animated.Text style={styles.address} numberOfLines={0}>
|
||||
{this.state.addressText}
|
||||
</Animated.Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={{ marginBottom: 24 }}>
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'share-alternative',
|
||||
type: 'entypo',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={async () => {
|
||||
Share.share({
|
||||
message: this.state.walletInfo.uris[0],
|
||||
});
|
||||
}}
|
||||
title={loc.receive.details.share}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
address: {
|
||||
marginVertical: 32,
|
||||
fontSize: 15,
|
||||
color: '#9aa0aa',
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
LNDViewAdditionalInvoiceInformation.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
}),
|
||||
};
|
245
screen/lnd/lndViewInvoice.js
Normal file
245
screen/lnd/lndViewInvoice.js
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { Animated, StyleSheet, View, TouchableOpacity, Clipboard, Dimensions, Share } from 'react-native';
|
||||
import { BlueLoading, BlueText, SafeBlueArea, BlueButton, BlueNavigationStyle, BlueSpacing20 } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
import { Icon } from 'react-native-elements';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
const loc = require('../../loc');
|
||||
const EV = require('../../events');
|
||||
const QRFast = require('react-native-qrcode');
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
export default class LNDViewInvoice extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true, () => navigation.dismiss()),
|
||||
title: 'Lightning Invoice',
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const invoice = props.navigation.getParam('invoice');
|
||||
const fromWallet = props.navigation.getParam('fromWallet');
|
||||
this.state = {
|
||||
invoice,
|
||||
fromWallet,
|
||||
isLoading: typeof invoice === 'string',
|
||||
addressText: typeof invoice === 'object' && invoice.hasOwnProperty('payment_request') ? invoice.payment_request : invoice,
|
||||
isFetchingInvoices: true,
|
||||
qrCodeHeight: height > width ? height / 2.5 : width / 2,
|
||||
};
|
||||
this.fetchInvoiceInterval = undefined;
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
this.fetchInvoiceInterval = setInterval(async () => {
|
||||
if (this.state.isFetchingInvoices) {
|
||||
try {
|
||||
const userInvoices = JSON.stringify(await this.state.fromWallet.getUserInvoices());
|
||||
const updatedUserInvoice = JSON.parse(userInvoices).filter(invoice =>
|
||||
typeof this.state.invoice === 'object'
|
||||
? invoice.payment_request === this.state.invoice.payment_request
|
||||
: invoice.payment_request === this.state.invoice,
|
||||
)[0];
|
||||
|
||||
if (typeof updatedUserInvoice !== 'undefined') {
|
||||
this.setState({ invoice: updatedUserInvoice, isLoading: false, addressText: updatedUserInvoice.payment_request });
|
||||
if (updatedUserInvoice.ispaid) {
|
||||
// we fetched the invoice, and it is paid :-)
|
||||
this.setState({ isFetchingInvoices: false });
|
||||
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
||||
clearInterval(this.fetchInvoiceInterval);
|
||||
this.fetchInvoiceInterval = undefined;
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
|
||||
} else {
|
||||
const currentDate = new Date();
|
||||
const now = (currentDate.getTime() / 1000) | 0;
|
||||
const invoiceExpiration = updatedUserInvoice.timestamp + updatedUserInvoice.expire_time;
|
||||
if (invoiceExpiration < now && !updatedUserInvoice.ispaid) {
|
||||
// invoice expired :-(
|
||||
this.setState({ isFetchingInvoices: false });
|
||||
ReactNativeHapticFeedback.trigger('notificationError', false);
|
||||
clearInterval(this.fetchInvoiceInterval);
|
||||
this.fetchInvoiceInterval = undefined;
|
||||
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
clearInterval(this.fetchInvoiceInterval);
|
||||
this.fetchInvoiceInterval = undefined;
|
||||
console.log(error);
|
||||
alert(error);
|
||||
this.props.navigation.dismiss();
|
||||
}
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.fetchInvoiceInterval);
|
||||
this.fetchInvoiceInterval = undefined;
|
||||
}
|
||||
|
||||
copyToClipboard = () => {
|
||||
this.setState({ addressText: loc.receive.details.copiedToClipboard }, () => {
|
||||
Clipboard.setString(this.state.invoice.payment_request);
|
||||
setTimeout(() => this.setState({ addressText: this.state.invoice.payment_request }), 1000);
|
||||
});
|
||||
};
|
||||
|
||||
onLayout = () => {
|
||||
const { height } = Dimensions.get('window');
|
||||
this.setState({ qrCodeHeight: height > width ? height / 2.5 : width / 2 });
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
const { invoice } = this.state;
|
||||
if (typeof invoice === 'object') {
|
||||
const currentDate = new Date();
|
||||
const now = (currentDate.getTime() / 1000) | 0;
|
||||
const invoiceExpiration = invoice.timestamp + invoice.expire_time;
|
||||
|
||||
if (invoice.ispaid || invoice.type === 'paid_invoice') {
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 60,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 43,
|
||||
marginBottom: 53,
|
||||
}}
|
||||
>
|
||||
<Icon name="check" size={50} type="font-awesome" color="#0f5cc0" />
|
||||
</View>
|
||||
<BlueText>This invoice has been paid for</BlueText>
|
||||
</View>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
if (invoiceExpiration < now && !invoice.ispaid) {
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: '#ccddf9',
|
||||
width: 120,
|
||||
height: 120,
|
||||
borderRadius: 60,
|
||||
alignSelf: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 43,
|
||||
marginBottom: 53,
|
||||
}}
|
||||
>
|
||||
<Icon name="times" size={50} type="font-awesome" color="#0f5cc0" />
|
||||
</View>
|
||||
<BlueText>This invoice was not paid for and has expired</BlueText>
|
||||
</View>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
} else if (invoiceExpiration > now && invoice.ispaid) {
|
||||
if (invoice.ispaid) {
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
|
||||
<BlueText>'This invoice has been paid for.'</BlueText>
|
||||
</View>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Invoice has not expired, nor has it been paid for.
|
||||
return (
|
||||
<SafeBlueArea>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
marginTop: 8,
|
||||
paddingHorizontal: 16,
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
onLayout={this.onLayout}
|
||||
>
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<QRFast
|
||||
value={typeof this.state.invoice === 'object' ? invoice.payment_request : invoice}
|
||||
fgColor={BlueApp.settings.brandingColor}
|
||||
bgColor={BlueApp.settings.foregroundColor}
|
||||
size={this.state.qrCodeHeight}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<BlueSpacing20 />
|
||||
{invoice && invoice.amt && <BlueText>Please pay {invoice.amt} sats</BlueText>}
|
||||
{invoice && invoice.description && <BlueText>For: {invoice.description}</BlueText>}
|
||||
<TouchableOpacity onPress={this.copyToClipboard}>
|
||||
<Animated.Text style={styles.address} numberOfLines={0}>
|
||||
{this.state.addressText}
|
||||
</Animated.Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'share-alternative',
|
||||
type: 'entypo',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={async () => {
|
||||
Share.share({
|
||||
message: 'lightning:' + invoice.payment_request,
|
||||
});
|
||||
}}
|
||||
title={loc.receive.details.share}
|
||||
/>
|
||||
<BlueButton
|
||||
buttonStyle={{ backgroundColor: 'white' }}
|
||||
icon={{
|
||||
name: 'info',
|
||||
type: 'entypo',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => this.props.navigation.navigate('LNDViewAdditionalInvoiceInformation', { fromWallet: this.state.fromWallet })}
|
||||
title="Additional Information"
|
||||
/>
|
||||
</View>
|
||||
<BlueSpacing20 />
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
address: {
|
||||
marginVertical: 32,
|
||||
fontSize: 15,
|
||||
color: '#9aa0aa',
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
LNDViewInvoice.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
}),
|
||||
};
|
|
@ -1,138 +1,77 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { TouchableOpacity, View } from 'react-native';
|
||||
import { Dropdown } from 'react-native-material-dropdown';
|
||||
import { BlueSpacingVariable, BlueLoading, SafeBlueArea, BlueCard, BlueHeaderDefaultSub } from '../../BlueComponents';
|
||||
import { TouchableOpacity, Linking, View } from 'react-native';
|
||||
import { BlueSpacingVariable, BlueNavigationStyle, SafeBlueArea, BlueCard } from '../../BlueComponents';
|
||||
import { ListItem } from 'react-native-elements';
|
||||
import PropTypes from 'prop-types';
|
||||
import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
let loc = require('../../loc');
|
||||
|
||||
let data = [];
|
||||
|
||||
export default class ManageFunds extends Component {
|
||||
static navigationOptions = {
|
||||
header: ({ navigation }) => {
|
||||
return <BlueHeaderDefaultSub leftText={loc.lnd.title} onClose={() => navigation.goBack(null)} />;
|
||||
},
|
||||
};
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: loc.lnd.title,
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let fromSecret;
|
||||
if (props.navigation.state.params.fromSecret) fromSecret = props.navigation.state.params.fromSecret;
|
||||
let fromWallet = false;
|
||||
this.onWalletSelect = this.onWalletSelect.bind(this);
|
||||
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getSecret() === fromSecret) {
|
||||
fromWallet = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fromWallet) {
|
||||
console.log(fromWallet.type);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
fromWallet,
|
||||
fromSecret,
|
||||
isLoading: true,
|
||||
};
|
||||
this.state = { fromWallet: props.navigation.getParam('fromWallet') };
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
data = [];
|
||||
for (let c = 0; c < BlueApp.getWallets().length; c++) {
|
||||
let w = BlueApp.getWallets()[c];
|
||||
if (w.type !== LightningCustodianWallet.type) {
|
||||
data.push({
|
||||
value: c,
|
||||
label: w.getLabel() + ' (' + w.getBalance() + ' BTC)',
|
||||
});
|
||||
async onWalletSelect(wallet) {
|
||||
this.props.navigation.dismiss();
|
||||
/** @type {LightningCustodianWallet} */
|
||||
let toAddress = false;
|
||||
if (this.state.fromWallet.refill_addressess.length > 0) {
|
||||
toAddress = this.state.fromWallet.refill_addressess[0];
|
||||
} else {
|
||||
try {
|
||||
await this.state.fromWallet.fetchBtcAddress();
|
||||
toAddress = this.state.fromWallet.refill_addressess[0];
|
||||
} catch (Err) {
|
||||
return alert(Err.message);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
if (wallet) {
|
||||
setTimeout(() => {
|
||||
this.props.navigation.navigate('SendDetails', {
|
||||
memo: loc.lnd.refill_lnd_balance,
|
||||
fromSecret: wallet.getSecret(),
|
||||
address: toAddress,
|
||||
});
|
||||
}, 100);
|
||||
} else {
|
||||
return alert('Internal error');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<BlueSpacingVariable />
|
||||
|
||||
<BlueCard>
|
||||
{(() => {
|
||||
if (this.state.isRefill) {
|
||||
return (
|
||||
<View>
|
||||
<Dropdown
|
||||
label={loc.lnd.choose_source_wallet}
|
||||
data={data}
|
||||
onChangeText={async value => {
|
||||
/** @type {LightningCustodianWallet} */
|
||||
let fromWallet = this.state.fromWallet;
|
||||
let toAddress = false;
|
||||
if (fromWallet.refill_addressess.length > 0) {
|
||||
toAddress = fromWallet.refill_addressess[0];
|
||||
} else {
|
||||
try {
|
||||
await fromWallet.fetchBtcAddress();
|
||||
toAddress = fromWallet.refill_addressess[0];
|
||||
} catch (Err) {
|
||||
return alert(Err.message);
|
||||
}
|
||||
}
|
||||
|
||||
let wallet = BlueApp.getWallets()[value];
|
||||
if (wallet) {
|
||||
console.log(wallet.getSecret());
|
||||
setTimeout(() => {
|
||||
console.log({ toAddress });
|
||||
this.props.navigation.navigate('SendDetails', {
|
||||
memo: loc.lnd.refill_lnd_balance,
|
||||
fromSecret: wallet.getSecret(),
|
||||
address: toAddress,
|
||||
});
|
||||
}, 750);
|
||||
} else {
|
||||
return alert('Internal error');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<View>
|
||||
<ListItem
|
||||
titleStyle={{ color: BlueApp.settings.foregroundColor }}
|
||||
component={TouchableOpacity}
|
||||
onPress={a => {
|
||||
this.setState({ isRefill: true });
|
||||
}}
|
||||
title={loc.lnd.refill}
|
||||
/>
|
||||
<ListItem
|
||||
titleStyle={{ color: BlueApp.settings.foregroundColor }}
|
||||
component={TouchableOpacity}
|
||||
onPress={a => {
|
||||
alert('Coming soon');
|
||||
}}
|
||||
title={loc.lnd.withdraw}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
<ListItem
|
||||
titleStyle={{ color: BlueApp.settings.foregroundColor }}
|
||||
component={TouchableOpacity}
|
||||
onPress={a => {
|
||||
this.props.navigation.navigate('SelectWallet', { onWalletSelect: this.onWalletSelect });
|
||||
}}
|
||||
title={loc.lnd.refill}
|
||||
/>
|
||||
<ListItem
|
||||
titleStyle={{ color: BlueApp.settings.foregroundColor }}
|
||||
component={TouchableOpacity}
|
||||
onPress={a => {
|
||||
Linking.openURL('https://zigzag.io');
|
||||
}}
|
||||
title={loc.lnd.withdraw}
|
||||
/>
|
||||
|
||||
<View />
|
||||
</BlueCard>
|
||||
|
@ -144,7 +83,9 @@ export default class ManageFunds extends Component {
|
|||
ManageFunds.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
goBack: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
fromSecret: PropTypes.string,
|
||||
|
|
|
@ -3,50 +3,58 @@ import React from 'react';
|
|||
import { Text, Dimensions, ActivityIndicator, View, TouchableOpacity, TouchableWithoutFeedback, TextInput, Keyboard } from 'react-native';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueHeaderDefaultSub } from '../../BlueComponents';
|
||||
import { BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueNavigationStyle, BlueBitcoinAmount } from '../../BlueComponents';
|
||||
import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
let currency = require('../../currency');
|
||||
let EV = require('../../events');
|
||||
let loc = require('../../loc');
|
||||
const { width } = Dimensions.get('window');
|
||||
|
||||
export default class ScanLndInvoice extends React.Component {
|
||||
static navigationOptions = {
|
||||
header: ({ navigation }) => {
|
||||
return <BlueHeaderDefaultSub leftText={'Pay invoice'} onClose={() => navigation.goBack(null)} />;
|
||||
},
|
||||
};
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: loc.send.header,
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
state = {
|
||||
isLoading: false,
|
||||
isAmountInitiallyEmpty: false,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let fromSecret;
|
||||
if (props.navigation.state.params.fromSecret) fromSecret = props.navigation.state.params.fromSecret;
|
||||
let fromWallet = {};
|
||||
|
||||
if (!fromSecret) {
|
||||
const lightningWallets = BlueApp.getWallets().filter(item => item.type === LightningCustodianWallet.type);
|
||||
if (lightningWallets.length > 0) {
|
||||
fromSecret = lightningWallets[0].getSecret();
|
||||
if (!BlueApp.getWallets().some(item => item.type === LightningCustodianWallet.type)) {
|
||||
alert('Before paying a Lightning invoice, you must first add a Lightning wallet.');
|
||||
props.navigation.dismiss();
|
||||
} else {
|
||||
let fromSecret;
|
||||
if (props.navigation.state.params.fromSecret) fromSecret = props.navigation.state.params.fromSecret;
|
||||
let fromWallet = {};
|
||||
|
||||
if (!fromSecret) {
|
||||
const lightningWallets = BlueApp.getWallets().filter(item => item.type === LightningCustodianWallet.type);
|
||||
if (lightningWallets.length > 0) {
|
||||
fromSecret = lightningWallets[0].getSecret();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getSecret() === fromSecret) {
|
||||
fromWallet = w;
|
||||
break;
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if (w.getSecret() === fromSecret) {
|
||||
fromWallet = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
fromWallet,
|
||||
fromSecret,
|
||||
};
|
||||
this.state = {
|
||||
fromWallet,
|
||||
fromSecret,
|
||||
destination: '',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
|
@ -71,7 +79,7 @@ export default class ScanLndInvoice extends React.Component {
|
|||
}, 6000);
|
||||
|
||||
if (!this.state.fromWallet) {
|
||||
alert('Error: cant find source wallet (this should never happen)');
|
||||
alert('Before paying a Lightning invoice, you must first add a Lightning wallet.');
|
||||
return this.props.navigation.goBack();
|
||||
}
|
||||
|
||||
|
@ -82,7 +90,7 @@ export default class ScanLndInvoice extends React.Component {
|
|||
* @type {LightningCustodianWallet}
|
||||
*/
|
||||
let w = this.state.fromWallet;
|
||||
let decoded = false;
|
||||
let decoded;
|
||||
try {
|
||||
decoded = await w.decodeInvoice(data);
|
||||
|
||||
|
@ -94,10 +102,11 @@ export default class ScanLndInvoice extends React.Component {
|
|||
}
|
||||
Keyboard.dismiss();
|
||||
this.setState({
|
||||
isPaying: true,
|
||||
invoice: data,
|
||||
decoded,
|
||||
expiresIn,
|
||||
destination: data,
|
||||
isAmountInitiallyEmpty: decoded.num_satoshis === '0',
|
||||
});
|
||||
} catch (Err) {
|
||||
alert(Err.message);
|
||||
|
@ -108,62 +117,89 @@ export default class ScanLndInvoice extends React.Component {
|
|||
if (!this.state.hasOwnProperty('decoded')) {
|
||||
return null;
|
||||
}
|
||||
let decoded = this.state.decoded;
|
||||
|
||||
/** @type {LightningCustodianWallet} */
|
||||
let fromWallet = this.state.fromWallet;
|
||||
this.setState(
|
||||
{
|
||||
isLoading: true,
|
||||
},
|
||||
async () => {
|
||||
let decoded = this.state.decoded;
|
||||
|
||||
let expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms
|
||||
if (+new Date() > expiresIn) {
|
||||
return alert('Invoice expired');
|
||||
}
|
||||
/** @type {LightningCustodianWallet} */
|
||||
let fromWallet = this.state.fromWallet;
|
||||
|
||||
this.setState({
|
||||
isPayingInProgress: true,
|
||||
});
|
||||
let expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms
|
||||
if (+new Date() > expiresIn) {
|
||||
this.setState({ isLoading: false });
|
||||
return alert('Invoice expired');
|
||||
}
|
||||
|
||||
let start = +new Date();
|
||||
let end;
|
||||
try {
|
||||
await fromWallet.payInvoice(this.state.invoice);
|
||||
end = +new Date();
|
||||
} catch (Err) {
|
||||
console.log(Err.message);
|
||||
this.props.navigation.goBack();
|
||||
return alert('Error');
|
||||
}
|
||||
const currentUserInvoices = await fromWallet.getUserInvoices();
|
||||
if (currentUserInvoices.some(invoice => invoice.payment_hash === decoded.payment_hash)) {
|
||||
this.setState({ isLoading: false });
|
||||
return alert(loc.lnd.sameWalletAsInvoiceError);
|
||||
}
|
||||
|
||||
console.log('payInvoice took', (end - start) / 1000, 'sec');
|
||||
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs
|
||||
let start = +new Date();
|
||||
let end;
|
||||
try {
|
||||
await fromWallet.payInvoice(this.state.invoice, this.state.invoice.num_satoshis);
|
||||
end = +new Date();
|
||||
} catch (Err) {
|
||||
console.log(Err.message);
|
||||
this.setState({ isLoading: false });
|
||||
this.props.navigation.goBack();
|
||||
return alert('Error');
|
||||
}
|
||||
|
||||
alert('Success');
|
||||
this.props.navigation.goBack();
|
||||
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();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
processTextForInvoice = text => {
|
||||
if (text.toLowerCase().startsWith('lnb') || text.toLowerCase().startsWith('lightning:lnb')) {
|
||||
this.processInvoice(text);
|
||||
} else {
|
||||
this.setState({ decoded: undefined, expiresIn: undefined });
|
||||
this.setState({ decoded: undefined, expiresIn: undefined, destination: text });
|
||||
}
|
||||
};
|
||||
|
||||
shouldDisablePayButton = () => {
|
||||
if (typeof this.state.decoded !== 'object') {
|
||||
return true;
|
||||
} else {
|
||||
if (!this.state.decoded.hasOwnProperty('num_satoshis')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return this.state.decoded.num_satoshis <= 0 || this.state.isLoading || isNaN(this.state.decoded.num_satoshis);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<Text style={{ textAlign: 'center', fontSize: 50, fontWeight: '700', color: '#2f5fb3' }}>
|
||||
{this.state.hasOwnProperty('decoded') &&
|
||||
this.state.decoded !== undefined &&
|
||||
currency.satoshiToLocalCurrency(this.state.decoded.num_satoshis)}
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'center', fontSize: 25, fontWeight: '600', color: '#d4d4d4' }}>
|
||||
{this.state.hasOwnProperty('decoded') &&
|
||||
this.state.decoded !== undefined &&
|
||||
currency.satoshiToBTC(this.state.decoded.num_satoshis)}
|
||||
</Text>
|
||||
<BlueBitcoinAmount
|
||||
pointerEvents={this.state.isAmountInitiallyEmpty ? 'auto' : 'none'}
|
||||
isLoading={this.state.isLoading}
|
||||
amount={typeof this.state.decoded === 'object' ? this.state.decoded.num_satoshis : 0}
|
||||
onChangeText={text => {
|
||||
if (typeof this.state.decoded === 'object') {
|
||||
text = parseInt(text);
|
||||
let decoded = this.state.decoded;
|
||||
decoded.num_satoshis = text;
|
||||
this.setState({ decoded: decoded });
|
||||
}
|
||||
}}
|
||||
disabled={typeof this.state.decoded !== 'object' || this.state.isLoading}
|
||||
unit={BitcoinUnit.SATS}
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueCard>
|
||||
<View
|
||||
style={{
|
||||
|
@ -182,10 +218,13 @@ export default class ScanLndInvoice extends React.Component {
|
|||
}}
|
||||
>
|
||||
<TextInput
|
||||
onChangeText={this.processTextForInvoice}
|
||||
onChangeText={text => {
|
||||
this.setState({ destination: text });
|
||||
this.processTextForInvoice(text);
|
||||
}}
|
||||
placeholder={loc.wallets.details.destination}
|
||||
numberOfLines={1}
|
||||
value={this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined ? this.state.decoded.destination : ''}
|
||||
value={this.state.destination}
|
||||
style={{ flex: 1, marginHorizontal: 8, minHeight: 33, height: 33 }}
|
||||
editable={!this.state.isLoading}
|
||||
/>
|
||||
|
@ -212,61 +251,40 @@ export default class ScanLndInvoice extends React.Component {
|
|||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
borderColor: '#d2d2d2',
|
||||
borderBottomColor: '#d2d2d2',
|
||||
borderWidth: 1.0,
|
||||
borderBottomWidth: 0.5,
|
||||
backgroundColor: '#f5f5f5',
|
||||
minHeight: 44,
|
||||
height: 44,
|
||||
marginHorizontal: 20,
|
||||
alignItems: 'center',
|
||||
marginVertical: 8,
|
||||
borderRadius: 4,
|
||||
}}
|
||||
>
|
||||
<TextInput
|
||||
onChangeText={text => {}}
|
||||
placeholder={loc.wallets.details.description}
|
||||
numberOfLines={1}
|
||||
value={this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined ? this.state.decoded.description : ''}
|
||||
style={{ flex: 1, marginHorizontal: 8, minHeight: 33, height: 33 }}
|
||||
editable={!this.state.isLoading}
|
||||
/>
|
||||
<Text numberOfLines={0} style={{ color: '#81868e', fontWeight: '500', fontSize: 14 }}>
|
||||
{this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined ? this.state.decoded.description : ''}
|
||||
</Text>
|
||||
</View>
|
||||
{this.state.expiresIn !== undefined && (
|
||||
<Text style={{ color: '#81868e', fontSize: 12, left: 20, top: 10 }}>Expires in: {this.state.expiresIn}</Text>
|
||||
)}
|
||||
</BlueCard>
|
||||
|
||||
<BlueSpacing20 />
|
||||
|
||||
{this.state.hasOwnProperty('decoded') &&
|
||||
this.state.decoded !== undefined &&
|
||||
(() => {
|
||||
if (this.state.isPayingInProgress) {
|
||||
return (
|
||||
<View>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'bolt',
|
||||
type: 'font-awesome',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
title={'Pay'}
|
||||
buttonStyle={{ width: 150, left: (width - 150) / 2 - 20 }}
|
||||
onPress={() => {
|
||||
this.pay();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
{this.state.isLoading ? (
|
||||
<View>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
) : (
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'bolt',
|
||||
type: 'font-awesome',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
title={'Pay'}
|
||||
buttonStyle={{ width: 150, left: (width - 150) / 2 - 20 }}
|
||||
onPress={() => {
|
||||
this.pay();
|
||||
}}
|
||||
disabled={this.shouldDisablePayButton()}
|
||||
/>
|
||||
)}
|
||||
</SafeBlueArea>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
|
@ -278,6 +296,7 @@ ScanLndInvoice.propTypes = {
|
|||
goBack: PropTypes.function,
|
||||
navigate: PropTypes.function,
|
||||
getParam: PropTypes.function,
|
||||
dismiss: PropTypes.function,
|
||||
state: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
uri: PropTypes.string,
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { ScrollView } from 'react-native';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import { BlueLoading, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueHeader, BlueSpacing20 } from '../BlueComponents';
|
||||
import { BlueLoading, BlueButton, SafeBlueArea, BlueCard, BlueText, BlueNavigationStyle, BlueSpacing20 } from '../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../BlueApp');
|
||||
|
@ -12,10 +11,8 @@ let loc = require('../loc');
|
|||
|
||||
export default class PlausibleDeniability extends Component {
|
||||
static navigationOptions = {
|
||||
tabBarLabel: loc.plausibledeniability.title,
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons name={focused ? 'ios-settings' : 'ios-settings-outline'} size={26} style={{ color: tintColor }} />
|
||||
),
|
||||
...BlueNavigationStyle(),
|
||||
title: loc.plausibledeniability.title,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
|
@ -38,14 +35,6 @@ export default class PlausibleDeniability extends Component {
|
|||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<BlueHeader
|
||||
backgroundColor={BlueApp.settings.brandingColor}
|
||||
centerComponent={{
|
||||
text: loc.plausibledeniability.title,
|
||||
style: { color: BlueApp.settings.foregroundColor, fontSize: 23 },
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueCard>
|
||||
<ScrollView maxHeight={450}>
|
||||
<BlueText>{loc.plausibledeniability.help}</BlueText>
|
||||
|
@ -85,20 +74,6 @@ export default class PlausibleDeniability extends Component {
|
|||
this.props.navigation.navigate('Wallets');
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'arrow-left',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
title={loc.plausibledeniability.go_back}
|
||||
onPress={() => {
|
||||
this.props.navigation.goBack();
|
||||
}}
|
||||
/>
|
||||
</ScrollView>
|
||||
</BlueCard>
|
||||
</SafeBlueArea>
|
||||
|
|
|
@ -146,9 +146,15 @@ export default class SendDetails extends Component {
|
|||
let memo = '';
|
||||
|
||||
parsedBitcoinUri = bip21.decode(this.props.navigation.state.params.uri);
|
||||
address = parsedBitcoinUri.address || address;
|
||||
amount = parsedBitcoinUri.options.amount.toString() || amount;
|
||||
memo = parsedBitcoinUri.options.label || memo;
|
||||
address = parsedBitcoinUri.hasOwnProperty('address') ? parsedBitcoinUri.address : address;
|
||||
if (parsedBitcoinUri.hasOwnProperty('options')) {
|
||||
if (parsedBitcoinUri.options.hasOwnProperty('amount')) {
|
||||
amount = parsedBitcoinUri.options.amount.toString();
|
||||
}
|
||||
if (parsedBitcoinUri.options.hasOwnProperty('label')) {
|
||||
memo = parsedBitcoinUri.options.label || memo;
|
||||
}
|
||||
}
|
||||
this.setState({ address, amount, memo });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
|
@ -223,7 +229,7 @@ export default class SendDetails extends Component {
|
|||
})
|
||||
.catch(error => {
|
||||
alert(error.errorMessage);
|
||||
this.setState({ address: text.replace(' ', ''), isLoading: false, bip70TransactionExpiration: null, amount: 0 });
|
||||
this.setState({ isLoading: false, bip70TransactionExpiration: null });
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
|
@ -50,64 +50,65 @@ export default class About extends Component {
|
|||
|
||||
<BlueTextCentered h4>Always backup your keys</BlueTextCentered>
|
||||
<BlueSpacing20 />
|
||||
</BlueCard>
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'mark-github',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://github.com/BlueWallet/BlueWallet');
|
||||
}}
|
||||
title="github.com/BlueWallet/BlueWallet"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'mark-github',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://github.com/BlueWallet/BlueWallet');
|
||||
}}
|
||||
title="github.com/BlueWallet/BlueWallet"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'twitter',
|
||||
type: 'font-awesome',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://twitter.com/bluewalletio');
|
||||
}}
|
||||
title="Follow us on Twitter"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'twitter',
|
||||
type: 'font-awesome',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://twitter.com/bluewalletio');
|
||||
}}
|
||||
title="Follow us on Twitter"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'telegram',
|
||||
type: 'font-awesome',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://t.me/bluewallet');
|
||||
}}
|
||||
title="Join Telegram chat"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'telegram',
|
||||
type: 'font-awesome',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://t.me/bluewallet');
|
||||
}}
|
||||
title="Join Telegram chat"
|
||||
/>
|
||||
<BlueSpacing20 />
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'thumbsup',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
if (Platform.OS === 'ios') {
|
||||
Linking.openURL('https://itunes.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040?l=ru&ls=1&mt=8');
|
||||
} else {
|
||||
Linking.openURL('https://play.google.com/store/apps/details?id=io.bluewallet.bluewallet');
|
||||
}
|
||||
}}
|
||||
title="Leave us a review on Appstore"
|
||||
/>
|
||||
|
||||
<BlueSpacing20 />
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'thumbsup',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
if (Platform.OS === 'ios') {
|
||||
Linking.openURL('https://itunes.apple.com/us/app/bluewallet-bitcoin-wallet/id1376878040?l=ru&ls=1&mt=8');
|
||||
} else {
|
||||
Linking.openURL('https://play.google.com/store/apps/details?id=io.bluewallet.bluewallet');
|
||||
}
|
||||
}}
|
||||
title="Leave us a review on Appstore"
|
||||
/>
|
||||
|
||||
<BlueSpacing20 />
|
||||
<BlueCard>
|
||||
<BlueText h3>Built with awesome:</BlueText>
|
||||
<BlueSpacing20 />
|
||||
<BlueText h4>* React Native</BlueText>
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FlatList, TouchableOpacity, AsyncStorage, ActivityIndicator, View } from 'react-native';
|
||||
import { SafeBlueArea, BlueNavigationStyle, BlueListItem } from '../../BlueComponents';
|
||||
import { FlatList, TouchableOpacity, ActivityIndicator, View } from 'react-native';
|
||||
import { SafeBlueArea, BlueNavigationStyle, BlueListItem, BlueText, BlueCard } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { AppStorage } from '../../class';
|
||||
import { FiatUnit } from '../../models/fiatUnit';
|
||||
/** @type {AppStorage} */
|
||||
let loc = require('../../loc');
|
||||
let currency = require('../../currency');
|
||||
|
||||
|
@ -22,11 +20,11 @@ export default class Currency extends Component {
|
|||
|
||||
async componentDidMount() {
|
||||
try {
|
||||
const preferredCurrency = await AsyncStorage.getItem(AppStorage.PREFERREDCURRENCY);
|
||||
const preferredCurrency = await currency.getPreferredCurrency();
|
||||
if (preferredCurrency === null) {
|
||||
throw Error();
|
||||
}
|
||||
this.setState({ selectedCurrency: JSON.parse(preferredCurrency) });
|
||||
this.setState({ selectedCurrency: preferredCurrency });
|
||||
} catch (_error) {
|
||||
this.setState({ selectedCurrency: FiatUnit.USD });
|
||||
}
|
||||
|
@ -37,15 +35,15 @@ export default class Currency extends Component {
|
|||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.setState({ isSavingNewPreferredCurrency: true, selectedCurrency: item }, async () => {
|
||||
await AsyncStorage.setItem(AppStorage.PREFERREDCURRENCY, JSON.stringify(item));
|
||||
await currency.startUpdater(true);
|
||||
await currency.setPrefferedCurrency(item);
|
||||
await currency.startUpdater();
|
||||
this.setState({ isSavingNewPreferredCurrency: false });
|
||||
});
|
||||
}}
|
||||
>
|
||||
<BlueListItem
|
||||
title={item.symbol + ' ' + item.formatterValue}
|
||||
{...(this.state.selectedCurrency.formatterValue === item.formatterValue
|
||||
title={item.symbol + ' ' + item.endPointKey}
|
||||
{...(this.state.selectedCurrency.endPointKey === item.endPointKey
|
||||
? {
|
||||
rightIcon: this.state.selectedNewCurrency ? (
|
||||
<ActivityIndicator />
|
||||
|
@ -70,6 +68,9 @@ export default class Currency extends Component {
|
|||
extraData={this.state.data}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
<BlueCard>
|
||||
<BlueText>Prices are obtained from CoinDesk</BlueText>
|
||||
</BlueCard>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Picker } from 'react-native';
|
||||
import { BlueLoading, SafeBlueArea, BlueCard, BlueNavigationStyle } from '../../BlueComponents';
|
||||
import { FlatList, TouchableOpacity } from 'react-native';
|
||||
import { BlueLoading, BlueText, SafeBlueArea, BlueListItem, BlueCard, BlueNavigationStyle } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
import { Icon } from 'react-native-elements';
|
||||
let loc = require('../../loc');
|
||||
|
||||
export default class Language extends Component {
|
||||
|
@ -17,16 +16,50 @@ export default class Language extends Component {
|
|||
this.state = {
|
||||
isLoading: true,
|
||||
language: loc.getLanguage(),
|
||||
availableLanguages: [
|
||||
{ label: 'English', value: 'en' },
|
||||
{ label: 'Русский', value: 'ru' },
|
||||
{ label: 'Українська', value: 'ua' },
|
||||
{ label: 'Spanish', value: 'es' },
|
||||
{ label: 'Portuguese (BR)', value: 'pt_br' },
|
||||
{ label: 'Portuguese (PT)', value: 'pt_pt' },
|
||||
{ label: 'Deutsch (DE)', value: 'de_de' },
|
||||
{ label: 'Česky (CZ)', value: 'cs_cz' },
|
||||
{ label: 'Thai (TH)', value: 'th_th' },
|
||||
{ label: 'Dutch (NL)', value: 'nl_nl' },
|
||||
{ label: 'Français (FR)', value: 'fr_fr' },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
storageIsEncrypted: await BlueApp.storageIsEncrypted(),
|
||||
});
|
||||
}
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
console.log('setLanguage', item.value);
|
||||
loc.setLanguage(item.value);
|
||||
loc.saveLanguage(item.value);
|
||||
return this.setState({ language: item.value });
|
||||
}}
|
||||
>
|
||||
<BlueListItem
|
||||
title={item.label}
|
||||
{...(this.state.language === item.value
|
||||
? {
|
||||
rightIcon: <Icon name="check" type="font-awesome" color="#0c2550" />,
|
||||
}
|
||||
: { hideChevron: true })}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return <BlueLoading />;
|
||||
|
@ -34,24 +67,15 @@ export default class Language extends Component {
|
|||
|
||||
return (
|
||||
<SafeBlueArea forceInset={{ horizontal: 'always' }} style={{ flex: 1 }}>
|
||||
<FlatList
|
||||
style={{ flex: 1 }}
|
||||
keyExtractor={(_item, index) => `${index}`}
|
||||
data={this.state.availableLanguages}
|
||||
extraData={this.state.availableLanguages}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
<BlueCard>
|
||||
<Picker
|
||||
selectedValue={this.state.language}
|
||||
onValueChange={(itemValue, itemIndex) => {
|
||||
console.log('setLanguage', itemValue);
|
||||
loc.setLanguage(itemValue);
|
||||
loc.saveLanguage(itemValue);
|
||||
return this.setState({ language: itemValue });
|
||||
}}
|
||||
>
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="English" value="en" />
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="Русский" value="ru" />
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="Українська" value="ua" />
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="Spanish" value="es" />
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="Portuguese (BR)" value="pt_br" />
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="Portuguese (PT)" value="pt_pt" />
|
||||
<Picker.Item color={BlueApp.settings.foregroundColor} label="Deutsch (DE)" value="de_DE" />
|
||||
</Picker>
|
||||
<BlueText>When selecting a new language, restarting Blue Wallet may be required for the change to take effect.</BlueText>
|
||||
</BlueCard>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
|
|
|
@ -1,16 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import { AsyncStorage, View, TextInput, Linking } from 'react-native';
|
||||
import { AppStorage } from '../../class';
|
||||
import {
|
||||
BlueLoading,
|
||||
BlueSpacing20,
|
||||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueCard,
|
||||
BlueNavigationStyle,
|
||||
BlueSpacing40,
|
||||
BlueText,
|
||||
} from '../../BlueComponents';
|
||||
import { BlueLoading, BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueNavigationStyle, BlueText } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet';
|
||||
/** @type {AppStorage} */
|
||||
|
@ -65,25 +56,25 @@ export default class LightningSettings extends Component {
|
|||
To connect to your own LND node please install LndHub and put its URL here in settings. Leave blank to use default LndHub
|
||||
(lndhub.io)
|
||||
</BlueText>
|
||||
</BlueCard>
|
||||
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'mark-github',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
backgroundColor: '#FFFFFF',
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://github.com/BlueWallet/LndHub');
|
||||
}}
|
||||
title="github.com/BlueWallet/LndHub"
|
||||
buttonStyle={{
|
||||
backgroundColor: '#FFFFFF',
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueSpacing40 />
|
||||
<BlueButton
|
||||
icon={{
|
||||
name: 'mark-github',
|
||||
type: 'octicon',
|
||||
color: BlueApp.settings.buttonTextColor,
|
||||
backgroundColor: '#FFFFFF',
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL('https://github.com/BlueWallet/LndHub');
|
||||
}}
|
||||
title="github.com/BlueWallet/LndHub"
|
||||
buttonStyle={{
|
||||
backgroundColor: '#FFFFFF',
|
||||
}}
|
||||
/>
|
||||
|
||||
<BlueCard>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
BlueNavigationStyle,
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { SegwitBech32Wallet } from '../../class';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
|
||||
|
@ -39,13 +40,20 @@ export default class RBF extends Component {
|
|||
}
|
||||
|
||||
let destinationAddress;
|
||||
|
||||
for (let o of sourceTx.outputs) {
|
||||
if (o.addresses[0] === sourceWallet.getAddress()) {
|
||||
if (!o.addresses && o.script) {
|
||||
// probably bech32 output, so we need to decode address
|
||||
o.addresses = [SegwitBech32Wallet.scriptPubKeyToAddress(o.script)];
|
||||
}
|
||||
|
||||
if (o.addresses && o.addresses[0] === sourceWallet.getAddress()) {
|
||||
// change
|
||||
// nop
|
||||
} else {
|
||||
// DESTINATION address
|
||||
destinationAddress = o.addresses[0];
|
||||
|
||||
destinationAddress = (o.addresses && o.addresses[0]) || '';
|
||||
console.log('dest = ', destinationAddress);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import PropTypes from 'prop-types';
|
|||
let BlueApp = require('../../BlueApp');
|
||||
let loc = require('../../loc');
|
||||
const dayjs = require('dayjs');
|
||||
|
||||
function onlyUnique(value, index, self) {
|
||||
return self.indexOf(value) === index;
|
||||
}
|
||||
|
|
|
@ -180,65 +180,72 @@ export default class WalletsAdd extends Component {
|
|||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<BlueButton
|
||||
title={loc.wallets.add.create}
|
||||
buttonStyle={{
|
||||
width: width / 1.5,
|
||||
}}
|
||||
onPress={() => {
|
||||
this.props.navigation.goBack();
|
||||
setTimeout(async () => {
|
||||
let w;
|
||||
{!this.state.isLoading ? (
|
||||
<BlueButton
|
||||
title={loc.wallets.add.create}
|
||||
buttonStyle={{
|
||||
width: width / 1.5,
|
||||
}}
|
||||
onPress={() => {
|
||||
this.setState(
|
||||
{ isLoading: true },
|
||||
async () => {
|
||||
let w;
|
||||
|
||||
if (this.state.activeLightning) {
|
||||
// lightning was selected
|
||||
if (this.state.activeLightning) {
|
||||
// lightning was selected
|
||||
// eslint-disable-next-line
|
||||
for (let t of BlueApp.getWallets()) {
|
||||
if (t.type === LightningCustodianWallet.type) {
|
||||
// already exist
|
||||
this.setState({ isLoading: false });
|
||||
return alert('Only 1 Lightning wallet allowed for now');
|
||||
}
|
||||
}
|
||||
|
||||
global.lightning_create_try = global.lightning_create_try || 1;
|
||||
if (global.lightning_create_try++ < 9 && +new Date() < 1545264000000) return alert('Coming soon');
|
||||
// eslint-disable-next-line
|
||||
for (let t of BlueApp.getWallets()) {
|
||||
if (t.type === LightningCustodianWallet.type) {
|
||||
// already exist
|
||||
return alert('Only 1 Ligthning wallet allowed for now');
|
||||
w = new LightningCustodianWallet();
|
||||
w.setLabel(this.state.label || w.typeReadable);
|
||||
|
||||
try {
|
||||
let lndhub = await AsyncStorage.getItem(AppStorage.LNDHUB);
|
||||
if (lndhub) {
|
||||
w.setBaseURI(lndhub);
|
||||
w.init();
|
||||
}
|
||||
await w.createAccount();
|
||||
await w.authorize();
|
||||
} catch (Err) {
|
||||
this.setState({ isLoading: false });
|
||||
console.warn('lnd create failure', Err);
|
||||
// giving app, not adding anything
|
||||
}
|
||||
A(A.ENUM.CREATED_LIGHTNING_WALLET);
|
||||
} else if (this.state.selectedIndex === 1) {
|
||||
// btc was selected
|
||||
// index 1 radio - segwit single address
|
||||
w = new SegwitP2SHWallet();
|
||||
w.setLabel(this.state.label || loc.wallets.add.label_new_segwit);
|
||||
} else {
|
||||
// zero index radio - HD segwit
|
||||
w = new HDSegwitP2SHWallet();
|
||||
w.setLabel((this.state.label || loc.wallets.add.label_new_segwit) + ' HD');
|
||||
}
|
||||
}
|
||||
|
||||
w = new LightningCustodianWallet();
|
||||
w.setLabel(this.state.label || w.typeReadable);
|
||||
|
||||
try {
|
||||
let lndhub = await AsyncStorage.getItem(AppStorage.LNDHUB);
|
||||
if (lndhub) {
|
||||
w.setBaseURI(lndhub);
|
||||
w.init();
|
||||
}
|
||||
await w.createAccount();
|
||||
await w.authorize();
|
||||
} catch (Err) {
|
||||
console.warn('lnd create failure', Err);
|
||||
// giving app, not adding anything
|
||||
}
|
||||
A(A.ENUM.CREATED_LIGHTNING_WALLET);
|
||||
} else if (this.state.selectedIndex === 1) {
|
||||
// btc was selected
|
||||
// index 1 radio - segwit single address
|
||||
w = new SegwitP2SHWallet();
|
||||
w.setLabel(this.state.label || loc.wallets.add.label_new_segwit);
|
||||
} else {
|
||||
// zero index radio - HD segwit
|
||||
w = new HDSegwitP2SHWallet();
|
||||
w.setLabel((this.state.label || loc.wallets.add.label_new_segwit) + ' HD');
|
||||
}
|
||||
|
||||
await w.generate();
|
||||
BlueApp.wallets.push(w);
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
A(A.ENUM.CREATED_WALLET);
|
||||
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
||||
}, 1);
|
||||
}}
|
||||
/>
|
||||
await w.generate();
|
||||
BlueApp.wallets.push(w);
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
A(A.ENUM.CREATED_WALLET);
|
||||
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
||||
this.props.navigation.dismiss();
|
||||
},
|
||||
1,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ActivityIndicator />
|
||||
)}
|
||||
|
||||
<BlueButtonLink
|
||||
title={loc.wallets.add.import_wallet}
|
||||
|
@ -258,5 +265,6 @@ WalletsAdd.propTypes = {
|
|||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func,
|
||||
goBack: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -90,9 +90,7 @@ export default class BuyBitcoin extends Component {
|
|||
color: BlueApp.settings.buttonTextColor,
|
||||
}}
|
||||
onPress={() => {
|
||||
Linking.openURL(
|
||||
'https://payments.changelly.com/?crypto=USD&fiat=USD&ref_id=rtagfcvnwiwvhm99&address=' + this.state.address,
|
||||
);
|
||||
Linking.openURL('https://old.changelly.com/?ref_id=rtagfcvnwiwvhm99');
|
||||
}}
|
||||
title="Buy from Changelly"
|
||||
/>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Dimensions, Platform, ActivityIndicator, View } from 'react-native';
|
||||
import { QRCode as QRSlow } from 'react-native-custom-qr-codes';
|
||||
import { BlueSpacing40, SafeBlueArea, BlueCard, BlueText, BlueHeaderDefaultSub } from '../../BlueComponents';
|
||||
import { BlueSpacing40, SafeBlueArea, BlueNavigationStyle, BlueCard, BlueText } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
const QRFast = require('react-native-qrcode');
|
||||
/** @type {AppStorage} */
|
||||
|
@ -17,11 +17,11 @@ if (aspectRatio > 1.6) {
|
|||
}
|
||||
|
||||
export default class WalletExport extends Component {
|
||||
static navigationOptions = {
|
||||
header: ({ navigation }) => {
|
||||
return <BlueHeaderDefaultSub leftText={loc.wallets.export.title} onClose={() => navigation.goBack(null)} />;
|
||||
},
|
||||
};
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: loc.wallets.export.title,
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -29,7 +29,6 @@ export default class WalletExport extends Component {
|
|||
let address = props.navigation.state.params.address;
|
||||
let secret = props.navigation.state.params.secret;
|
||||
let wallet;
|
||||
|
||||
for (let w of BlueApp.getWallets()) {
|
||||
if ((address && w.getAddress() === address) || w.getSecret() === secret) {
|
||||
// found our wallet
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
BlueButton,
|
||||
SafeBlueArea,
|
||||
BlueSpacing20,
|
||||
BlueHeaderDefaultSub,
|
||||
BlueNavigationStyle,
|
||||
} from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { LightningCustodianWallet } from '../../class/lightning-custodian-wallet';
|
||||
|
@ -30,11 +30,10 @@ let loc = require('../../loc');
|
|||
const { width } = Dimensions.get('window');
|
||||
|
||||
export default class WalletsImport extends Component {
|
||||
static navigationOptions = {
|
||||
header: ({ navigation }) => {
|
||||
return <BlueHeaderDefaultSub leftText={loc.wallets.import.title} onClose={() => navigation.goBack(null)} />;
|
||||
},
|
||||
};
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(),
|
||||
title: loc.wallets.import.title,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -43,7 +42,7 @@ export default class WalletsImport extends Component {
|
|||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
label: '',
|
||||
|
@ -51,14 +50,18 @@ export default class WalletsImport extends Component {
|
|||
}
|
||||
|
||||
async _saveWallet(w) {
|
||||
alert(loc.wallets.import.success);
|
||||
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
||||
w.setLabel(loc.wallets.import.imported + ' ' + w.typeReadable);
|
||||
BlueApp.wallets.push(w);
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
A(A.ENUM.CREATED_WALLET);
|
||||
this.props.navigation.dismiss();
|
||||
if (BlueApp.getWallets().some(wallet => wallet.getSecret() === w.secret)) {
|
||||
alert('This wallet has been previously imported.');
|
||||
} else {
|
||||
alert(loc.wallets.import.success);
|
||||
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
|
||||
w.setLabel(loc.wallets.import.imported + ' ' + w.typeReadable);
|
||||
BlueApp.wallets.push(w);
|
||||
await BlueApp.saveToDisk();
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED);
|
||||
A(A.ENUM.CREATED_WALLET);
|
||||
this.props.navigation.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
async importMnemonic(text) {
|
||||
|
@ -227,6 +230,7 @@ export default class WalletsImport extends Component {
|
|||
}}
|
||||
>
|
||||
<BlueButton
|
||||
disabled={!this.state.label}
|
||||
title={loc.wallets.import.do_import}
|
||||
buttonStyle={{
|
||||
width: width / 1.5,
|
||||
|
@ -259,7 +263,7 @@ export default class WalletsImport extends Component {
|
|||
WalletsImport.propTypes = {
|
||||
navigation: PropTypes.shape({
|
||||
navigate: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
goBack: PropTypes.func,
|
||||
dismiss: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -9,15 +9,18 @@ import {
|
|||
BlueTransactionOutgoingIcon,
|
||||
BlueTransactionPendingIcon,
|
||||
BlueTransactionOffchainIcon,
|
||||
BlueTransactionExpiredIcon,
|
||||
BlueList,
|
||||
BlueListItem,
|
||||
BlueHeaderDefaultMain,
|
||||
BlueTransactionOffchainIncomingIcon,
|
||||
} from '../../BlueComponents';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { NavigationEvents } from 'react-navigation';
|
||||
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
|
||||
import PropTypes from 'prop-types';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import { LightningCustodianWallet } from '../../class';
|
||||
let EV = require('../../events');
|
||||
let A = require('../../analytics');
|
||||
/** @type {AppStorage} */
|
||||
|
@ -46,6 +49,7 @@ export default class WalletsList extends Component {
|
|||
this.state = {
|
||||
isLoading: true,
|
||||
wallets: BlueApp.getWallets().concat(false),
|
||||
lastSnappedTo: 0,
|
||||
};
|
||||
EV(EV.enum.WALLETS_COUNT_CHANGED, this.refreshFunction.bind(this));
|
||||
|
||||
|
@ -59,7 +63,8 @@ export default class WalletsList extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Forcefully fetches TXs and balance for lastSnappedTo (i.e. current) wallet
|
||||
* Forcefully fetches TXs and balance for lastSnappedTo (i.e. current) wallet.
|
||||
* Triggered manually by user on pull-to-refresh.
|
||||
*/
|
||||
refreshTransactions() {
|
||||
if (!(this.lastSnappedTo < BlueApp.getWallets().length)) {
|
||||
|
@ -135,6 +140,7 @@ export default class WalletsList extends Component {
|
|||
onSnapToItem(index) {
|
||||
console.log('onSnapToItem', index);
|
||||
this.lastSnappedTo = index;
|
||||
this.setState({ lastSnappedTo: index });
|
||||
|
||||
if (index < BlueApp.getWallets().length) {
|
||||
// not the last
|
||||
|
@ -177,6 +183,9 @@ export default class WalletsList extends Component {
|
|||
if (wallets[index].fetchPendingTransactions) {
|
||||
await wallets[index].fetchPendingTransactions();
|
||||
}
|
||||
if (wallets[index].fetchUserInvoices) {
|
||||
await wallets[index].fetchUserInvoices();
|
||||
}
|
||||
this.refreshFunction();
|
||||
didRefresh = true;
|
||||
} else {
|
||||
|
@ -221,13 +230,63 @@ 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, BitcoinUnit.BTC).toString();
|
||||
} else if (invoiceExpiration < now) {
|
||||
if (item.ispaid) {
|
||||
return loc.formatBalanceWithoutSuffix(item.value && item.value, BitcoinUnit.BTC).toString();
|
||||
} else {
|
||||
return loc.lnd.expired;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return loc.formatBalanceWithoutSuffix(item.value && item.value, BitcoinUnit.BTC).toString();
|
||||
}
|
||||
};
|
||||
|
||||
rowTitleStyle = item => {
|
||||
let color = '#37c0a1';
|
||||
|
||||
if (item.type === 'user_invoice' || item.type === 'payment_request') {
|
||||
const currentDate = new Date();
|
||||
const now = (currentDate.getTime() / 1000) | 0;
|
||||
const invoiceExpiration = item.timestamp + item.expire_time;
|
||||
|
||||
if (invoiceExpiration > now) {
|
||||
color = '#37c0a1';
|
||||
} else if (invoiceExpiration < now) {
|
||||
if (item.ispaid) {
|
||||
color = '#37c0a1';
|
||||
} else {
|
||||
color = '#FF0000';
|
||||
}
|
||||
}
|
||||
} else if (item.value / 100000000 < 0) {
|
||||
color = BlueApp.settings.foregroundColor;
|
||||
}
|
||||
|
||||
return {
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
color: color,
|
||||
};
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
|
||||
if (this.state.isLoading) {
|
||||
return <BlueLoading />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1, backgroundColor: '#FFFFFF' }}>
|
||||
<NavigationEvents
|
||||
|
@ -306,6 +365,27 @@ export default class WalletsList extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
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 }}>
|
||||
|
@ -337,6 +417,20 @@ export default class WalletsList extends Component {
|
|||
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 => wallet.type === LightningCustodianWallet.type);
|
||||
if (typeof lightningWallet === 'object') {
|
||||
if (lightningWallet.length === 1) {
|
||||
this.props.navigation.navigate('LNDViewInvoice', {
|
||||
invoice: rowData.item,
|
||||
fromWallet: lightningWallet[0],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
badge={{
|
||||
|
@ -345,15 +439,8 @@ export default class WalletsList extends Component {
|
|||
containerStyle: { marginTop: 0 },
|
||||
}}
|
||||
hideChevron
|
||||
rightTitle={loc.formatBalanceWithoutSuffix(rowData.item.value && rowData.item.value, BitcoinUnit.BTC)}
|
||||
rightTitleStyle={{
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
color:
|
||||
rowData.item.value / 100000000 < 0 || rowData.item.type === 'paid_invoice'
|
||||
? BlueApp.settings.foregroundColor
|
||||
: '#37c0a1',
|
||||
}}
|
||||
rightTitle={this.rowTitle(rowData.item)}
|
||||
rightTitleStyle={this.rowTitleStyle(rowData.item)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, { Component } from 'react';
|
||||
import { View, ActivityIndicator, Image, Text, TouchableOpacity, FlatList } from 'react-native';
|
||||
import { SafeBlueArea, BlueNavigationStyle } from '../../BlueComponents';
|
||||
import { SafeBlueArea, BlueNavigationStyle, BlueText, BlueSpacing20 } from '../../BlueComponents';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import PropTypes from 'prop-types';
|
||||
import { WatchOnlyWallet, LegacyWallet } from '../../class';
|
||||
|
@ -157,12 +157,24 @@ export default class SelectWallet extends Component {
|
|||
};
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading || this.state.data.length <= 0) {
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={{ flex: 1, paddingTop: 20 }}>
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignContent: 'center', paddingTop: 20 }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
} else if (this.state.data.length <= 0) {
|
||||
return (
|
||||
<SafeBlueArea style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', paddingTop: 20 }}>
|
||||
<BlueText style={{ textAlign: 'center' }}>There are currently no Bitcoin wallets available.</BlueText>
|
||||
<BlueSpacing20 />
|
||||
<BlueText style={{ textAlign: 'center' }}>
|
||||
A Bitcoin wallet is required to refill Lightning wallets. Please, create or import one.
|
||||
</BlueText>
|
||||
</View>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Text, View, Image, FlatList, RefreshControl, TouchableOpacity } from 'react-native';
|
||||
import { Text, View, Image, FlatList, RefreshControl, TouchableOpacity, StatusBar } from 'react-native';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import PropTypes from 'prop-types';
|
||||
import { NavigationEvents } from 'react-navigation';
|
||||
|
@ -7,6 +7,7 @@ import {
|
|||
BlueText,
|
||||
BlueTransactionOnchainIcon,
|
||||
ManageFundsBigButton,
|
||||
BlueTransactionExpiredIcon,
|
||||
BlueTransactionIncommingIcon,
|
||||
BlueTransactionOutgoingIcon,
|
||||
BlueTransactionPendingIcon,
|
||||
|
@ -14,13 +15,13 @@ import {
|
|||
BlueSendButtonIcon,
|
||||
BlueReceiveButtonIcon,
|
||||
BlueListItem,
|
||||
BlueTransactionOffchainIncomingIcon,
|
||||
} from '../../BlueComponents';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { BitcoinUnit } from '../../models/bitcoinUnits';
|
||||
import { LightningCustodianWallet } from '../../class';
|
||||
/** @type {AppStorage} */
|
||||
let BlueApp = require('../../BlueApp');
|
||||
|
||||
let loc = require('../../loc');
|
||||
let EV = require('../../events');
|
||||
|
||||
|
@ -155,6 +156,9 @@ export default class WalletTransactions extends Component {
|
|||
if (wallet.fetchPendingTransactions) {
|
||||
await wallet.fetchPendingTransactions();
|
||||
}
|
||||
if (wallet.fetchUserInvoices) {
|
||||
await wallet.fetchUserInvoices();
|
||||
}
|
||||
let end = +new Date();
|
||||
console.log(wallet.getLabel(), 'fetch tx took', (end - start) / 1000, 'sec');
|
||||
} catch (err) {
|
||||
|
@ -289,15 +293,72 @@ export default class WalletTransactions extends Component {
|
|||
};
|
||||
|
||||
async onWillBlur() {
|
||||
StatusBar.setBarStyle('dark-content');
|
||||
await BlueApp.saveToDisk();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
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()).toString();
|
||||
} else if (invoiceExpiration < now) {
|
||||
if (item.ispaid) {
|
||||
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit()).toString();
|
||||
} else {
|
||||
return loc.lnd.expired;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit()).toString();
|
||||
}
|
||||
};
|
||||
|
||||
rowTitleStyle = item => {
|
||||
let color = '#37c0a1';
|
||||
|
||||
if (item.type === 'user_invoice' || item.type === 'payment_request') {
|
||||
const currentDate = new Date();
|
||||
const now = (currentDate.getTime() / 1000) | 0;
|
||||
const invoiceExpiration = item.timestamp + item.expire_time;
|
||||
|
||||
if (invoiceExpiration > now) {
|
||||
color = '#37c0a1';
|
||||
} else if (invoiceExpiration < now) {
|
||||
if (item.ispaid) {
|
||||
color = '#37c0a1';
|
||||
} else {
|
||||
color = '#FF0000';
|
||||
}
|
||||
}
|
||||
} else if (item.value / 100000000 < 0) {
|
||||
color = BlueApp.settings.foregroundColor;
|
||||
}
|
||||
|
||||
return {
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
color: color,
|
||||
};
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<NavigationEvents
|
||||
onWillFocus={() => {
|
||||
StatusBar.setBarStyle('light-content');
|
||||
this.refreshFunction();
|
||||
}}
|
||||
onWillBlur={() => this.onWillBlur()}
|
||||
|
@ -311,7 +372,7 @@ export default class WalletTransactions extends Component {
|
|||
style={{ alignSelf: 'flex-end', right: 10, flexDirection: 'row' }}
|
||||
onPress={() => {
|
||||
console.log('navigating to', this.state.wallet.getLabel());
|
||||
navigate('ManageFunds', { fromSecret: this.state.wallet.getSecret() });
|
||||
navigate('ManageFunds', { fromWallet: this.state.wallet });
|
||||
}}
|
||||
>
|
||||
<BlueText style={{ fontWeight: '600', fontSize: 16 }}>{loc.lnd.title}</BlueText>
|
||||
|
@ -378,7 +439,6 @@ export default class WalletTransactions extends Component {
|
|||
}
|
||||
refreshControl={<RefreshControl onRefresh={() => this.refreshTransactions()} refreshing={this.state.isTransactionsLoading} />}
|
||||
data={this.state.dataSource}
|
||||
extraData={this.state.dataSource}
|
||||
keyExtractor={this._keyExtractor}
|
||||
renderItem={rowData => {
|
||||
return (
|
||||
|
@ -409,6 +469,27 @@ export default class WalletTransactions extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
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 }}>
|
||||
|
@ -440,6 +521,15 @@ export default class WalletTransactions extends Component {
|
|||
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('LNDViewExistingInvoice', {
|
||||
invoice: rowData.item,
|
||||
fromWallet: this.state.wallet,
|
||||
});
|
||||
}
|
||||
}}
|
||||
badge={{
|
||||
|
@ -448,20 +538,8 @@ export default class WalletTransactions extends Component {
|
|||
containerStyle: { marginTop: 0 },
|
||||
}}
|
||||
hideChevron
|
||||
rightTitle={loc
|
||||
.formatBalanceWithoutSuffix(
|
||||
(rowData.item.value && rowData.item.value) || 0,
|
||||
this.state.wallet.getPreferredBalanceUnit(),
|
||||
)
|
||||
.toString()}
|
||||
rightTitleStyle={{
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
color:
|
||||
rowData.item.value / 100000000 < 0 || rowData.item.type === 'paid_invoice'
|
||||
? BlueApp.settings.foregroundColor
|
||||
: '#37c0a1',
|
||||
}}
|
||||
rightTitle={this.rowTitle(rowData.item)}
|
||||
rightTitleStyle={this.rowTitleStyle(rowData.item)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
@ -474,7 +552,9 @@ export default class WalletTransactions extends Component {
|
|||
backgroundColor: 'transparent',
|
||||
position: 'absolute',
|
||||
bottom: 30,
|
||||
borderRadius: 15,
|
||||
borderRadius: 30,
|
||||
minHeight: 48,
|
||||
flex: 0.84,
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
|
@ -483,9 +563,10 @@ export default class WalletTransactions extends Component {
|
|||
return (
|
||||
<BlueReceiveButtonIcon
|
||||
onPress={() => {
|
||||
navigate('ReceiveDetails', { address: this.state.wallet.getAddress(), secret: this.state.wallet.getSecret() });
|
||||
if (this.state.wallet.getAddress()) {
|
||||
// EV(EV.enum.RECEIVE_ADDRESS_CHANGED, w.getAddress());
|
||||
if (this.state.wallet.type === new LightningCustodianWallet().type) {
|
||||
navigate('LNDCreateInvoice', { fromWallet: this.state.wallet });
|
||||
} else {
|
||||
navigate('ReceiveDetails', { address: this.state.wallet.getAddress(), secret: this.state.wallet.getSecret() });
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
@ -515,7 +596,7 @@ export default class WalletTransactions extends Component {
|
|||
<ManageFundsBigButton
|
||||
onPress={() => {
|
||||
console.log('navigating to', this.state.wallet.getLabel());
|
||||
navigate('ManageFunds', { fromSecret: this.state.wallet.getSecret() });
|
||||
navigate('ManageFunds', { fromWallet: this.state.wallet });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Dimensions, Platform, ActivityIndicator, View, Clipboard, Animated, TouchableOpacity } from 'react-native';
|
||||
import { QRCode as QRSlow } from 'react-native-custom-qr-codes';
|
||||
import { BlueSpacing40, SafeBlueArea, BlueCard, BlueText, BlueHeaderDefaultSub } from '../../BlueComponents';
|
||||
import { BlueSpacing40, SafeBlueArea, BlueCard, BlueText, BlueNavigationStyle } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
const QRFast = require('react-native-qrcode');
|
||||
/** @type {AppStorage} */
|
||||
|
@ -17,11 +17,11 @@ if (aspectRatio > 1.6) {
|
|||
}
|
||||
|
||||
export default class WalletXpub extends Component {
|
||||
static navigationOptions = {
|
||||
header: ({ navigation }) => {
|
||||
return <BlueHeaderDefaultSub leftText={loc.wallets.xpub.title} onClose={() => navigation.goBack(null)} />;
|
||||
},
|
||||
};
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: loc.wallets.xpub.title,
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
|
Loading…
Add table
Reference in a new issue