Merge pull request #3 from BlueWallet/master

merged from original repo
This commit is contained in:
sansegkh 2019-01-07 21:20:52 +07:00 committed by GitHub
commit a33efc020d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 688 additions and 184 deletions

View file

@ -106,6 +106,7 @@ export class LightningButton extends Component {
render() {
return (
<TouchableOpacity
disabled={this.props.disabled}
onPress={() => {
// eslint-disable-next-line
if (this.props.onPress) this.props.onPress();
@ -136,6 +137,10 @@ export class LightningButton extends Component {
}
}
LightningButton.propTypes = {
disabled: PropTypes.bool,
};
export class BlueButtonLink extends Component {
render() {
// eslint-disable-next-line
@ -1055,7 +1060,7 @@ export class WalletsCarousel extends Component {
color: '#fff',
}}
>
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit())}
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true)}
</Text>
<Text style={{ backgroundColor: 'transparent' }} />
<Text
@ -1131,14 +1136,17 @@ export class BlueBitcoinAmount extends Component {
<View>
<View style={{ flexDirection: 'row', justifyContent: 'center', paddingTop: 16, paddingBottom: 16 }}>
<TextInput
{...this.props}
keyboardType="numeric"
onChangeText={text =>
this.props.onChangeText(
this.props.unit === BitcoinUnit.BTC
? text.replace(new RegExp('[^0-9.]'), '', '.')
: text.replace(new RegExp('[^0-9]'), ''),
)
onChangeText={text => {
text = text.replace(',', '.');
text = this.props.unit === BitcoinUnit.BTC ? text.replace(/[^0-9.]/g, '') : text.replace(/[^0-9]/g, '');
text = text.replace(/(\..*)\./g, '$1');
if (text.startsWith('.')) {
text = '0.';
}
this.props.onChangeText(text);
}}
placeholder="0"
maxLength={10}
ref={textInput => (this.textInput = textInput)}
@ -1150,7 +1158,6 @@ export class BlueBitcoinAmount extends Component {
fontSize: 36,
fontWeight: '600',
}}
{...this.props}
/>
<Text
style={{
@ -1168,8 +1175,9 @@ export class BlueBitcoinAmount extends Component {
<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),
this.props.unit === BitcoinUnit.BTC ? amount || 0 : loc.formatBalanceWithoutSuffix(amount || 0, BitcoinUnit.BTC, false),
BitcoinUnit.LOCAL_CURRENCY,
false,
)}
</Text>
</View>

View file

@ -342,7 +342,11 @@ export class AppStorage {
let txs = [];
for (let wallet of this.wallets) {
txs = txs.concat(wallet.getTransactions());
let walletTransactions = wallet.getTransactions();
for (let t of walletTransactions) {
t.walletPreferredBalanceUnit = wallet.getPreferredBalanceUnit();
}
txs = txs.concat(walletTransactions);
}
for (let t of txs) {

View file

@ -33,7 +33,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>215</string>
<string>223</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSRequiresIPhoneOS</key>

View file

@ -8,10 +8,13 @@ module.exports = {
hours_ago: 'hodin',
minutes_ago: 'minut',
never: 'nikdy',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'Vyberte peněženku',
options: 'možnosti',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'Blue Wallet',
title: 'peněženky',

215
loc/da_DK.js Normal file
View file

@ -0,0 +1,215 @@
module.exports = {
_: {
storage_is_encrypted: 'Lageret er krypteret. Indtast adgangskode for at dekryptere',
enter_password: 'Indtast adgangskode',
bad_password: 'Forkert adgangskode, prøv igen',
months_ago: 'måneder siden',
days_ago: 'dage siden',
hours_ago: 'timer siden',
minutes_ago: 'minutter siden',
never: 'aldrig',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'Vælg wallet',
options: 'valgmuligheder',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'Blue Wallet',
title: 'wallets',
header: 'En wallet består af par af hemmelige (private nøgler) og en adresse' + 'som du kan dele med andre for at modtage coins.',
add: 'Tilføj Wallet',
create_a_wallet: 'Opret en wallet',
create_a_wallet1: 'Det er helt gratis og du kan oprette',
create_a_wallet2: 'lige så mange du vil',
latest_transaction: 'seneste transaktion',
empty_txs1: 'Dine transaktioner vil blive vist her,',
empty_txs2: 'ingen endnu',
tap_here_to_buy: 'Tryk her for at købe Bitcoin',
},
reorder: {
title: 'Ændre rækkefølgen af wallets',
},
add: {
title: 'Tilføj wallet',
description:
'Du kan enten scanne en backup papir wallet (i et WIF - Wallet Import Format), eller oprette en ny wallet. Segwit wallets er understøttet som standard.',
scan: 'Scan',
create: 'Opret',
label_new_segwit: 'Ny SegWit',
label_new_lightning: 'Ny Lightning',
wallet_name: 'wallet navn',
wallet_type: 'type',
or: 'eller',
import_wallet: 'Importer wallet',
imported: 'Importeret',
coming_soon: 'Kommer snart',
lightning: 'Lightning',
bitcoin: 'Bitcoin',
},
details: {
title: 'Wallet',
address: 'Adresse',
type: 'Type',
label: 'Etiket',
destination: 'destination',
description: 'bskrivelse',
are_you_sure: 'Er du sikker?',
yes_delete: 'Ja, slet',
no_cancel: 'Nej, annuller',
delete: 'Slet',
save: 'Gem',
delete_this_wallet: 'Slet denne wallet',
export_backup: 'Eksporter / backup',
buy_bitcoin: 'Køb Bitcoin',
show_xpub: 'Vis wallet XPUB',
},
export: {
title: 'wallet eksport',
},
xpub: {
title: 'wallet XPUB',
copiedToClipboard: 'Kopieret til udklipsholder.',
},
import: {
title: 'importer',
explanation:
'Indtast din huskeregel, private nøgle, WIF, eller hvad du end har. BlueWallet vil forsøge at gætte det rigtige format og importere din wallet',
imported: 'Importeret',
error: 'Importen lykkedes ikke. Er det en gyldig nøgle?',
success: 'Succes',
do_import: 'Importer',
scan_qr: 'eller scan QR kode istedet?',
},
scanQrWif: {
go_back: 'Tilbage',
cancel: 'Annuller',
decoding: 'Afkoder',
input_password: 'Indtast adgangskode',
password_explain: 'Dette er en BIP38 krypteret privat nøgle',
bad_password: 'Forkert adgangkode',
wallet_already_exists: 'En sådan wallet eksisterer allerede',
bad_wif: 'Forkert WIF',
imported_wif: 'Importeret WIF ',
with_address: ' med adresse ',
imported_segwit: 'Importeret SegWit',
imported_legacy: 'Importeret Legacy',
imported_watchonly: 'Importeret Watch-only',
},
},
transactions: {
list: {
tabBarLabel: 'Transaktioner',
title: 'transaktioner',
description: 'En liste af indgåeende og udgående transaktioner i dine wallets',
conf: 'conf',
},
details: {
title: 'Transaktion',
from: 'Fra',
to: 'Til',
copy: 'Kopier',
transaction_details: 'Transaktions detaljer',
show_in_block_explorer: 'Vis i block-explorer',
},
},
send: {
header: 'Send',
details: {
title: 'opret transaktion',
amount_field_is_not_valid: 'Beløbsfeltet er ikke gyldigt',
fee_field_is_not_valid: 'Gebyr feltet er ikke gyldigt',
address_field_is_not_valid: 'Adresse felt er ikke gyldigt',
total_exceeds_balance: 'Beløbet du prøver at sende er større end din kontosaldo.',
create_tx_error: 'Der skete en fejl ved oprettelse af transaktionen. Check om addressen er gyldig.',
address: 'adresse',
amount_placeholder: 'beløb der skal sendes (i BTC)',
fee_placeholder: 'plus transaktionsgebyr (i BTC)',
note_placeholder: 'Notat til eget brug',
cancel: 'Annuller',
scan: 'Scan',
send: 'Send',
create: 'Opret',
remaining_balance: 'Resterende saldo',
},
confirm: {
header: 'Bekræft',
sendNow: 'Send nu',
},
success: {
done: 'Udført',
},
create: {
details: 'Detaljer',
title: 'opret transaktion',
error: 'Der skete en fejl ved oprettelse af transaktionen. Er addresssen og beløbet korrekt?',
go_back: 'Tilbage',
this_is_hex: 'Dette er transaktion hex, klar til at sende ud til netværket.',
to: 'Til',
amount: 'Beløb',
fee: 'Gebyr',
tx_size: 'TX størrelse',
satoshi_per_byte: 'Satoshi per byte',
memo: 'Notat',
broadcast: 'Transmitter',
not_enough_fee: 'Gebyret er ikke højt nok. Forhøj gebyret.',
},
},
receive: {
header: 'Modtag',
details: {
title: 'Del denne adresse med betaleren',
share: 'del',
copiedToClipboard: 'Kopieret til udklipsholder.',
label: 'Beskrivelse',
setAmount: 'Modtag med beløb',
},
},
buyBitcoin: {
header: 'Køb Bitcoin',
tap_your_address: 'Tryk på addressen og kopier den til udklipsholder:',
copied: 'Kopieret til udklipsholder!',
},
settings: {
header: 'indstillinger',
plausible_deniability: 'Sandsynlig benægtelse...',
storage_not_encrypted: 'Lager: ikke krypteret',
storage_encrypted: 'Lager: krypteret',
password: 'Adgangskode',
password_explain: 'Indtast den adgangskode du vil bruge til at kryptere lageret',
retype_password: 'Gentag adgangskoden',
passwords_do_not_match: 'Adgangskoden er ikke den samme',
encrypt_storage: 'Krypter lager',
about: 'Andet',
language: 'Sprog',
currency: 'Valuta',
},
plausibledeniability: {
title: 'Sandsynlig benægtelse',
help:
'Under visse omstændighder, kan du blive tvunget til at give din ' +
'adgangskode. For at beskytte dine coins kan du med Bluewallet lave ' +
'et falsk krypteret lager, med en anden kode. I en presset situation, ' +
'kan du give denne adgangskode istedet. Hvis denne kode indtastes i ' +
'BlueWallet, vil brugeren se den alternative wallet. Det vil se helt' +
'legitimt ud for andre, og dermed beskytte din originale wallet og ' +
'dine coins.',
help2: 'Det nye lager vil være fuldt funktionsdygtigt, og du kan evt have nogle ' + 'småbeløb så det ser troværdigt ud.',
create_fake_storage: 'Opret falsk kryopteret lager',
go_back: 'tilbage',
create_password: 'Opret adgangskode',
create_password_explanation: 'Adgangskoden til det falske lager må ikke være den samme som den du bruger til det rigtige lager',
password_should_not_match: 'Adgangskoden til det falske lager må ikke være den samme som den du bruger til det rigtige lager',
retype_password: 'Indtast adgangskoden igen',
passwords_do_not_match: 'Adgangskoden er ikke den samme, prøv igen',
success: 'Succes',
},
lnd: {
title: 'Administration',
choose_source_wallet: 'Vælge en wallet',
refill_lnd_balance: 'Genopfyld Lightning wallet',
refill: 'Genopfyld',
withdraw: 'Træk coins tilbage',
},
};

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'Stunden zurück',
minutes_ago: 'Minuten zurück',
never: 'nie',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'Wähle Wallet',
options: 'Einstellungen',
createBitcoinWallet:
'In order to use a Lightning wallet, a Bitcoin wallet is needed in order to fund it. Please, create or import a Bitcoin wallet.',
list: {
app_name: 'Blue Wallet',
title: 'Wallets',

View file

@ -8,10 +8,13 @@ module.exports = {
hours_ago: 'hours ago',
minutes_ago: 'minutes ago',
never: 'never',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'Select Wallet',
options: 'options',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'Blue Wallet',
title: 'wallets',

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'horas atras',
minutes_ago: 'minutos atras',
never: 'nunca',
continue: 'Continua',
ok: 'OK',
},
wallets: {
options: 'opciones',
select_wallet: 'Selecciona billetera',
createBitcoinWallet:
'In order to use a Lightning wallet, a Bitcoin wallet is needed in order to fund it. Would you like to continue anyway?',
list: {
app_name: 'Blue Wallet',
title: 'billeteras',

219
loc/fr_FR.js Normal file
View file

@ -0,0 +1,219 @@
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',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'Choix du portefeuille',
options: 'options',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
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.',
},
};

View file

@ -26,11 +26,13 @@ let strings;
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 === 'da-dk' ||
locale === 'nl-nl'
) {
locale = locale.replace('-', '_');
@ -50,9 +52,11 @@ strings = new Localization({
es: require('./es.js'),
ua: require('./ua.js'),
de_de: require('./de_DE.js'),
da_dk: require('./da_DK.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);
@ -96,7 +100,7 @@ function removeTrailingZeros(value) {
* @param toUnit {String} Value from models/bitcoinUnits.js
* @returns {string}
*/
strings.formatBalance = (balance, toUnit) => {
strings.formatBalance = (balance, toUnit, withFormatting = false) => {
if (toUnit === undefined) {
return balance + ' ' + BitcoinUnit.BTC;
}
@ -104,7 +108,7 @@ strings.formatBalance = (balance, toUnit) => {
return balance + ' ' + BitcoinUnit.BTC;
} else if (toUnit === BitcoinUnit.SATS) {
const value = new BigNumber(balance).multipliedBy(100000000);
return new Intl.NumberFormat().format(value.toString()) + ' ' + BitcoinUnit.SATS;
return (withFormatting ? new Intl.NumberFormat().format(value.toString()).replace(',', ' ') : value) + ' ' + BitcoinUnit.SATS;
} else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) {
return currency.BTCToLocalCurrency(balance);
}
@ -116,7 +120,7 @@ strings.formatBalance = (balance, toUnit) => {
* @param toUnit {String} Value from models/bitcoinUnits.js
* @returns {string}
*/
strings.formatBalanceWithoutSuffix = (balance, toUnit) => {
strings.formatBalanceWithoutSuffix = (balance, toUnit, withFormatting = false) => {
if (toUnit === undefined) {
return balance;
}
@ -125,7 +129,7 @@ strings.formatBalanceWithoutSuffix = (balance, toUnit) => {
const value = new BigNumber(balance).dividedBy(100000000).toFixed(8);
return removeTrailingZeros(value);
} else if (toUnit === BitcoinUnit.SATS) {
return new Intl.NumberFormat().format(balance);
return withFormatting ? new Intl.NumberFormat().format(balance).replace(',', ' ') : balance;
} else if (toUnit === BitcoinUnit.LOCAL_CURRENCY) {
return currency.satoshiToLocalCurrency(balance);
}

View file

@ -8,10 +8,13 @@ module.exports = {
hours_ago: 'uur geleden',
minutes_ago: 'minuten geleden',
never: 'nooit',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'Selecteer portemonnee',
options: 'opties',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'Blue Wallet',
title: 'portemonnees',

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'horas atrás',
minutes_ago: 'minutos atrás',
never: 'nunca',
continue: 'Continue',
ok: 'OK',
},
wallets: {
options: 'opções',
select_wallet: 'Escolher carteira',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
tabBarLabel: 'Carteiras',
app_name: 'Blue Wallet',

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'hours ago',
minutes_ago: 'minutes ago',
never: 'never',
continue: 'Continue',
ok: 'OK',
},
wallets: {
options: 'options',
select_wallet: 'Select Wallet',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'Blue Wallet',
title: 'wallets',

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'часов назад',
minutes_ago: 'минут назад',
never: 'никогда',
continue: 'Continue',
ok: 'OK',
},
wallets: {
options: 'options',
select_wallet: 'Select Wallet',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'BlueWallet',
title: 'кошельки',

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'ชั่วโมงที่แล้ว',
minutes_ago: 'นาทีที่แล้ว',
never: 'ไม่เคย',
continue: 'Continue',
ok: 'OK',
},
wallets: {
select_wallet: 'เลือกกระเป๋าสตางค์',
options: 'ทางเลือก',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'บูลวอลเล็ต',
title: 'กระเป๋าสตางค์',

View file

@ -8,10 +8,14 @@ module.exports = {
hours_ago: 'часів тому',
minutes_ago: 'мінут тому',
never: 'ніколи',
continue: 'Continue',
ok: 'OK',
},
wallets: {
options: 'options',
select_wallet: 'Select Wallet',
createBitcoinWallet: 'In order to use a Lightning wallet, a Bitcoin wallet is needed to fund it. Would you like to continue anyway?',
list: {
app_name: 'BlueWallet',
title: 'гаманці',

View file

@ -1,14 +1,15 @@
export const FiatUnit = Object.freeze({
USD: { endPointKey: 'USD', symbol: '$', locale: 'en-US' },
AUD: { endPointKey: 'AUD', symbol: '$', locale: 'en-AU' },
CAD: { endPointKey: 'CAD', symbol: '$', locale: 'en-CA' },
CZK: { endPointKey: 'CZK', symbol: 'Kč', locale: 'cs-CZ' },
CNY: { endPointKey: 'CNY', symbol: '¥', locale: 'zh-CN' },
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' },
JPY: { endPointKey: 'JPY', symbol: '¥', locale: 'ja-JP' },
RUB: { endPointKey: 'RUB', symbol: '₽', locale: 'ru-RU' },
SGD: { endPointKey: 'SGD', symbol: 'S$', locale: 'zh-SG' },
VEF: { endPointKey: 'VEF', symbol: 'Bs.', locale: 'es-VE' },
ZAR: { endPointKey: 'ZAR', symbol: 'R', locale: 'en-ZA' },
});

View file

@ -71,7 +71,8 @@ export default class ScanLndInvoice extends React.Component {
}
}
async processInvoice(data) {
processInvoice(data) {
this.setState({ isLoading: true }, async () => {
if (this.ignoreRead) return;
this.ignoreRead = true;
setTimeout(() => {
@ -107,11 +108,13 @@ export default class ScanLndInvoice extends React.Component {
expiresIn,
destination: data,
isAmountInitiallyEmpty: decoded.num_satoshis === '0',
isLoading: false,
});
} catch (Err) {
this.setState({ destination: '' });
this.setState({ isLoading: false });
alert(Err.message);
}
});
}
async pay() {
@ -144,7 +147,7 @@ export default class ScanLndInvoice extends React.Component {
let start = +new Date();
let end;
try {
await fromWallet.payInvoice(this.state.invoice, this.state.invoice.num_satoshis);
await fromWallet.payInvoice(this.state.invoice, this.state.decoded.num_satoshis);
end = +new Date();
} catch (Err) {
console.log(Err.message);
@ -191,7 +194,7 @@ export default class ScanLndInvoice extends React.Component {
amount={typeof this.state.decoded === 'object' ? this.state.decoded.num_satoshis : 0}
onChangeText={text => {
if (typeof this.state.decoded === 'object') {
text = parseInt(text);
text = parseInt(text || 0);
let decoded = this.state.decoded;
decoded.num_satoshis = text;
this.setState({ decoded: decoded });

View file

@ -220,7 +220,7 @@ export default class SendDetails extends Component {
.then(response => {
this.setState({
address: response.address,
amount: loc.formatBalanceWithoutSuffix(response.amount, BitcoinUnit.BTC),
amount: loc.formatBalanceWithoutSuffix(response.amount, BitcoinUnit.BTC, false),
memo: response.memo,
fee: response.fee,
bip70TransactionExpiration: response.expires,
@ -229,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 });
});
},
);

View file

@ -18,15 +18,17 @@ export default class Language extends Component {
language: loc.getLanguage(),
availableLanguages: [
{ label: 'English', value: 'en' },
{ label: 'Русский', value: 'ru' },
{ label: 'Українська', value: 'ua' },
{ label: 'Spanish', value: 'es' },
{ label: 'Česky (CZ)', value: 'cs_cz' },
{ label: 'Danish (DK)', value: 'da_dk' },
{ label: 'Deutsch (DE)', value: 'de_de' },
{ label: 'Dutch (NL)', value: 'nl_nl' },
{ label: 'Français (FR)', value: 'fr_fr' },
{ 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: 'Русский', value: 'ru' },
{ label: 'Spanish', value: 'es' },
{ label: 'Thai (TH)', value: 'th_th' },
{ label: 'Dutch (NL)', value: 'nl_nl' },
{ label: 'Українська', value: 'ua' },
],
};
}

View file

@ -1,6 +1,6 @@
/* global alert */
import React, { Component } from 'react';
import { AsyncStorage, ActivityIndicator, Keyboard, Dimensions, View, TextInput, TouchableWithoutFeedback } from 'react-native';
import { Alert, AsyncStorage, ActivityIndicator, Keyboard, Dimensions, View, TextInput, TouchableWithoutFeedback } from 'react-native';
import {
BlueTextCentered,
BlueText,
@ -140,6 +140,7 @@ export default class WalletsAdd extends Component {
height: (width - 60) / 3,
}}
title={loc.wallets.add.create}
disabled={BlueApp.getWallets().some(wallet => wallet.type === LightningCustodianWallet.type)}
/>
</View>
</View>
@ -193,16 +194,19 @@ export default class WalletsAdd extends Component {
let w;
if (this.state.activeLightning) {
// lightning was selected
// eslint-disable-next-line
for (let t of BlueApp.getWallets()) {
let hasBitcoinWallet = false;
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');
} else if (t.type !== LightningCustodianWallet.type) {
hasBitcoinWallet = true;
}
}
this.createLightningWallet = async () => {
w = new LightningCustodianWallet();
w.setLabel(this.state.label || w.typeReadable);
@ -220,6 +224,40 @@ for (let t of BlueApp.getWallets()) {
// giving app, not adding anything
}
A(A.ENUM.CREATED_LIGHTNING_WALLET);
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();
};
if (!hasBitcoinWallet) {
Alert.alert(
loc.wallets.add.lightning,
loc.wallets.createBitcoinWallet,
[
{
text: loc.send.details.cancel,
style: 'cancel',
onPress: () => {
this.setState({ isLoading: false });
},
},
{
text: loc._.ok,
style: 'default',
onPress: () => {
this.createLightningWallet();
},
},
],
{ cancelable: false },
);
} else {
this.createLightningWallet();
}
} else if (this.state.selectedIndex === 1) {
// btc was selected
// index 1 radio - segwit single address
@ -230,7 +268,7 @@ for (let t of BlueApp.getWallets()) {
w = new HDSegwitP2SHWallet();
w.setLabel((this.state.label || loc.wallets.add.label_new_segwit) + ' HD');
}
if (this.state.activeBitcoin) {
await w.generate();
BlueApp.wallets.push(w);
await BlueApp.saveToDisk();
@ -238,6 +276,7 @@ for (let t of BlueApp.getWallets()) {
A(A.ENUM.CREATED_WALLET);
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
this.props.navigation.dismiss();
}
},
1,
);

View file

@ -32,18 +32,8 @@ export default class WalletDetails extends Component {
constructor(props) {
super(props);
let address = props.navigation.state.params.address;
let secret = props.navigation.state.params.secret;
/** @type {AbstractWallet} */
let wallet;
for (let w of BlueApp.getWallets()) {
if ((address && w.getAddress() === address) || w.getSecret() === secret) {
// found our wallet
wallet = w;
}
}
const wallet = props.navigation.getParam('wallet');
const address = wallet.getAddress();
this.state = {
isLoading: true,
@ -54,18 +44,19 @@ export default class WalletDetails extends Component {
this.props.navigation.setParams({ saveAction: () => this.setLabel() });
}
async componentDidMount() {
componentDidMount() {
this.setState({
isLoading: false,
});
}
async setLabel() {
setLabel() {
this.setState({ isLoading: true }, () => {
this.state.wallet.setLabel(this.state.walletName);
BlueApp.saveToDisk();
alert('Wallet updated.');
this.props.navigation.goBack(null);
});
}
render() {
@ -187,12 +178,14 @@ export default class WalletDetails extends Component {
{
text: loc.wallets.details.yes_delete,
onPress: async () => {
this.setState({ isLoading: true }, async () => {
BlueApp.deleteWallet(this.state.wallet);
ReactNativeHapticFeedback.trigger('notificationSuccess', false);
await BlueApp.saveToDisk();
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
EV(EV.enum.WALLETS_COUNT_CHANGED);
this.props.navigation.navigate('Wallets');
});
},
style: 'destructive',
},
@ -222,6 +215,7 @@ WalletDetails.propTypes = {
}),
navigate: PropTypes.func,
goBack: PropTypes.func,
getParam: PropTypes.func,
setParams: PropTypes.func,
}),
};

View file

@ -1,20 +1,13 @@
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, BlueNavigationStyle, BlueCard, BlueText } from '../../BlueComponents';
import { BlueSpacing20, SafeBlueArea, BlueNavigationStyle, BlueText } from '../../BlueComponents';
import PropTypes from 'prop-types';
const QRFast = require('react-native-qrcode');
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
let loc = require('../../loc');
const { height, width } = Dimensions.get('window');
const aspectRatio = height / width;
let isIpad;
if (aspectRatio > 1.6) {
isIpad = false;
} else {
isIpad = true;
}
export default class WalletExport extends Component {
static navigationOptions = ({ navigation }) => ({
@ -38,11 +31,12 @@ export default class WalletExport extends Component {
this.state = {
isLoading: true,
qrCodeHeight: height > width ? height / 2.5 : width / 2,
wallet,
};
}
async componentDidMount() {
componentDidMount() {
this.setState({
isLoading: false,
showQr: false,
@ -54,17 +48,15 @@ export default class WalletExport extends Component {
}, 1000);
}
determineSize = () => {
if (width > 312) {
return width - 48;
}
return 312;
onLayout = () => {
const { height } = Dimensions.get('window');
this.setState({ qrCodeHeight: height > width ? height / 2.5 : width / 2 });
};
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 20 }}>
<View style={{ flex: 1, paddingTop: 20 }} onLayout={this.onLayout}>
<ActivityIndicator />
</View>
);
@ -82,12 +74,7 @@ export default class WalletExport extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
{(() => {
if (isIpad) {
return <BlueSpacing40 />;
}
})()}
<BlueCard style={{ alignItems: 'center', flex: 1 }}>
<View style={{ alignItems: 'center', flex: 1, justifyContent: 'center', paddingHorizontal: 0 }} onLayout={this.onLayout}>
<View>
<BlueText>{this.state.wallet.typeReadable}</BlueText>
</View>
@ -101,14 +88,14 @@ export default class WalletExport extends Component {
);
}
})()}
<BlueSpacing20 />
{(() => {
if (this.state.showQr) {
if (Platform.OS === 'ios' || this.state.wallet.getSecret().length < 54) {
return (
<QRSlow
content={this.state.wallet.getSecret()}
size={this.determineSize()}
size={this.state.qrCodeHeight}
color={BlueApp.settings.foregroundColor}
backgroundColor={BlueApp.settings.brandingColor}
logo={require('../../img/qr-code.png')}
@ -119,7 +106,7 @@ export default class WalletExport extends Component {
return (
<QRFast
value={this.state.wallet.getSecret()}
size={this.determineSize()}
size={this.state.qrCodeHeight}
fgColor={BlueApp.settings.brandingColor}
bgColor={BlueApp.settings.foregroundColor}
/>
@ -133,9 +120,10 @@ export default class WalletExport extends Component {
);
}
})()}
<BlueSpacing20 />
<BlueText style={{ marginVertical: 8 }}>{this.state.wallet.getSecret()}</BlueText>
</BlueCard>
<BlueText style={{ alignItems: 'center', paddingHorizontal: 8 }}>{this.state.wallet.getSecret()}</BlueText>
</View>
</SafeBlueArea>
);
}

View file

@ -19,7 +19,6 @@ 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');
@ -233,23 +232,23 @@ export default class WalletsList extends Component {
rowTitle = item => {
if (item.type === 'user_invoice' || item.type === 'payment_request') {
if (isNaN(item.value)) {
item.value = "0"
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();
return loc.formatBalanceWithoutSuffix(item.value && item.value, item.walletPreferredBalanceUnit, true).toString();
} else if (invoiceExpiration < now) {
if (item.ispaid) {
return loc.formatBalanceWithoutSuffix(item.value && item.value, BitcoinUnit.BTC).toString();
return loc.formatBalanceWithoutSuffix(item.value && item.value, item.walletPreferredBalanceUnit, true).toString();
} else {
return loc.lnd.expired;
}
}
} else {
return loc.formatBalanceWithoutSuffix(item.value && item.value, BitcoinUnit.BTC).toString();
return loc.formatBalanceWithoutSuffix(item.value && item.value, item.walletPreferredBalanceUnit, true).toString();
}
};

View file

@ -151,7 +151,7 @@ export default class ReorderWallets extends Component {
color: '#fff',
}}
>
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit())}
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true)}
</Text>
<Text style={{ backgroundColor: 'transparent' }} />
<Text

View file

@ -126,7 +126,7 @@ export default class SelectWallet extends Component {
color: '#fff',
}}
>
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit())}
{loc.formatBalance(Number(item.getBalance()), item.getPreferredBalanceUnit(), true)}
</Text>
<Text style={{ backgroundColor: 'transparent' }} />
<Text

View file

@ -33,8 +33,7 @@ export default class WalletTransactions extends Component {
style={{ marginHorizontal: 8, minWidth: 150 }}
onPress={() =>
navigation.navigate('WalletDetails', {
address: navigation.state.params.wallet.getAddress(),
secret: navigation.state.params.wallet.getSecret(),
wallet: navigation.state.params.wallet,
})
}
>
@ -236,7 +235,7 @@ export default class WalletTransactions extends Component {
color: '#fff',
}}
>
{loc.formatBalance(this.state.wallet.getBalance(), this.state.wallet.getPreferredBalanceUnit()).toString()}
{loc.formatBalance(this.state.wallet.getBalance(), this.state.wallet.getPreferredBalanceUnit(), true).toString()}
</Text>
</TouchableOpacity>
<Text style={{ backgroundColor: 'transparent' }} />
@ -304,23 +303,23 @@ export default class WalletTransactions extends Component {
rowTitle = item => {
if (item.type === 'user_invoice' || item.type === 'payment_request') {
if (isNaN(item.value)) {
item.value = 0
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();
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit(), true).toString();
} else if (invoiceExpiration < now) {
if (item.ispaid) {
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit()).toString();
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit(), true).toString();
} else {
return loc.lnd.expired;
}
}
} else {
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit()).toString();
return loc.formatBalanceWithoutSuffix(item.value && item.value, this.state.wallet.getPreferredBalanceUnit(), true).toString();
}
};

View file

@ -1,20 +1,13 @@
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, BlueNavigationStyle } from '../../BlueComponents';
import { BlueSpacing20, SafeBlueArea, BlueText, BlueNavigationStyle } from '../../BlueComponents';
import PropTypes from 'prop-types';
const QRFast = require('react-native-qrcode');
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
let loc = require('../../loc');
const { height, width } = Dimensions.get('window');
const aspectRatio = height / width;
let isIpad;
if (aspectRatio > 1.6) {
isIpad = false;
} else {
isIpad = true;
}
export default class WalletXpub extends Component {
static navigationOptions = ({ navigation }) => ({
@ -41,6 +34,7 @@ export default class WalletXpub extends Component {
wallet,
xpub: wallet.getXpub(),
xpubText: wallet.getXpub(),
qrCodeHeight: height > width ? height / 2.5 : width / 2,
};
}
@ -55,13 +49,6 @@ export default class WalletXpub extends Component {
}, 1000);
}
determineSize = () => {
if (width > 312) {
return width - 48;
}
return 312;
};
copyToClipboard = () => {
this.setState({ xpubText: loc.wallets.xpub.copiedToClipboard }, () => {
Clipboard.setString(this.state.xpub);
@ -69,6 +56,11 @@ export default class WalletXpub extends Component {
});
};
onLayout = () => {
const { height } = Dimensions.get('window');
this.setState({ qrCodeHeight: height > width ? height / 2.5 : width / 2 });
};
render() {
if (this.state.isLoading) {
return (
@ -80,11 +72,11 @@ export default class WalletXpub extends Component {
return (
<SafeBlueArea style={{ flex: 1, paddingTop: 20 }}>
{isIpad && <BlueSpacing40 />}
<BlueCard style={{ alignItems: 'center', flex: 1 }}>
<View style={{ alignItems: 'center', flex: 1, justifyContent: 'center' }} onLayout={this.onLayout}>
<View>
<BlueText>{this.state.wallet.typeReadable}</BlueText>
</View>
<BlueSpacing20 />
{(() => {
if (this.state.showQr) {
@ -92,10 +84,10 @@ export default class WalletXpub extends Component {
return (
<QRSlow
content={this.state.xpub}
size={this.determineSize()}
color={BlueApp.settings.foregroundColor}
backgroundColor={BlueApp.settings.brandingColor}
logo={require('../../img/qr-code.png')}
size={this.state.qrCodeHeight}
ecl={'Q'}
/>
);
@ -103,9 +95,9 @@ export default class WalletXpub extends Component {
return (
<QRFast
value={this.state.xpub}
size={this.determineSize()}
fgColor={BlueApp.settings.brandingColor}
bgColor={BlueApp.settings.foregroundColor}
size={this.state.qrCodeHeight}
/>
);
}
@ -117,13 +109,13 @@ export default class WalletXpub extends Component {
);
}
})()}
<BlueSpacing20 />
<TouchableOpacity onPress={this.copyToClipboard}>
<Animated.Text style={{ marginVertical: 8, textAlign: 'center' }} numberOfLines={0}>
<Animated.Text style={{ paddingHorizontal: 8, textAlign: 'center' }} numberOfLines={0}>
{this.state.xpubText}
</Animated.Text>
</TouchableOpacity>
</BlueCard>
</View>
</SafeBlueArea>
);
}