diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d7c1b7241..4eb4ffac5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,3 +7,7 @@ Please include a summary of the changes and which issue is fixed / feature is ad # Pull Request - Checklist - [ ] Initial Manual Tests Passed +- [ ] Double check modified code and verify it with the feature/task requirements +- [ ] Formate code +- [ ] Look for code duplication +- [ ] Clear naming for variables and methods diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index f8496ffcd..53008ed52 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -5,7 +5,7 @@ on: branches: [ main ] jobs: - test: + PR_test_build: runs-on: ubuntu-20.04 env: @@ -111,9 +111,11 @@ jobs: echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart + echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart + echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart - name: Rename app - run: sed -i -e "s/\${APP_NAME}/$GITHUB_HEAD_REF/g" /opt/android/cake_wallet/android/app/src/main/AndroidManifest.xml + run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties - name: Build run: | diff --git a/README.md b/README.md index 36a3b6508..3077366ac 100644 --- a/README.md +++ b/README.md @@ -90,12 +90,12 @@ Edit the applicable `strings_XX.arb` file in `res/values/` and open a pull reque - French - German - Italian -- Portugese +- Portuguese - Dutch - Polish - Croatian - Russian -- Ukranian +- Ukrainian - Hindi - Japanese - Chinese @@ -105,6 +105,9 @@ Edit the applicable `strings_XX.arb` file in `res/values/` and open a pull reque - Turkish - Burmese - Urdu +- Bulgarian +- Czech +- Indonesian ## Add a new language diff --git a/Refund Pollicy.md b/Refund Pollicy.md deleted file mode 100644 index d2e13f5ef..000000000 --- a/Refund Pollicy.md +++ /dev/null @@ -1,27 +0,0 @@ -# Refund Policy - -This Refund Policy covers returns, refunds, and cancellations for your purchases from Cake Technologies, LLC (“Company,” “we,” or “us”). - -### Returns - -We do not accept returns of cryptocurrencies. Once cryptocurrencies are delivered to the provided wallet address, we cannot accept a return. If we allow you to sell cryptocurrencies to us, you may optionally engage in another trade to convert the cryptocurrency to another asset at the price at that point in time. - -### Refunds - -We do not issue refunds except in the case of an error resulting in a non-delivery of cryptocurrencies. In this case, we will decide whether to complete the trade or refund the account. We endeavor to complete an investigation to determine whether an error occurred and to make this decision within ten (10) days of receipt of your error report, and we will do so in any case within ninety (90) days. We reserve the right to issue a refund for the equivalent amount in another asset at the exchange rate then offered by us should we determine an error occurred. - -### Cancellations - -Once you make a payment to us, trades cannot be cancelled. In nearly all cases, we deliver cryptocurrency to your address in a matter of seconds or minutes. If you have not received your purchased cryptocurrency within six (6) hours of completing payment and have confirmed that your wallet is connected to a reliable node and fully synchronized with the network, please contact us. - -### Network Fees - -We may charge a network fee for the delivery of cryptocurrencies. This will be clearly shown in the checkout page. If we issue a refund, we may choose to deduct any network fees from the refund, including any network fees incurred in processing the refund. - -### Fraud - -If you believe a cryptocurrency purchase was conducted fraudulently, please alert your bank or card issuer, as applicable, and follow their instructions. Please be aware that fraudulent transactions may result in the loss of your money with no recourse. - -### Contact Us - -If you believe that there has been an error in processing your payment, please contact us at support@cakewallet.com. \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 04c2af566..692e8dfb1 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.5.10' + ext.kotlin_version = '1.6.21' repositories { google() jcenter() diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index b7ca2e6de..733c691d3 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/assets/images/trocador.png b/assets/images/trocador.png new file mode 100644 index 000000000..67c9f221c Binary files /dev/null and b/assets/images/trocador.png differ diff --git a/cw_core/lib/crypto_currency.dart b/cw_core/lib/crypto_currency.dart index 90051f1f7..925f39de0 100644 --- a/cw_core/lib/crypto_currency.dart +++ b/cw_core/lib/crypto_currency.dart @@ -94,7 +94,7 @@ class CryptoCurrency extends EnumerableItem with Serializable { static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png'); static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/images/eth_icon.png'); static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/images/litecoin-ltc_icon.png'); - static const nano = CryptoCurrency(title: 'NANO', raw: 10, name: 'nano'); + static const nano = CryptoCurrency(title: 'NANO', raw: 10, name: 'nano', iconPath: 'assets/images/nano.png'); static const trx = CryptoCurrency(title: 'TRX', fullName: 'TRON', raw: 11, name: 'trx', iconPath: 'assets/images/trx_icon.png'); static const usdt = CryptoCurrency(title: 'USDT', tag: 'OMNI', fullName: 'USDT Tether', raw: 12, name: 'usdt', iconPath: 'assets/images/usdt_icon.png'); static const usdterc20 = CryptoCurrency(title: 'USDT', tag: 'ETH', fullName: 'USDT Tether', raw: 13, name: 'usdterc20', iconPath: 'assets/images/usdterc20_icon.png'); @@ -117,7 +117,7 @@ class CryptoCurrency extends EnumerableItem with Serializable { static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd'); static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png'); - static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'C-CHAIN', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png'); + static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'AVAXC', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png'); static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png'); static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/bttbsc_icon.png'); static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png'); diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 50503361c..e33aeb803 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -13,6 +13,7 @@ dependencies: flutter: sdk: flutter http: ^0.13.4 + file: ^6.1.4 path_provider: ^2.0.11 mobx: ^2.0.7+4 flutter_mobx: ^2.0.6+1 diff --git a/cw_haven/pubspec.yaml b/cw_haven/pubspec.yaml index 28f2c315e..7a5ac6aa4 100644 --- a/cw_haven/pubspec.yaml +++ b/cw_haven/pubspec.yaml @@ -12,7 +12,7 @@ environment: dependencies: flutter: sdk: flutter - ffi: ^1.1.2 + ffi: ^2.0.1 http: ^0.13.4 path_provider: ^2.0.11 mobx: ^2.0.7+4 diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index 23e8782cb..6d5041dfa 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -12,7 +12,7 @@ environment: dependencies: flutter: sdk: flutter - ffi: ^1.1.2 + ffi: ^2.0.1 http: ^0.13.4 path_provider: ^2.0.11 mobx: ^2.0.7+4 diff --git a/lib/anypay/any_pay_payment.dart b/lib/anypay/any_pay_payment.dart index 37bf7949e..0657b0526 100644 --- a/lib/anypay/any_pay_payment.dart +++ b/lib/anypay/any_pay_payment.dart @@ -57,7 +57,7 @@ class AnyPayPayment { List get outAddresses { return instructions - .map((instuction) => instuction.outputs.map((out) => out.address)) + .map((instruction) => instruction.outputs.map((out) => out.address)) .expand((e) => e) .toList(); } diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index ffcb9eb4c..3cb434efe 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -217,7 +217,7 @@ class BackupService { final fiatApiMode = data[PreferencesKey.currentFiatApiModeKey] as int?; final currentPinLength = data[PreferencesKey.currentPinLength] as int?; final currentTheme = data[PreferencesKey.currentTheme] as int?; - final disableExchange = data[PreferencesKey.disableExchangeKey] as bool?; + final exchangeStatus = data[PreferencesKey.exchangeStatusKey] as int?; final currentDefaultSettingsMigrationVersion = data[PreferencesKey.currentDefaultSettingsMigrationVersion] as int?; final moneroTransactionPriority = data[PreferencesKey.moneroTransactionPriority] as int?; final bitcoinTransactionPriority = data[PreferencesKey.bitcoinTransactionPriority] as int?; @@ -280,9 +280,9 @@ class BackupService { await _sharedPreferences.setInt( PreferencesKey.currentTheme, currentTheme); - if (disableExchange != null) - await _sharedPreferences.setBool( - PreferencesKey.disableExchangeKey, disableExchange); + if (exchangeStatus != null) + await _sharedPreferences.setInt( + PreferencesKey.exchangeStatusKey, exchangeStatus); if (currentDefaultSettingsMigrationVersion != null) await _sharedPreferences.setInt( @@ -431,8 +431,8 @@ class BackupService { _sharedPreferences.getInt(PreferencesKey.displayActionListModeKey), PreferencesKey.currentTheme: _sharedPreferences.getInt(PreferencesKey.currentTheme), - PreferencesKey.disableExchangeKey: - _sharedPreferences.getBool(PreferencesKey.disableExchangeKey), + PreferencesKey.exchangeStatusKey: + _sharedPreferences.getInt(PreferencesKey.exchangeStatusKey), PreferencesKey.currentDefaultSettingsMigrationVersion: _sharedPreferences .getInt(PreferencesKey.currentDefaultSettingsMigrationVersion), PreferencesKey.bitcoinTransactionPriority: diff --git a/lib/core/fiat_conversion_service.dart b/lib/core/fiat_conversion_service.dart index f4ec3775b..66997675d 100644 --- a/lib/core/fiat_conversion_service.dart +++ b/lib/core/fiat_conversion_service.dart @@ -4,18 +4,31 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; -const fiatApiAuthority = 'fiat-api.cakewallet.com'; -const fiatApiPath = '/v1/rates'; +const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com'; +const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion'; +const _fiatApiPath = '/v2/rates'; Future _fetchPrice(Map args) async { final crypto = args['crypto'] as CryptoCurrency; final fiat = args['fiat'] as FiatCurrency; + final torOnly = args['torOnly'] as bool; + + final Map queryParams = { + 'interval_count': '1', + 'base': crypto.toString(), + 'quote': fiat.toString(), + }; + double price = 0.0; try { - final fiatStringified = fiat.toString(); - final uri = Uri.https(fiatApiAuthority, fiatApiPath, - {'convert': fiatStringified}); + late final Uri uri; + if (torOnly) { + uri = Uri.http(_fiatApiOnionAuthority, _fiatApiPath, queryParams); + } else { + uri = Uri.https(_fiatApiClearNetAuthority, _fiatApiPath, queryParams); + } + final response = await get(uri); if (response.statusCode != 200) { @@ -23,13 +36,10 @@ Future _fetchPrice(Map args) async { } final responseJSON = json.decode(response.body) as Map; - final data = responseJSON['data'] as List; + final results = responseJSON['results'] as Map; - for (final item in data) { - if (item['symbol'] == crypto.title) { - price = item['quote'][fiatStringified]['price'] as double; - break; - } + if (results.isNotEmpty) { + price = results.values.first as double; } return price; @@ -38,12 +48,14 @@ Future _fetchPrice(Map args) async { } } -Future _fetchPriceAsync( - CryptoCurrency crypto, FiatCurrency fiat) async => - compute(_fetchPrice, {'fiat': fiat, 'crypto': crypto}); +Future _fetchPriceAsync(CryptoCurrency crypto, FiatCurrency fiat, bool torOnly) async => + compute(_fetchPrice, {'fiat': fiat, 'crypto': crypto, 'torOnly': torOnly}); class FiatConversionService { - static Future fetchPrice( - CryptoCurrency crypto, FiatCurrency fiat) async => - await _fetchPriceAsync(crypto, fiat); + static Future fetchPrice({ + required CryptoCurrency crypto, + required FiatCurrency fiat, + required bool torOnly, + }) async => + await _fetchPriceAsync(crypto, fiat, torOnly); } diff --git a/lib/core/wallet_loading_service.dart b/lib/core/wallet_loading_service.dart index 5bae5b346..761c6acce 100644 --- a/lib/core/wallet_loading_service.dart +++ b/lib/core/wallet_loading_service.dart @@ -22,13 +22,13 @@ class WalletLoadingService { final wallet = await walletService.openWallet(name, password); if (type == WalletType.monero) { - await upateMoneroWalletPassword(wallet); + await updateMoneroWalletPassword(wallet); } return wallet; } - Future upateMoneroWalletPassword(WalletBase wallet) async { + Future updateMoneroWalletPassword(WalletBase wallet) async { final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name); var isPasswordUpdated = sharedPreferences.getBool(key) ?? false; @@ -37,8 +37,8 @@ class WalletLoadingService { } final password = generateWalletPassword(); - // Save new generated password with backup key for case - // if wallet will change password, but it will faild to updated in secure storage + // Save new generated password with backup key for case where + // wallet will change password, but it will fail to update in secure storage final bakWalletName = '#__${wallet.name}_bak__#'; await keyService.saveWalletPassword(walletName: bakWalletName, password: password); await wallet.changePassword(password); diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index 3c8d9fbbe..94fc7ede8 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -1,10 +1,12 @@ import 'dart:io' show File, Platform; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive/hive.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cw_core/wallet_type.dart'; @@ -142,7 +144,9 @@ Future defaultSettingsMigration( case 19: await validateBitcoinSavedTransactionPriority(sharedPreferences); break; - + case 20: + await migrateExchangeStatus(sharedPreferences); + break; default: break; } @@ -501,3 +505,15 @@ Future changeDefaultHavenNode( await node.save(); }); } + +Future migrateExchangeStatus(SharedPreferences sharedPreferences) async { + final isExchangeDisabled = sharedPreferences.getBool(PreferencesKey.disableExchangeKey); + if (isExchangeDisabled == null) { + return; + } + + await sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, isExchangeDisabled + ? ExchangeApiMode.disabled.raw : ExchangeApiMode.enabled.raw); + + await sharedPreferences.remove(PreferencesKey.disableExchangeKey); +} diff --git a/lib/entities/exchange_api_mode.dart b/lib/entities/exchange_api_mode.dart new file mode 100644 index 000000000..0b8b575a5 --- /dev/null +++ b/lib/entities/exchange_api_mode.dart @@ -0,0 +1,39 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cw_core/enumerable_item.dart'; + +class ExchangeApiMode extends EnumerableItem with Serializable { + const ExchangeApiMode({required String title, required int raw}) : super(title: title, raw: raw); + + static const all = [ExchangeApiMode.enabled, ExchangeApiMode.torOnly, ExchangeApiMode.disabled]; + + static const enabled = ExchangeApiMode(raw: 0, title: 'Enabled'); + static const torOnly = ExchangeApiMode(raw: 1, title: 'Tor only'); + static const disabled = ExchangeApiMode(raw: 2, title: 'Disabled'); + + static ExchangeApiMode deserialize({required int raw}) { + switch (raw) { + case 0: + return enabled; + case 1: + return torOnly; + case 2: + return disabled; + default: + throw Exception('Unexpected token: $raw for ExchangeApiMode deserialize'); + } + } + + @override + String toString() { + switch (this) { + case ExchangeApiMode.enabled: + return S.current.enabled; + case ExchangeApiMode.torOnly: + return S.current.tor_only; + case ExchangeApiMode.disabled: + return S.current.disabled; + default: + return ''; + } + } +} \ No newline at end of file diff --git a/lib/entities/language_service.dart b/lib/entities/language_service.dart index 547d26f45..968c3e843 100644 --- a/lib/entities/language_service.dart +++ b/lib/entities/language_service.dart @@ -23,7 +23,10 @@ class LanguageService { 'ar': 'العربية (Arabic)', 'tr': 'Türkçe (Turkish)', 'my': 'မြန်မာ (Burmese)', - 'ur': 'اردو (Urdu)' + 'bg': 'Български (Bulgarian)', + 'cs': 'čeština (Czech)', + 'ur': 'اردو (Urdu)', + 'id': 'Bahasa Indonesia (Indonesian)' }; static const Map localeCountryCode = { @@ -46,7 +49,10 @@ class LanguageService { 'ar': 'sau', 'tr': 'tur', 'my': 'mmr', - 'ur': 'pak' + 'bg': 'bgr', + 'cs': 'czk', + 'ur': 'pak', + 'id': 'idn' }; static final list = {}; diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index a44dcb3d9..e237b0691 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -13,6 +13,7 @@ class PreferencesKey { static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication'; static const disableExchangeKey = 'disable_exchange'; + static const exchangeStatusKey = 'exchange_status'; static const currentTheme = 'current_theme'; static const isDarkThemeLegacy = 'dark_theme'; static const displayActionListModeKey = 'display_list_mode'; diff --git a/lib/exchange/changenow/changenow_exchange_provider.dart b/lib/exchange/changenow/changenow_exchange_provider.dart index 3f18d43b1..e173dbdf6 100644 --- a/lib/exchange/changenow/changenow_exchange_provider.dart +++ b/lib/exchange/changenow/changenow_exchange_provider.dart @@ -269,6 +269,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { : currency.title.toLowerCase(); } } + } String normalizeCryptoCurrency(CryptoCurrency currency) { diff --git a/lib/exchange/exchange_provider.dart b/lib/exchange/exchange_provider.dart index 763350c94..cc81a21f6 100644 --- a/lib/exchange/exchange_provider.dart +++ b/lib/exchange/exchange_provider.dart @@ -14,6 +14,7 @@ abstract class ExchangeProvider { bool get isAvailable; bool get isEnabled; bool get supportsFixedRate; + bool get supportsOnionAddress => false; @override String toString() => title; diff --git a/lib/exchange/exchange_provider_description.dart b/lib/exchange/exchange_provider_description.dart index 2fd231085..e545f69ce 100644 --- a/lib/exchange/exchange_provider_description.dart +++ b/lib/exchange/exchange_provider_description.dart @@ -1,31 +1,30 @@ import 'package:cw_core/enumerable_item.dart'; -class ExchangeProviderDescription extends EnumerableItem - with Serializable { - const ExchangeProviderDescription({ - required String title, - required int raw, - required this.image, - this.horizontalLogo = false}) +class ExchangeProviderDescription extends EnumerableItem with Serializable { + const ExchangeProviderDescription( + {required String title, required int raw, required this.image, this.horizontalLogo = false}) : super(title: title, raw: raw); final bool horizontalLogo; final String image; - static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0, image: 'assets/images/xmrto.png'); + static const xmrto = + ExchangeProviderDescription(title: 'XMR.TO', raw: 0, image: 'assets/images/xmrto.png'); static const changeNow = ExchangeProviderDescription(title: 'ChangeNOW', raw: 1, image: 'assets/images/changenow.png'); static const morphToken = ExchangeProviderDescription(title: 'MorphToken', raw: 2, image: 'assets/images/morph.png'); - static const sideShift = + static const sideShift = ExchangeProviderDescription(title: 'SideShift', raw: 3, image: 'assets/images/sideshift.png'); - static const simpleSwap = - ExchangeProviderDescription(title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png'); + static const simpleSwap = ExchangeProviderDescription( + title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png'); - static const all = - ExchangeProviderDescription(title: 'All trades', raw: 5, image:''); + static const trocador = + ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png'); + + static const all = ExchangeProviderDescription(title: 'All trades', raw: 6, image: ''); static ExchangeProviderDescription deserialize({required int raw}) { switch (raw) { @@ -40,6 +39,8 @@ class ExchangeProviderDescription extends EnumerableItem case 4: return simpleSwap; case 5: + return trocador; + case 6: return all; default: throw Exception('Unexpected token: $raw for ExchangeProviderDescription deserialize'); diff --git a/lib/exchange/trade.dart b/lib/exchange/trade.dart index f20a080b7..70dfa5713 100644 --- a/lib/exchange/trade.dart +++ b/lib/exchange/trade.dart @@ -8,21 +8,25 @@ part 'trade.g.dart'; @HiveType(typeId: Trade.typeId) class Trade extends HiveObject { - Trade( - {required this.id, - required this.amount, - ExchangeProviderDescription? provider, - CryptoCurrency? from, - CryptoCurrency? to, - TradeState? state, - this.createdAt, - this.expiredAt, - this.inputAddress, - this.extraId, - this.outputTransaction, - this.refundAddress, - this.walletId, - this.payoutAddress}) { + Trade({ + required this.id, + required this.amount, + ExchangeProviderDescription? provider, + CryptoCurrency? from, + CryptoCurrency? to, + TradeState? state, + this.createdAt, + this.expiredAt, + this.inputAddress, + this.extraId, + this.outputTransaction, + this.refundAddress, + this.walletId, + this.payoutAddress, + this.password, + this.providerId, + this.providerName, + }) { if (provider != null) { providerRaw = provider.raw; } @@ -92,16 +96,23 @@ class Trade extends HiveObject { @HiveField(13) String? payoutAddress; + @HiveField(14) + String? password; + + @HiveField(15) + String? providerId; + + @HiveField(16) + String? providerName; + static Trade fromMap(Map map) { return Trade( id: map['id'] as String, - provider: ExchangeProviderDescription.deserialize( - raw: map['provider'] as int), + provider: ExchangeProviderDescription.deserialize(raw: map['provider'] as int), from: CryptoCurrency.deserialize(raw: map['input'] as int), to: CryptoCurrency.deserialize(raw: map['output'] as int), - createdAt: map['date'] != null - ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) - : null, + createdAt: + map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null, amount: map['amount'] as String, walletId: map['wallet_id'] as String); } diff --git a/lib/exchange/trocador/trocador_exchange_provider.dart b/lib/exchange/trocador/trocador_exchange_provider.dart new file mode 100644 index 000000000..98726a265 --- /dev/null +++ b/lib/exchange/trocador/trocador_exchange_provider.dart @@ -0,0 +1,312 @@ +import 'dart:convert'; + +import 'package:cake_wallet/exchange/exchange_pair.dart'; +import 'package:cake_wallet/exchange/exchange_provider.dart'; +import 'package:cake_wallet/exchange/trade_state.dart'; +import 'package:cake_wallet/exchange/trocador/trocador_request.dart'; +import 'package:cw_core/crypto_currency.dart'; +import 'package:cake_wallet/exchange/trade_request.dart'; +import 'package:cake_wallet/exchange/trade.dart'; +import 'package:cake_wallet/exchange/limits.dart'; +import 'package:cake_wallet/exchange/exchange_provider_description.dart'; +import 'package:cake_wallet/.secrets.g.dart' as secrets; +import 'package:http/http.dart'; + +class TrocadorExchangeProvider extends ExchangeProvider { + TrocadorExchangeProvider({this.useTorOnly = false}) + : _lastUsedRateId = '', + super(pairList: _supportedPairs()); + + bool useTorOnly; + + static const List _notSupported = [ + CryptoCurrency.scrt, + CryptoCurrency.stx, + CryptoCurrency.zaddr, + ]; + + static List _supportedPairs() { + final supportedCurrencies = + CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList(); + + return supportedCurrencies + .map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true))) + .expand((i) => i) + .toList(); + } + + static const onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion'; + static const clearNetAuthority = 'trocador.app'; + static const apiKey = secrets.trocadorApiKey; + static const markup = secrets.trocadorExchangeMarkup; + static const newRatePath = '/api/new_rate'; + static const createTradePath = 'api/new_trade'; + static const tradePath = 'api/trade'; + static const coinPath = 'api/coin'; + String _lastUsedRateId; + + @override + Future checkIsAvailable() async => true; + + @override + Future createTrade({required TradeRequest request, required bool isFixedRateMode}) { + final _request = request as TrocadorRequest; + return _createTrade(request: _request, isFixedRateMode: isFixedRateMode); + } + + Future _createTrade({ + required TrocadorRequest request, + required bool isFixedRateMode, + }) async { + final params = { + 'api_key': apiKey, + 'ticker_from': request.from.title.toLowerCase(), + 'ticker_to': request.to.title.toLowerCase(), + 'network_from': _networkFor(request.from), + 'network_to': _networkFor(request.to), + 'payment': isFixedRateMode ? 'True' : 'False', + 'min_kycrating': 'C', + 'markup': markup, + 'best_only': 'True', + if (!isFixedRateMode) 'amount_from': request.fromAmount, + if (isFixedRateMode) 'amount_to': request.toAmount, + 'address': request.address, + 'refund': request.refundAddress + }; + + if (isFixedRateMode) { + await fetchRate( + from: request.from, + to: request.to, + amount: double.tryParse(request.toAmount) ?? 0, + isFixedRateMode: true, + isReceiveAmount: true, + ); + params['id'] = _lastUsedRateId; + } + + final uri = await _getUri(createTradePath, params); + final response = await get(uri); + + if (response.statusCode == 400) { + final responseJSON = json.decode(response.body) as Map; + final error = responseJSON['error'] as String; + final message = responseJSON['message'] as String; + throw Exception('${error}\n$message'); + } + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final responseJSON = json.decode(response.body) as Map; + final id = responseJSON['trade_id'] as String; + final inputAddress = responseJSON['address_provider'] as String; + final refundAddress = responseJSON['refund_address'] as String; + final status = responseJSON['status'] as String; + final state = TradeState.deserialize(raw: status); + final payoutAddress = responseJSON['address_user'] as String; + final date = responseJSON['date'] as String; + final password = responseJSON['password'] as String; + final providerId = responseJSON['id_provider'] as String; + final providerName = responseJSON['provider'] as String; + + return Trade( + id: id, + from: request.from, + to: request.to, + provider: description, + inputAddress: inputAddress, + refundAddress: refundAddress, + state: state, + password: password, + providerId: providerId, + providerName: providerName, + createdAt: DateTime.tryParse(date)?.toLocal(), + amount: responseJSON['amount_from']?.toString() ?? request.fromAmount, + payoutAddress: payoutAddress); + } + + @override + ExchangeProviderDescription get description => ExchangeProviderDescription.trocador; + + @override + Future fetchLimits( + {required CryptoCurrency from, + required CryptoCurrency to, + required bool isFixedRateMode}) async { + final params = { + 'api_key': apiKey, + 'ticker': from.title.toLowerCase(), + 'name': from.name, + }; + + final uri = await _getUri(coinPath, params); + + final response = await get(uri); + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final responseJSON = json.decode(response.body) as List; + + if (responseJSON.isEmpty) { + throw Exception('No data'); + } + + final coinJson = responseJSON.first as Map; + + return Limits( + min: coinJson['minimum'] as double, + max: coinJson['maximum'] as double, + ); + } + + @override + Future fetchRate( + {required CryptoCurrency from, + required CryptoCurrency to, + required double amount, + required bool isFixedRateMode, + required bool isReceiveAmount}) async { + try { + if (amount == 0) { + return 0.0; + } + + final params = { + 'api_key': apiKey, + 'ticker_from': from.title.toLowerCase(), + 'ticker_to': to.title.toLowerCase(), + 'network_from': _networkFor(from), + 'network_to': _networkFor(to), + if (!isFixedRateMode) 'amount_from': amount.toString(), + if (isFixedRateMode) 'amount_to': amount.toString(), + 'payment': isFixedRateMode ? 'True' : 'False', + 'min_kycrating': 'C', + 'markup': markup, + 'best_only': 'True', + }; + + final uri = await _getUri(newRatePath, params); + final response = await get(uri); + final responseJSON = json.decode(response.body) as Map; + final fromAmount = double.parse(responseJSON['amount_from'].toString()); + final toAmount = double.parse(responseJSON['amount_to'].toString()); + final rateId = responseJSON['trade_id'] as String? ?? ''; + + if (rateId.isNotEmpty) { + _lastUsedRateId = rateId; + } + + return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount); + } catch (e) { + print(e.toString()); + return 0.0; + } + } + + @override + Future findTradeById({required String id}) async { + final uri = await _getUri(tradePath, {'api_key': apiKey, 'id': id}); + return get(uri).then((response) { + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final responseListJson = json.decode(response.body) as List; + + final responseJSON = responseListJson.first; + final id = responseJSON['trade_id'] as String; + final inputAddress = responseJSON['address_user'] as String; + final refundAddress = responseJSON['refund_address'] as String; + final payoutAddress = responseJSON['address_provider'] as String; + final fromAmount = responseJSON['amount_from']?.toString() ?? '0'; + final from = CryptoCurrency.fromString(responseJSON['ticker_from'] as String); + final to = CryptoCurrency.fromString(responseJSON['ticker_to'] as String); + final state = TradeState.deserialize(raw: responseJSON['status'] as String); + final date = DateTime.parse(responseJSON['date'] as String); + final password = responseJSON['password'] as String; + final providerId = responseJSON['id_provider'] as String; + final providerName = responseJSON['provider'] as String; + + return Trade( + id: id, + from: from, + to: to, + provider: description, + inputAddress: inputAddress, + refundAddress: refundAddress, + createdAt: date, + amount: fromAmount, + state: state, + payoutAddress: payoutAddress, + password: password, + providerId: providerId, + providerName: providerName, + ); + }); + } + + @override + bool get isAvailable => true; + + @override + bool get isEnabled => true; + + @override + bool get supportsFixedRate => true; + + @override + bool get supportsOnionAddress => true; + + @override + String get title => 'Trocador'; + + String _networkFor(CryptoCurrency currency) { + switch (currency) { + case CryptoCurrency.eth: + return 'ERC20'; + case CryptoCurrency.maticpoly: + return 'Mainnet'; + case CryptoCurrency.usdcpoly: + return 'MATIC'; + case CryptoCurrency.zec: + return 'Mainnet'; + default: + return currency.tag != null ? _normalizeTag(currency.tag!) : 'Mainnet'; + } + } + + String _normalizeTag(String tag) { + switch (tag) { + case 'ETH': + return 'ERC20'; + case 'TRX': + return 'TRC20'; + default: + return tag.toLowerCase(); + } + } + + Future _getUri(String path, Map queryParams) async { + if (!supportsOnionAddress) { + return Uri.https(clearNetAuthority, path, queryParams); + } + + final uri = Uri.http(onionApiAuthority, path, queryParams); + + if (useTorOnly) { + return uri; + } + + try { + await get(uri); + + return uri; + } catch (e) { + return Uri.https(clearNetAuthority, path, queryParams); + } + } +} diff --git a/lib/exchange/trocador/trocador_request.dart b/lib/exchange/trocador/trocador_request.dart new file mode 100644 index 000000000..fbb8fdc84 --- /dev/null +++ b/lib/exchange/trocador/trocador_request.dart @@ -0,0 +1,21 @@ +import 'package:cake_wallet/exchange/trade_request.dart'; +import 'package:cw_core/crypto_currency.dart'; + +class TrocadorRequest extends TradeRequest { + TrocadorRequest( + {required this.from, + required this.to, + required this.address, + required this.fromAmount, + required this.toAmount, + required this.refundAddress, + required this.isReverse}); + + CryptoCurrency from; + CryptoCurrency to; + String address; + String fromAmount; + String toAmount; + String refundAddress; + bool isReverse; +} diff --git a/lib/reactions/bootstrap.dart b/lib/reactions/bootstrap.dart index 4b65ed9d2..6451c92c5 100644 --- a/lib/reactions/bootstrap.dart +++ b/lib/reactions/bootstrap.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:cake_wallet/reactions/fiat_rate_update.dart'; +import 'package:cake_wallet/reactions/on_current_fiat_api_mode_change.dart'; import 'package:cake_wallet/reactions/on_current_node_change.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/widgets.dart'; @@ -31,6 +32,7 @@ Future bootstrap(GlobalKey navigatorKey) async { startCurrentWalletChangeReaction( appStore, settingsStore, fiatConversionStore); startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore); + startCurrentFiatApiModeChangeReaction(appStore, settingsStore, fiatConversionStore); startOnCurrentNodeChangeReaction(appStore); startFiatRateUpdate(appStore, settingsStore, fiatConversionStore); } diff --git a/lib/reactions/fiat_rate_update.dart b/lib/reactions/fiat_rate_update.dart index 48c61d8ca..f9ddbef52 100644 --- a/lib/reactions/fiat_rate_update.dart +++ b/lib/reactions/fiat_rate_update.dart @@ -26,7 +26,9 @@ Future startFiatRateUpdate( } else { fiatConversionStore.prices[appStore.wallet!.currency] = await FiatConversionService.fetchPrice( - appStore.wallet!.currency, settingsStore.fiatCurrency); + crypto: appStore.wallet!.currency, + fiat: settingsStore.fiatCurrency, + torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly); } } catch (e) { print(e); diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index edadf33b0..7521170e6 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:flutter/widgets.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/entities/load_current_wallet.dart'; @@ -16,8 +17,9 @@ void startAuthenticationStateChange(AuthenticationStore authenticationStore, if (state == AuthenticationState.installed) { try { await loadCurrentWallet(); - } catch (e) { - loginError = e; + } catch (error, stack) { + loginError = error; + ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); } return; } diff --git a/lib/reactions/on_current_fiat_api_mode_change.dart b/lib/reactions/on_current_fiat_api_mode_change.dart new file mode 100644 index 000000000..5bcaeef4c --- /dev/null +++ b/lib/reactions/on_current_fiat_api_mode_change.dart @@ -0,0 +1,25 @@ +import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:mobx/mobx.dart'; +import 'package:cake_wallet/core/fiat_conversion_service.dart'; +import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; +import 'package:cake_wallet/store/settings_store.dart'; +import 'package:cake_wallet/store/app_store.dart'; + +ReactionDisposer? _onCurrentFiatCurrencyChangeDisposer; + +void startCurrentFiatApiModeChangeReaction(AppStore appStore, + SettingsStore settingsStore, FiatConversionStore fiatConversionStore) { + _onCurrentFiatCurrencyChangeDisposer?.reaction.dispose(); + _onCurrentFiatCurrencyChangeDisposer = reaction( + (_) => settingsStore.fiatApiMode, (FiatApiMode fiatApiMode) async { + if (appStore.wallet == null || fiatApiMode == FiatApiMode.disabled) { + return; + } + + fiatConversionStore.prices[appStore.wallet!.currency] = + await FiatConversionService.fetchPrice( + crypto: appStore.wallet!.currency, + fiat: settingsStore.fiatCurrency, + torOnly: fiatApiMode == FiatApiMode.torOnly); + }); +} diff --git a/lib/reactions/on_current_fiat_change.dart b/lib/reactions/on_current_fiat_change.dart index 5170c4576..873984940 100644 --- a/lib/reactions/on_current_fiat_change.dart +++ b/lib/reactions/on_current_fiat_change.dart @@ -18,7 +18,10 @@ void startCurrentFiatChangeReaction(AppStore appStore, } final cryptoCurrency = appStore.wallet!.currency; - fiatConversionStore.prices[appStore.wallet!.currency] = - await FiatConversionService.fetchPrice(cryptoCurrency, fiatCurrency); + fiatConversionStore.prices[cryptoCurrency] = + await FiatConversionService.fetchPrice( + crypto: cryptoCurrency, + fiat: fiatCurrency, + torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly); }); } diff --git a/lib/reactions/on_current_wallet_change.dart b/lib/reactions/on_current_wallet_change.dart index e44973c5f..7fdb6b84f 100644 --- a/lib/reactions/on_current_wallet_change.dart +++ b/lib/reactions/on_current_wallet_change.dart @@ -69,8 +69,8 @@ void startCurrentWalletChangeReaction(AppStore appStore, if (wallet.type == WalletType.haven) { await updateHavenRate(fiatConversionStore); } - - if (wallet.walletInfo.address?.isEmpty ?? true) { + + if (wallet.walletInfo.address.isEmpty) { wallet.walletInfo.address = wallet.walletAddresses.address; if (wallet.walletInfo.isInBox) { @@ -94,7 +94,9 @@ void startCurrentWalletChangeReaction(AppStore appStore, fiatConversionStore.prices[wallet.currency] = 0; fiatConversionStore.prices[wallet.currency] = await FiatConversionService.fetchPrice( - wallet.currency, settingsStore.fiatCurrency); + crypto: wallet.currency, + fiat: settingsStore.fiatCurrency, + torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly); } catch (e) { print(e.toString()); } diff --git a/lib/src/screens/backup/backup_page.dart b/lib/src/screens/backup/backup_page.dart index a055066c0..f819e88e5 100644 --- a/lib/src/screens/backup/backup_page.dart +++ b/lib/src/screens/backup/backup_page.dart @@ -1,10 +1,9 @@ import 'dart:io'; import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/utils/share_util.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:share_plus/share_plus.dart'; -import 'package:cross_file/cross_file.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -110,7 +109,7 @@ class BackupPage extends BasePage { if (Platform.isAndroid) { onExportAndroid(context, backup); } else { - await share(backup); + await share(backup, context); } }, actionLeftButton: () => Navigator.of(dialogContext).pop()); @@ -140,18 +139,14 @@ class BackupPage extends BasePage { }, actionLeftButton: () async { Navigator.of(dialogContext).pop(); - await share(backup); + await share(backup, context); }); }); } - Future share(BackupExportFile backup) async { - const mimeType = 'application/*'; + Future share(BackupExportFile backup, BuildContext context) async { final path = await backupViewModelBase.saveBackupFileLocally(backup); - await Share.shareXFiles([XFile( - path, - name: backup.name, - mimeType: mimeType)]); + await ShareUtil.shareFile(filePath: path, fileName: backup.name, context: context); await backupViewModelBase.removeBackupFileLocally(backup); } } diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index c21365aa4..699e887ac 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -8,7 +8,6 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/cupertino.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart'; @@ -229,7 +228,8 @@ class DashboardPage extends BasePage { } await Future.delayed(Duration(seconds: 1)); - await showPopUp( + if (context.mounted) { + await showPopUp( context: context, builder: (BuildContext context) { return AlertWithOneAction( @@ -239,6 +239,7 @@ class DashboardPage extends BasePage { buttonText: S.of(context).understand, buttonAction: () => Navigator.of(context).pop()); }); + } }); var needToPresentYat = false; diff --git a/lib/src/screens/dashboard/widgets/address_page.dart b/lib/src/screens/dashboard/widgets/address_page.dart index 9a9a2c070..a09eb2ba8 100644 --- a/lib/src/screens/dashboard/widgets/address_page.dart +++ b/lib/src/screens/dashboard/widgets/address_page.dart @@ -117,7 +117,8 @@ class AddressPage extends BasePage { } await Future.delayed(Duration(seconds: 1)); - await showPopUp( + if (context.mounted) { + await showPopUp( context: context, builder: (BuildContext context) { return AlertWithTwoActions( @@ -131,6 +132,7 @@ class AddressPage extends BasePage { Navigator.of(context).pop(); }); }); + } }); return KeyboardActions( diff --git a/lib/src/screens/dashboard/widgets/trade_row.dart b/lib/src/screens/dashboard/widgets/trade_row.dart index 21952140e..3b613b0e2 100644 --- a/lib/src/screens/dashboard/widgets/trade_row.dart +++ b/lib/src/screens/dashboard/widgets/trade_row.dart @@ -9,7 +9,8 @@ class TradeRow extends StatelessWidget { required this.to, required this.createdAtFormattedDate, this.onTap, - this.formattedAmount,}); + this.formattedAmount, + }); final VoidCallback? onTap; final ExchangeProviderDescription provider; @@ -35,47 +36,40 @@ class TradeRow extends StatelessWidget { SizedBox(width: 12), Expanded( child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('${from.toString()} → ${to.toString()}', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor! - )), - formattedAmount != null - ? Text(formattedAmount! + ' ' + amountCrypto, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor! - )) - : Container() - ]), - SizedBox(height: 5), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (createdAtFormattedDate != null) - Text(createdAtFormattedDate!, - style: TextStyle( - fontSize: 14, - color: Theme.of(context).textTheme! - .overline!.backgroundColor!)) - ]) - ], - ) - ) + mainAxisSize: MainAxisSize.min, + children: [ + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + Text('${from.toString()} → ${to.toString()}', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)), + formattedAmount != null + ? Text(formattedAmount! + ' ' + amountCrypto, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: + Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)) + : Container() + ]), + SizedBox(height: 5), + Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + if (createdAtFormattedDate != null) + Text(createdAtFormattedDate!, + style: TextStyle( + fontSize: 14, + color: Theme.of(context).textTheme!.overline!.backgroundColor!)) + ]) + ], + )) ], ), )); } - Image? _getPoweredImage(ExchangeProviderDescription provider) { - Image? image; + Widget? _getPoweredImage(ExchangeProviderDescription provider) { + Widget? image; switch (provider) { case ExchangeProviderDescription.xmrto: @@ -93,10 +87,15 @@ class TradeRow extends StatelessWidget { case ExchangeProviderDescription.simpleSwap: image = Image.asset('assets/images/simpleSwap.png', width: 36, height: 36); break; + case ExchangeProviderDescription.trocador: + image = ClipRRect( + borderRadius: BorderRadius.circular(50), + child: Image.asset('assets/images/trocador.png', width: 36, height: 36)); + break; default: image = null; } return image; } -} \ No newline at end of file +} diff --git a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart index 6c2f996df..05ff65889 100644 --- a/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart +++ b/lib/src/screens/new_wallet/advanced_privacy_settings_page.dart @@ -1,7 +1,11 @@ +import 'package:cake_wallet/entities/exchange_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/choices_list_item.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -48,29 +52,47 @@ class _AdvancedPrivacySettingsBodyState extends State Observer( - builder: (_) => SettingsSwitcherCell( - title: item.title, - value: item.value(), - onValueChange: item.onValueChange, + Observer(builder: (_) { + return SettingsChoicesCell( + ChoicesListItem( + title: S.current.disable_fiat, + items: FiatApiMode.all, + selectedItem: widget.privacySettingsViewModel.fiatApiMode, + onItemSelected: (FiatApiMode mode) => + widget.privacySettingsViewModel.setFiatApiMode(mode), ), - ), - ), - Observer( - builder: (_) { - if (widget.privacySettingsViewModel.addCustomNode) { - return Padding( - padding: EdgeInsets.only(left: 24, right: 24, top: 24), - child: NodeForm( - formKey: _formKey, - nodeViewModel: widget.nodeViewModel, - ), - ); - } - return const SizedBox(); - }, - ), + ); + }), + Observer(builder: (_) { + return SettingsChoicesCell( + ChoicesListItem( + title: S.current.exchange, + items: ExchangeApiMode.all, + selectedItem: widget.privacySettingsViewModel.exchangeStatus, + onItemSelected: (ExchangeApiMode mode) => + widget.privacySettingsViewModel.setExchangeApiMode(mode), + ), + ); + }), + Observer(builder: (_) { + return Column( + children: [ + SettingsSwitcherCell( + title: S.current.add_custom_node, + value: widget.privacySettingsViewModel.addCustomNode, + onValueChange: (_, __) => widget.privacySettingsViewModel.toggleAddCustomNode(), + ), + if (widget.privacySettingsViewModel.addCustomNode) + Padding( + padding: EdgeInsets.only(left: 24, right: 24, top: 24), + child: NodeForm( + formKey: _formKey, + nodeViewModel: widget.nodeViewModel, + ), + ) + ], + ); + }), ], ), bottomSectionPadding: EdgeInsets.all(24), diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 33e199487..881536944 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -379,7 +379,8 @@ class SendPage extends BasePage { if (state is ExecutedSuccessfullyState) { WidgetsBinding.instance.addPostFrameCallback((_) { - showPopUp( + if (context.mounted) { + showPopUp( context: context, builder: (BuildContext context) { return ConfirmSendingAlert( @@ -423,6 +424,7 @@ class SendPage extends BasePage { }, actionLeftButton: () => Navigator.of(context).pop()); }); + } }); } diff --git a/lib/src/screens/settings/privacy_page.dart b/lib/src/screens/settings/privacy_page.dart index 2f15cc225..b11b41199 100644 --- a/lib/src/screens/settings/privacy_page.dart +++ b/lib/src/screens/settings/privacy_page.dart @@ -1,6 +1,10 @@ +import 'package:cake_wallet/entities/exchange_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; +import 'package:cake_wallet/view_model/settings/choices_list_item.dart'; import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -18,29 +22,34 @@ class PrivacyPage extends BasePage { return Container( padding: EdgeInsets.only(top: 10), child: Observer(builder: (_) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - SettingsSwitcherCell( - title: S.current.disable_fiat, - value: _privacySettingsViewModel.isFiatDisabled, - onValueChange: (BuildContext context, bool value) { - _privacySettingsViewModel.setFiatMode(value); + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SettingsChoicesCell( + ChoicesListItem( + title: S.current.fiat_api, + items: FiatApiMode.all, + selectedItem: _privacySettingsViewModel.fiatApiMode, + onItemSelected: (FiatApiMode fiatApiMode) => + _privacySettingsViewModel.setFiatMode(fiatApiMode), + ), + ), + SettingsChoicesCell( + ChoicesListItem( + title: S.current.exchange, + items: ExchangeApiMode.all, + selectedItem: _privacySettingsViewModel.exchangeStatus, + onItemSelected: (ExchangeApiMode mode) => _privacySettingsViewModel.setExchangeApiMode(mode), + ), + ), + SettingsSwitcherCell( + title: S.current.settings_save_recipient_address, + value: _privacySettingsViewModel.shouldSaveRecipientAddress, + onValueChange: (BuildContext _, bool value) { + _privacySettingsViewModel.setShouldSaveRecipientAddress(value); }), - SettingsSwitcherCell( - title: S.current.disable_exchange, - value: _privacySettingsViewModel.disableExchange, - onValueChange: (BuildContext context, bool value) { - _privacySettingsViewModel.setEnableExchange(value); - }), - SettingsSwitcherCell( - title: S.current.settings_save_recipient_address, - value: _privacySettingsViewModel.shouldSaveRecipientAddress, - onValueChange: (BuildContext _, bool value) { - _privacySettingsViewModel.setShouldSaveRecipientAddress(value); - }) - ], - ); + ], + ); }), ); } diff --git a/lib/src/screens/settings/widgets/settings_link_provider_cell.dart b/lib/src/screens/settings/widgets/settings_link_provider_cell.dart index 51fcc16d5..e64d6543b 100644 --- a/lib/src/screens/settings/widgets/settings_link_provider_cell.dart +++ b/lib/src/screens/settings/widgets/settings_link_provider_cell.dart @@ -30,6 +30,8 @@ class SettingsLinkProviderCell extends StandardListRow { color: Palette.blueCraiola)); static void _launchUrl(String url) async { - if (await canLaunch(url)) await launch(url, forceSafariVC: false); + try { + await launch(url, forceSafariVC: false); + } catch (e) {} } -} \ No newline at end of file +} diff --git a/lib/src/widgets/check_box_picker.dart b/lib/src/widgets/check_box_picker.dart index e2f817fc4..80461e26d 100644 --- a/lib/src/widgets/check_box_picker.dart +++ b/lib/src/widgets/check_box_picker.dart @@ -38,7 +38,7 @@ class CheckBoxPickerState extends State { Column( mainAxisSize: MainAxisSize.min, children: [ - if (widget.title?.isNotEmpty ?? false) + if (widget.title.isNotEmpty) Container( padding: EdgeInsets.symmetric(horizontal: 24), child: Text( @@ -58,7 +58,7 @@ class CheckBoxPickerState extends State { child: ClipRRect( borderRadius: BorderRadius.all(Radius.circular(30)), child: Container( - color: Theme.of(context).accentTextTheme!.headline6!.color!, + color: Theme.of(context).accentTextTheme.headline6!.color!, child: ConstrainedBox( constraints: BoxConstraints( maxHeight: MediaQuery.of(context).size.height * 0.65, @@ -70,7 +70,7 @@ class CheckBoxPickerState extends State { child: Stack( alignment: Alignment.center, children: [ - (items?.length ?? 0) > 3 + (items.length) > 3 ? Scrollbar( controller: controller, child: itemsList(), @@ -95,14 +95,14 @@ class CheckBoxPickerState extends State { Widget itemsList() { return Container( - color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!, + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, child: ListView.separated( padding: EdgeInsets.zero, controller: controller, shrinkWrap: true, separatorBuilder: (context, index) => widget.isSeparated ? Divider( - color: Theme.of(context).accentTextTheme!.headline6!.backgroundColor!, + color: Theme.of(context).accentTextTheme.headline6!.backgroundColor!, height: 1, ) : const SizedBox(), @@ -121,13 +121,13 @@ class CheckBoxPickerState extends State { }, child: Container( height: 55, - color: Theme.of(context).accentTextTheme!.headline6!.color!, + color: Theme.of(context).accentTextTheme.headline6!.color!, padding: EdgeInsets.only(left: 24, right: 24), child: CheckboxListTile( value: item.value, activeColor: item.value ? Palette.blueCraiola - : Theme.of(context).accentTextTheme!.subtitle1!.decorationColor!, + : Theme.of(context).accentTextTheme.subtitle1!.decorationColor!, checkColor: Colors.white, title: widget.displayItem?.call(item) ?? Text( @@ -138,7 +138,7 @@ class CheckBoxPickerState extends State { fontWeight: FontWeight.w600, color: item.isDisabled ? Colors.grey.withOpacity(0.5) - : Theme.of(context).primaryTextTheme!.headline6!.color!, + : Theme.of(context).primaryTextTheme.headline6!.color!, decoration: TextDecoration.none, ), ), diff --git a/lib/store/dashboard/trade_filter_store.dart b/lib/store/dashboard/trade_filter_store.dart index 87fa749a9..c772a35d6 100644 --- a/lib/store/dashboard/trade_filter_store.dart +++ b/lib/store/dashboard/trade_filter_store.dart @@ -12,7 +12,8 @@ abstract class TradeFilterStoreBase with Store { displayChangeNow = true, displaySideShift = true, displayMorphToken = true, - displaySimpleSwap = true; + displaySimpleSwap = true, + displayTrocador = true; @observable bool displayXMRTO; @@ -29,8 +30,11 @@ abstract class TradeFilterStoreBase with Store { @observable bool displaySimpleSwap; + @observable + bool displayTrocador; + @computed - bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap; + bool get displayAllTrades => displayChangeNow && displaySideShift && displaySimpleSwap && displayTrocador; @action void toggleDisplayExchange(ExchangeProviderDescription provider) { @@ -50,6 +54,9 @@ abstract class TradeFilterStoreBase with Store { case ExchangeProviderDescription.morphToken: displayMorphToken = !displayMorphToken; break; + case ExchangeProviderDescription.trocador: + displayTrocador = !displayTrocador; + break; case ExchangeProviderDescription.all: if (displayAllTrades) { displayChangeNow = false; @@ -57,12 +64,14 @@ abstract class TradeFilterStoreBase with Store { displayXMRTO = false; displayMorphToken = false; displaySimpleSwap = false; + displayTrocador = false; } else { displayChangeNow = true; displaySideShift = true; displayXMRTO = true; displayMorphToken = true; displaySimpleSwap = true; + displayTrocador = true; } break; } @@ -88,7 +97,8 @@ abstract class TradeFilterStoreBase with Store { ExchangeProviderDescription.morphToken) ||(displaySimpleSwap && item.trade.provider == - ExchangeProviderDescription.simpleSwap)) + ExchangeProviderDescription.simpleSwap) + ||(displayTrocador && item.trade.provider == ExchangeProviderDescription.trocador)) .toList() : _trades; } diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index b10e0d08d..b6e5a7549 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/pin_code_required_duration.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cw_core/transaction_priority.dart'; @@ -31,7 +32,7 @@ abstract class SettingsStoreBase with Store { required bool initialSaveRecipientAddress, required FiatApiMode initialFiatMode, required bool initialAllowBiometricalAuthentication, - required bool initialExchangeEnabled, + required ExchangeApiMode initialExchangeStatus, required ThemeBase initialTheme, required int initialPinLength, required String initialLanguageCode, @@ -53,7 +54,7 @@ abstract class SettingsStoreBase with Store { shouldSaveRecipientAddress = initialSaveRecipientAddress, fiatApiMode = initialFiatMode, allowBiometricalAuthentication = initialAllowBiometricalAuthentication, - disableExchange = initialExchangeEnabled, + exchangeStatus = initialExchangeStatus, currentTheme = initialTheme, pinCodeLength = initialPinLength, languageCode = initialLanguageCode, @@ -153,9 +154,9 @@ abstract class SettingsStoreBase with Store { PreferencesKey.currentBalanceDisplayModeKey, mode.serialize())); reaction( - (_) => disableExchange, - (bool disableExchange) => sharedPreferences.setBool( - PreferencesKey.disableExchangeKey, disableExchange)); + (_) => exchangeStatus, + (ExchangeApiMode mode) => sharedPreferences.setInt( + PreferencesKey.exchangeStatusKey, mode.serialize())); this .nodes @@ -192,7 +193,7 @@ abstract class SettingsStoreBase with Store { bool allowBiometricalAuthentication; @observable - bool disableExchange; + ExchangeApiMode exchangeStatus; @observable ThemeBase currentTheme; @@ -284,8 +285,9 @@ abstract class SettingsStoreBase with Store { final allowBiometricalAuthentication = sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? false; - final disableExchange = sharedPreferences - .getBool(PreferencesKey.disableExchangeKey) ?? false; + final exchangeStatus = ExchangeApiMode.deserialize( + raw: sharedPreferences + .getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) ? ThemeType.dark.index @@ -354,7 +356,7 @@ abstract class SettingsStoreBase with Store { initialSaveRecipientAddress: shouldSaveRecipientAddress, initialFiatMode: currentFiatApiMode, initialAllowBiometricalAuthentication: allowBiometricalAuthentication, - initialExchangeEnabled: disableExchange, + initialExchangeStatus: exchangeStatus, initialTheme: savedTheme, actionlistDisplayMode: actionListDisplayMode, initialPinLength: pinLength, @@ -400,7 +402,9 @@ abstract class SettingsStoreBase with Store { allowBiometricalAuthentication = sharedPreferences .getBool(PreferencesKey.allowBiometricalAuthenticationKey) ?? allowBiometricalAuthentication; - disableExchange = sharedPreferences.getBool(PreferencesKey.disableExchangeKey) ?? disableExchange; + exchangeStatus = ExchangeApiMode.deserialize( + raw: sharedPreferences + .getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); final legacyTheme = (sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy) ?? false) ? ThemeType.dark.index diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart index 4cbebdb5d..51a525394 100644 --- a/lib/utils/exception_handler.dart +++ b/lib/utils/exception_handler.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:io'; import 'package:cake_wallet/entities/preferences_key.dart'; @@ -6,9 +5,11 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mailer/flutter_mailer.dart'; +import 'package:package_info/package_info.dart'; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -31,7 +32,7 @@ class ExceptionHandler { ==========================================================\n\n'''; await file.writeAsString( - jsonEncode(exception) + separator, + "$exception $separator", mode: FileMode.append, ); } @@ -42,6 +43,8 @@ class ExceptionHandler { final file = File('${appDocDir.path}/error.txt'); + await _addDeviceInfo(file); + final MailOptions mailOptions = MailOptions( subject: 'Mobile App Issue', recipients: ['support@cakewallet.com'], @@ -121,13 +124,97 @@ class ExceptionHandler { _ignoredErrors.any((element) => error.contains(element)); static const List _ignoredErrors = const [ - "errno = 103", // SocketException: Software caused connection abort "errno = 9", // SocketException: Bad file descriptor - "errno = 32", // SocketException: Write failed (OS Error: Broken pipe) - "errno = 60", // SocketException: Operation timed out - "errno = 54", // SocketException: Connection reset by peer - "errno = 49", // SocketException: Can't assign requested address "errno = 28", // OS Error: No space left on device + "errno = 32", // SocketException: Write failed (OS Error: Broken pipe) + "errno = 49", // SocketException: Can't assign requested address + "errno = 54", // SocketException: Connection reset by peer + "errno = 57", // SocketException: Read failed (OS Error: Socket is not connected) + "errno = 60", // SocketException: Operation timed out + "errno = 103", // SocketException: Software caused connection abort + "errno = 104", // SocketException: Connection reset by peer + "errno = 110", // SocketException: Connection timed out "PERMISSION_NOT_GRANTED", ]; + + static Future _addDeviceInfo(File file) async { + final packageInfo = await PackageInfo.fromPlatform(); + final currentVersion = packageInfo.version; + + final deviceInfoPlugin = DeviceInfoPlugin(); + Map deviceInfo = {}; + + if (Platform.isAndroid) { + deviceInfo = _readAndroidBuildData(await deviceInfoPlugin.androidInfo); + deviceInfo["Platform"] = "Android"; + } else if (Platform.isIOS) { + deviceInfo = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo); + deviceInfo["Platform"] = "iOS"; + } else if (Platform.isLinux) { + deviceInfo = _readLinuxDeviceInfo(await deviceInfoPlugin.linuxInfo); + deviceInfo["Platform"] = "Linux"; + } else if (Platform.isMacOS) { + deviceInfo = _readMacOsDeviceInfo(await deviceInfoPlugin.macOsInfo); + deviceInfo["Platform"] = "MacOS"; + } else if (Platform.isWindows) { + deviceInfo = _readWindowsDeviceInfo(await deviceInfoPlugin.windowsInfo); + deviceInfo["Platform"] = "Windows"; + } + + await file.writeAsString( + "App Version: $currentVersion\n\nDevice Info $deviceInfo", + mode: FileMode.append, + ); + } + + static Map _readAndroidBuildData(AndroidDeviceInfo build) { + return { + 'brand': build.brand, + 'device': build.device, + 'manufacturer': build.manufacturer, + 'model': build.model, + 'product': build.product, + }; + } + + static Map _readIosDeviceInfo(IosDeviceInfo data) { + return { + 'systemName': data.systemName, + 'systemVersion': data.systemVersion, + 'model': data.model, + 'localizedModel': data.localizedModel, + }; + } + + static Map _readLinuxDeviceInfo(LinuxDeviceInfo data) { + return { + 'name': data.name, + 'version': data.version, + 'versionCodename': data.versionCodename, + 'versionId': data.versionId, + 'prettyName': data.prettyName, + 'buildId': data.buildId, + 'variant': data.variant, + 'variantId': data.variantId, + }; + } + + static Map _readMacOsDeviceInfo(MacOsDeviceInfo data) { + return { + 'arch': data.arch, + 'model': data.model, + 'kernelVersion': data.kernelVersion, + 'osRelease': data.osRelease, + }; + } + + static Map _readWindowsDeviceInfo(WindowsDeviceInfo data) { + return { + 'majorVersion': data.majorVersion, + 'minorVersion': data.minorVersion, + 'buildNumber': data.buildNumber, + 'productType': data.productType, + 'productName': data.productName, + }; + } } diff --git a/lib/utils/share_util.dart b/lib/utils/share_util.dart index 5b33399c7..518590fdd 100644 --- a/lib/utils/share_util.dart +++ b/lib/utils/share_util.dart @@ -1,13 +1,37 @@ import 'package:flutter/material.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:cross_file/cross_file.dart'; class ShareUtil { - static void share({required String text, required BuildContext context}) { - final box = context.findRenderObject() as RenderBox?; + static const _mimeType = 'application/*'; + static void share({required String text, required BuildContext context}) { Share.share( text, - sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, + sharePositionOrigin: _sharePosition(context), ); } -} \ No newline at end of file + + static Future shareFile({ + required String filePath, + required String fileName, + required BuildContext context, + }) async { + Share.shareXFiles( + [ + XFile( + filePath, + name: fileName, + mimeType: _mimeType, + ) + ], + sharePositionOrigin: _sharePosition(context), + ); + } + + static Rect? _sharePosition(BuildContext context) { + final box = context.findRenderObject() as RenderBox?; + + return box!.localToGlobal(Offset.zero) & box.size; + } +} diff --git a/lib/view_model/advanced_privacy_settings_view_model.dart b/lib/view_model/advanced_privacy_settings_view_model.dart index f800e3418..380937212 100644 --- a/lib/view_model/advanced_privacy_settings_view_model.dart +++ b/lib/view_model/advanced_privacy_settings_view_model.dart @@ -1,9 +1,8 @@ +import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/store/settings_store.dart'; -import 'package:cake_wallet/view_model/settings/switcher_list_item.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/generated/i18n.dart'; part 'advanced_privacy_settings_view_model.g.dart'; @@ -11,46 +10,30 @@ class AdvancedPrivacySettingsViewModel = AdvancedPrivacySettingsViewModelBase with _$AdvancedPrivacySettingsViewModel; abstract class AdvancedPrivacySettingsViewModelBase with Store { - AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore) - : _addCustomNode = false { - settings = [ - SwitcherListItem( - title: S.current.disable_fiat, - value: () => _settingsStore.fiatApiMode == FiatApiMode.disabled, - onValueChange: (_, bool value) => setFiatMode(value), - ), - SwitcherListItem( - title: S.current.disable_exchange, - value: () => _settingsStore.disableExchange, - onValueChange: (_, bool value) { - _settingsStore.disableExchange = value; - }, - ), - SwitcherListItem( - title: S.current.add_custom_node, - value: () => _addCustomNode, - onValueChange: (_, bool value) => _addCustomNode = value, - ), - ]; - } + AdvancedPrivacySettingsViewModelBase(this.type, this._settingsStore) : _addCustomNode = false; - late List settings; + @computed + ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus; + + @computed + FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode; @observable bool _addCustomNode = false; final WalletType type; + final SettingsStore _settingsStore; @computed bool get addCustomNode => _addCustomNode; @action - void setFiatMode(bool value) { - if (value) { - _settingsStore.fiatApiMode = FiatApiMode.disabled; - return; - } - _settingsStore.fiatApiMode = FiatApiMode.enabled; - } + void setFiatApiMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode; + + @action + void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value; + + @action + void toggleAddCustomNode() => _addCustomNode = !_addCustomNode; } diff --git a/lib/view_model/dashboard/dashboard_view_model.dart b/lib/view_model/dashboard/dashboard_view_model.dart index 12bd21058..d41e51411 100644 --- a/lib/view_model/dashboard/dashboard_view_model.dart +++ b/lib/view_model/dashboard/dashboard_view_model.dart @@ -1,3 +1,5 @@ +import 'package:cake_wallet/entities/exchange_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/balance.dart'; @@ -96,6 +98,11 @@ abstract class DashboardViewModelBase with Store { caption: ExchangeProviderDescription.simpleSwap.title, onChanged: () => tradeFilterStore .toggleDisplayExchange(ExchangeProviderDescription.simpleSwap)), + FilterItem( + value: () => tradeFilterStore.displayTrocador, + caption: ExchangeProviderDescription.trocador.title, + onChanged: () => tradeFilterStore + .toggleDisplayExchange(ExchangeProviderDescription.trocador)), ] }, subname = '', @@ -268,7 +275,7 @@ abstract class DashboardViewModelBase with Store { settingsStore.shouldShowYatPopup = shouldShow; @computed - bool get isEnabledExchangeAction => !settingsStore.disableExchange; + bool get isEnabledExchangeAction => settingsStore.exchangeStatus != ExchangeApiMode.disabled; @observable bool hasExchangeAction; diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index 541b74396..94c874979 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; +import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/exchange/changenow/changenow_exchange_provider.dart'; @@ -46,6 +47,9 @@ abstract class ExchangeTradeViewModelBase with Store { case ExchangeProviderDescription.simpleSwap: _provider = SimpleSwapExchangeProvider(); break; + case ExchangeProviderDescription.trocador: + _provider = TrocadorExchangeProvider(); + break; } _updateItems(); diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index d310e6278..2dd67cab7 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -2,11 +2,15 @@ import 'dart:async'; import 'dart:collection'; import 'dart:convert'; +import 'package:cake_wallet/entities/exchange_api_mode.dart'; +import 'package:cake_wallet/entities/fiat_api_mode.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart'; import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart'; +import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart'; +import 'package:cake_wallet/exchange/trocador/trocador_request.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/crypto_currency.dart'; @@ -53,6 +57,7 @@ abstract class ExchangeViewModelBase with Store { isDepositAddressEnabled = false, isReceiveAddressEnabled = false, isReceiveAmountEditable = false, + _useTorOnly = false, receiveCurrencies = [], depositCurrencies = [], limits = Limits(min: 0, max: 0), @@ -60,8 +65,10 @@ abstract class ExchangeViewModelBase with Store { limitsState = LimitsInitialState(), receiveCurrency = wallet.currency, depositCurrency = wallet.currency, - providerList = [ChangeNowExchangeProvider(), SideShiftExchangeProvider(), SimpleSwapExchangeProvider()], + providerList = [], selectedProviders = ObservableList() { + _useTorOnly = _settingsStore.exchangeStatus == ExchangeApiMode.torOnly; + _setProviders(); const excludeDepositCurrencies = [CryptoCurrency.btt, CryptoCurrency.nano]; const excludeReceiveCurrencies = [CryptoCurrency.xlm, CryptoCurrency.xrp, CryptoCurrency.bnb, CryptoCurrency.btt, CryptoCurrency.nano]; @@ -117,13 +124,20 @@ abstract class ExchangeViewModelBase with Store { _calculateBestRate(); }); } - + bool _useTorOnly; final WalletBase wallet; final Box trades; final ExchangeTemplateStore _exchangeTemplateStore; final TradesStore tradesStore; final SharedPreferences sharedPreferences; + List get _allProviders => [ + ChangeNowExchangeProvider(), + SideShiftExchangeProvider(), + SimpleSwapExchangeProvider(), + TrocadorExchangeProvider(useTorOnly: _useTorOnly), + ]; + @observable ExchangeProvider? provider; @@ -455,6 +469,18 @@ abstract class ExchangeViewModelBase with Store { amount = isFixedRateMode ? receiveAmount : depositAmount; } + if (provider is TrocadorExchangeProvider) { + request = TrocadorRequest( + from: depositCurrency, + to: receiveCurrency, + fromAmount: depositAmount.replaceAll(',', '.'), + toAmount: receiveAmount.replaceAll(',', '.'), + refundAddress: depositAddress, + address: receiveAddress, + isReverse: isFixedRateMode); + amount = isFixedRateMode ? receiveAmount : depositAmount; + } + amount = amount.replaceAll(',', '.'); if (limitsState is LimitsLoadedSuccessfully) { @@ -675,4 +701,12 @@ abstract class ExchangeViewModelBase with Store { break; } } + + void _setProviders(){ + if (_settingsStore.exchangeStatus == ExchangeApiMode.torOnly) { + providerList = _allProviders.where((provider) => provider.supportsOnionAddress).toList(); + } else { + providerList = _allProviders; + } + } } diff --git a/lib/view_model/settings/privacy_settings_view_model.dart b/lib/view_model/settings/privacy_settings_view_model.dart index f8c3e5b50..110afb07a 100644 --- a/lib/view_model/settings/privacy_settings_view_model.dart +++ b/lib/view_model/settings/privacy_settings_view_model.dart @@ -1,3 +1,4 @@ +import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; @@ -12,27 +13,21 @@ abstract class PrivacySettingsViewModelBase with Store { final SettingsStore _settingsStore; @computed - bool get disableExchange => _settingsStore.disableExchange; + ExchangeApiMode get exchangeStatus => _settingsStore.exchangeStatus; @computed bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; @computed - bool get isFiatDisabled => _settingsStore.fiatApiMode == FiatApiMode.disabled; + FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode; @action void setShouldSaveRecipientAddress(bool value) => _settingsStore.shouldSaveRecipientAddress = value; @action - void setEnableExchange(bool value) => _settingsStore.disableExchange = value; + void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value; @action - void setFiatMode(bool value) { - if (value) { - _settingsStore.fiatApiMode = FiatApiMode.disabled; - return; - } - _settingsStore.fiatApiMode = FiatApiMode.enabled; - } + void setFiatMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode; } diff --git a/lib/view_model/support_view_model.dart b/lib/view_model/support_view_model.dart index 3b919e750..15c25968f 100644 --- a/lib/view_model/support_view_model.dart +++ b/lib/view_model/support_view_model.dart @@ -7,7 +7,6 @@ import 'package:flutter/material.dart'; import 'package:mobx/mobx.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; -import 'package:cake_wallet/wallet_type_utils.dart'; part 'support_view_model.g.dart'; @@ -19,7 +18,9 @@ abstract class SupportViewModelBase with Store { RegularListItem( title: S.current.faq, handler: (BuildContext context) async { - if (await canLaunch(url)) await launch(url); + try { + await launch(url); + } catch (e) {} }, ), LinkListItem( diff --git a/lib/view_model/trade_details_view_model.dart b/lib/view_model/trade_details_view_model.dart index 5a1f78774..3a6f1ec74 100644 --- a/lib/view_model/trade_details_view_model.dart +++ b/lib/view_model/trade_details_view_model.dart @@ -6,6 +6,7 @@ import 'package:cake_wallet/exchange/morphtoken/morphtoken_exchange_provider.dar import 'package:cake_wallet/exchange/sideshift/sideshift_exchange_provider.dart'; import 'package:cake_wallet/exchange/simpleswap/simpleswap_exchange_provider.dart'; import 'package:cake_wallet/exchange/trade.dart'; +import 'package:cake_wallet/exchange/trocador/trocador_exchange_provider.dart'; import 'package:cake_wallet/exchange/xmrto/xmrto_exchange_provider.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; @@ -22,16 +23,15 @@ import 'package:cake_wallet/src/screens/trade_details/trade_details_status_item. import 'package:url_launcher/url_launcher.dart'; part 'trade_details_view_model.g.dart'; -class TradeDetailsViewModel = TradeDetailsViewModelBase - with _$TradeDetailsViewModel; +class TradeDetailsViewModel = TradeDetailsViewModelBase with _$TradeDetailsViewModel; abstract class TradeDetailsViewModelBase with Store { TradeDetailsViewModelBase({ required Trade tradeForDetails, required this.trades, - required this.settingsStore}) - : items = ObservableList(), - trade = tradeForDetails { + required this.settingsStore, + }) : items = ObservableList(), + trade = tradeForDetails { switch (trade.provider) { case ExchangeProviderDescription.xmrto: _provider = XMRTOExchangeProvider(); @@ -45,9 +45,12 @@ abstract class TradeDetailsViewModelBase with Store { case ExchangeProviderDescription.sideShift: _provider = SideShiftExchangeProvider(); break; - case ExchangeProviderDescription.simpleSwap: + case ExchangeProviderDescription.simpleSwap: _provider = SimpleSwapExchangeProvider(); break; + case ExchangeProviderDescription.trocador: + _provider = TrocadorExchangeProvider(); + break; } items = ObservableList(); @@ -96,12 +99,7 @@ abstract class TradeDetailsViewModelBase with Store { items.clear(); items.add( - DetailsListStatusItem( - title: S.current.trade_details_state, - value: trade.state != null - ? trade.state.toString() - : S.current.trade_details_fetching) - ); + DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString())); items.add(TradeDetailsListCardItem.tradeDetails( id: trade.id, @@ -114,15 +112,11 @@ abstract class TradeDetailsViewModelBase with Store { }, )); - if (trade.provider != null) { - items.add(StandartListItem( - title: S.current.trade_details_provider, - value: trade.provider.toString())); - } + items.add(StandartListItem( + title: S.current.trade_details_provider, value: trade.provider.toString())); if (trade.provider == ExchangeProviderDescription.changeNow) { - final buildURL = - 'https://changenow.io/exchange/txs/${trade.id.toString()}'; + final buildURL = 'https://changenow.io/exchange/txs/${trade.id.toString()}'; items.add(TrackTradeListItem( title: 'Track', value: buildURL, @@ -133,14 +127,25 @@ abstract class TradeDetailsViewModelBase with Store { if (trade.provider == ExchangeProviderDescription.sideShift) { final buildURL = 'https://sideshift.ai/orders/${trade.id.toString()}'; - items.add(TrackTradeListItem( - title: 'Track', value: buildURL, onTap: () => launch(buildURL))); + items.add(TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => launch(buildURL))); } if (trade.provider == ExchangeProviderDescription.simpleSwap) { final buildURL = 'https://simpleswap.io/exchange?id=${trade.id.toString()}'; - items.add(TrackTradeListItem( - title: 'Track', value: buildURL, onTap: () => launch(buildURL))); + items.add(TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => launch(buildURL))); + } + + if (trade.provider == ExchangeProviderDescription.trocador) { + final buildURL = 'https://trocador.app/en/checkout/${trade.id.toString()}'; + items.add(TrackTradeListItem(title: 'Track', value: buildURL, onTap: () => launch(buildURL))); + + items.add(StandartListItem( + title: '${trade.providerName} ${S.current.id.toUpperCase()}', + value: trade.providerId ?? '')); + + if (trade.password != null && trade.password!.isNotEmpty) + items.add(StandartListItem( + title: '${trade.providerName} ${S.current.password}', value: trade.password ?? '')); } } } diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 2caa9052f..9eccf4560 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -22,7 +22,7 @@ dependencies: barcode_scan2: ^4.2.1 http: ^0.13.4 path_provider: ^2.0.11 - mobx: ^2.0.7+4 + mobx: 2.0.7+4 flutter_mobx: ^2.0.6+1 flutter_slidable: ^2.0.0 share_plus: ^4.0.10 @@ -55,13 +55,14 @@ dependencies: another_flushbar: ^1.12.29 archive: ^3.3.0 cryptography: ^2.0.5 - file_picker: ^4.6.1 + file_picker: ^5.2.5 unorm_dart: ^0.2.0 # check unorm_dart for usage and for replace permission_handler: ^10.0.0 device_display_brightness: ^0.0.6 platform_device_id: ^1.0.1 flutter_mailer: ^2.0.2 + device_info_plus: ^8.1.0 cake_backup: git: url: https://github.com/cake-tech/cake_backup.git diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb new file mode 100644 index 000000000..2099abc19 --- /dev/null +++ b/res/values/strings_bg.arb @@ -0,0 +1,688 @@ +{ + "welcome" : "Добре дошли в", + "cake_wallet" : "Cake Wallet", + "first_wallet_text" : "Невероятен портфейл за Monero, Bitcoin, Litecoin и Haven", + "please_make_selection" : "Моля, изберете отдолу за създаване или възстановяване на портфейл.", + "create_new" : "Създаване на нов портфейл", + "restore_wallet" : "Възстановяване на портфейл", + + "monero_com": "Monero.com от Cake Wallet", + "monero_com_wallet_text": "Невероятен портфейл за Monero", + + "haven_app": "Haven от Cake Wallet", + "haven_app_wallet_text": "Невероятен портфейл за Haven", + + "accounts" : "Профили", + "edit" : "Промени", + "account" : "Профил", + "add" : "Добави", + + + "address_book" : "Адресна книга", + "contact" : "Контакт", + "please_select" : "Моля, изберете:", + "cancel" : "Откажи", + "ok" : "Ок", + "contact_name" : "Име на контакт", + "reset" : "Нулиране", + "save" : "Запази", + "address_remove_contact" : "Премахни контакт", + "address_remove_content" : "Сигурни ли сте, че искате да премахнете избрания контакт?", + + + "authenticated" : "Удостоверено", + "authentication" : "Удостоверяване", + "failed_authentication" : "Неуспешно удостоверяване. ${state_error}", + + + "wallet_menu" : "Меню", + "Blocks_remaining" : "${status} оставащи блока", + "please_try_to_connect_to_another_node" : "Моля, опитайте се да се свържете към друг node.", + "xmr_hidden" : "Скрит", + "xmr_available_balance" : "Наличен баланс", + "xmr_full_balance" : "Пълен баланс", + "send" : "Изпрати", + "receive" : "Получи", + "transactions" : "Транзакции", + "incoming" : "Входящи", + "outgoing" : "Изходящи", + "transactions_by_date" : "Транзакции по дата", + "trades" : "Trades", + "filter_by": "Филтрирай по", + "today" : "Днес", + "yesterday" : "Вчера", + "received" : "Получени", + "sent" : "Изпратени", + "pending" : " (чакащи)", + "rescan" : "Сканирай отново", + "reconnect" : "Reconnect", + "wallets" : "Портфейли", + "show_seed" : "Покажи seed", + "show_keys" : "Покажи seed/keys", + "address_book_menu" : "Адресна книга", + "reconnection" : "Свързване отново", + "reconnect_alert_text" : "Сигурни ли сте, че искате да се свържете отново?", + + + "exchange" : "Exchange", + "clear" : "Изчисти", + "refund_address" : "Refund address", + "change_exchange_provider" : "Промяна на Exchange Provider", + "you_will_send" : "Обръщане от", + "you_will_get" : "Обръщане в", + "amount_is_guaranteed" : "Сумата за получаване е гарантирана", + "amount_is_estimate" : "Сумата за получаване е ", + "powered_by" : "Powered by ${title}", + "error" : "Грешка", + "estimated" : "Изчислено", + "min_value" : "Мин: ${value} ${currency}", + "max_value" : "Макс: ${value} ${currency}", + "change_currency" : "Смени валута", + "overwrite_amount" : "Промени сума", + "qr_payment_amount" : "Този QR код съдържа сума за плащане. Искате ли да промените стойността?", + + "copy_id" : "Копиране на ID", + "exchange_result_write_down_trade_id" : "Моля, запишете trade ID-то, за да продължите.", + "trade_id" : "Trade ID:", + "copied_to_clipboard" : "Копирано", + "saved_the_trade_id" : "Запазих trade ID-то", + "fetching" : "Обработване", + "id" : "ID: ", + "amount" : "Сума: ", + "payment_id" : "Payment ID: ", + "status" : "Статус: ", + "offer_expires_in" : "Предложението изтича след: ", + "trade_is_powered_by" : "This trade is powered by ${provider}", + "copy_address" : "Copy Address", + "exchange_result_confirm" : "By pressing confirm, you will be sending ${fetchingLabel} ${from} from your wallet called ${walletName} to the address shown below. Or you can send from your external wallet to the below address/QR code.\n\nPlease press confirm to continue or go back to change the amounts.", + "exchange_result_description" : "You must send a minimum of ${fetchingLabel} ${from} to the address shown on the next page. If you send an amount lower than ${fetchingLabel} ${from} it may not get converted and it may not be refunded.", + "exchange_result_write_down_ID" : "*Please copy or write down your ID shown above.", + "confirm" : "Потвърждаване", + "confirm_sending" : "Потвърждаване на изпращането", + "commit_transaction_amount_fee" : "Изпълняване на транзакция\nСума: ${amount}\nТакса: ${fee}", + "sending" : "Изпращане", + "transaction_sent" : "Сумата е изпратена!", + "expired" : "Изтекло", + "time" : "${minutes} мин ${seconds} сек", + "send_xmr" : "Изпращане на XMR", + "exchange_new_template" : "Нов шаблон", + + "faq" : "FAQ", + + + "enter_your_pin" : "Въведете PIN", + "loading_your_wallet" : "Зареждане на портфейл", + + + "new_wallet" : "Нов портфейл", + "wallet_name" : "Име на портфейл", + "continue_text" : "Напред", + "choose_wallet_currency" : "Изберете валута за портфейла:", + + + "node_new" : "Нов Node", + "node_address" : "Нов адрес", + "node_port" : "Node порт", + "login" : "Влизане", + "password" : "Парола", + "nodes" : "Nodes", + "node_reset_settings_title" : "Възстановяване на настройки", + "nodes_list_reset_to_default_message" : "Сигурни ли сте, че искате да възстановите фабричните настройки?", + "change_current_node" : "Сигурни ли сте, че искате да промените сегашния node на ${node}?", + "change" : "Промени", + "remove_node" : "Премахни node", + "remove_node_message" : "Сигурни ли сте, че искате да премахнете избрания node?", + "remove" : "Премахни", + "delete" : "Изтрий", + "add_new_node" : "Добави нов node", + "change_current_node_title" : "Промени сегашния node", + "node_test" : "Тест", + "node_connection_successful" : "Връзката бе установена успешно", + "node_connection_failed" : "Връзката не можа да бъде установена", + "new_node_testing" : "Тестване на нов node", + + + "use" : "Смяна на ", + "digit_pin" : "-цифрен PIN", + + + "share_address" : "Сподели адрес", + "receive_amount" : "Сума", + "subaddresses" : "Подадреси", + "addresses" : "Адреси", + "scan_qr_code" : "Сканирайте QR кода, за да получите адреса", + "qr_fullscreen" : "Натиснете, за да отворите QR кода на цял екран", + "rename" : "Промяна на името", + "choose_account" : "Избиране на профил", + "create_new_account" : "Създаване на нов профил", + "accounts_subaddresses" : "Профили и подадреси", + + + "restore_restore_wallet" : "Възстановяване на портфейл", + "restore_title_from_seed_keys" : "Възстановяване от seed/keys", + "restore_description_from_seed_keys" : "Възстановете своя портфейл от seed/keys, които сте съхранили на сигурно място", + "restore_next" : "Next", + "restore_title_from_backup" : "Възстановяване от резервно копие", + "restore_description_from_backup" : "Можете да възстановите цялото приложение Cake Wallet от своя резервен файл", + "restore_seed_keys_restore" : "Възстановяне от Seed/Keys", + "restore_title_from_seed" : "Възстановяване от seed", + "restore_description_from_seed" : "Възстановяване на портфейл от кода от 13 или 25 думи", + "restore_title_from_keys" : "Възстановяване от keys", + "restore_description_from_keys" : "Възстановяване на портфейл от генерираните от Вашите тайни ключове клавиши", + "restore_wallet_name" : "Име на портфейл", + "restore_address" : "Адреси", + "restore_view_key_private" : "View key (таен)", + "restore_spend_key_private" : "Spend key (публичен)", + "restore_recover" : "Възстановяване", + "restore_wallet_restore_description" : "Описание на възстановяване на портфейл", + "restore_new_seed" : "Нов seed", + "restore_active_seed" : "Активиране на seed", + "restore_bitcoin_description_from_seed" : "Възстановяване на портфейл чрез код от 24 думи", + "restore_bitcoin_description_from_keys" : "Възстановяване на портфейл чрез WIF, изведен от Вашите private keys", + "restore_bitcoin_title_from_keys" : "Възстановяване от WIF", + "restore_from_date_or_blockheight" : "Моля, въведете дата няколко дни преди създаването на този портфейл. Ако знаете blockheight-а, въведето него вместо това", + + + "seed_reminder" : "Моля, запишете го в случай на загуба на устройството.", + "seed_title" : "Seed", + "seed_share" : "Споделяне на seed", + "copy" : "Копиране", + + + "seed_language_choose" : "Моля, изберете език на seed-а:", + "seed_choose" : "Изберете език на seed-а", + "seed_language_next" : "Следващ", + "seed_language_english" : "Английски", + "seed_language_chinese" : "Китайски", + "seed_language_dutch" : "Нидерландски", + "seed_language_german" : "Немски", + "seed_language_japanese" : "Японски", + "seed_language_portuguese" : "Португалски", + "seed_language_russian" : "Руски", + "seed_language_spanish" : "Испански", + "seed_language_french": "Френски", + "seed_language_italian": "Италиански", + + + "send_title" : "Изпращане", + "send_your_wallet" : "Вашият портфейл", + "send_address" : "${cryptoCurrency} адрес", + "send_payment_id" : "Payment ID (не е задължително)", + "all" : "ALL", + "send_error_minimum_value" : "Минималната сума е 0.01", + "send_error_currency" : "Валутата може да съдържа само числа", + "send_estimated_fee" : "Изчислена такса:", + "send_priority" : "В момента таксата е на ${transactionPriority} приоритетност.\nПриоритетността на транзакцията може да бъде променена в настройките", + "send_creating_transaction" : "Създаване на транзакция", + "send_templates" : "Шаблони", + "send_new" : "Ново", + "send_amount" : "Сума:", + "send_fee" : "Такса:", + "send_name" : "Име", + "send_got_it" : "Готово", + "send_sending" : "Изпращане...", + "send_success" : "Вашите ${crypto} бяха успешно изпратени", + + + "settings_title" : "Настройки", + "settings_nodes" : "Nodes", + "settings_current_node" : "Сегашен node", + "settings_wallets" : "Портфейли", + "settings_display_balance" : "Показване на баланс", + "settings_currency" : "Валута", + "settings_fee_priority" : "Таксова приоритетност", + "settings_save_recipient_address" : "Запазване адрес на получател", + "settings_personal" : "Лични", + "settings_change_pin" : "Промяна на PIN", + "settings_change_language" : "Промяна на езика", + "settings_allow_biometrical_authentication" : "Позволяване на биометрично удостоверяване.", + "settings_dark_mode" : "Тъмен режим", + "settings_transactions" : "Транзакции", + "settings_trades" : "Сделки", + "settings_display_on_dashboard_list" : "Показване на таблото", + "settings_all" : "Всичко", + "settings_only_trades" : "Само сделки", + "settings_only_transactions" : "Само транзакции", + "settings_none" : "Липсва", + "settings_support" : "Поддръжка", + "settings_terms_and_conditions" : "Условия", + "pin_is_incorrect" : "Грешен PIN", + + + "setup_pin" : "Настройване на PIN", + "enter_your_pin_again" : "Въведете своя PIN отново", + "setup_successful" : "Вашият PIN бе успешно настроен!", + + + "wallet_keys" : "Seed/keys на портфейла", + "wallet_seed" : "Seed на портфейла", + "private_key" : "Таен ключ", + "public_key" : "Публичен ключ", + "view_key_private" : "View key (таен)", + "view_key_public" : "View key (публичен)", + "spend_key_private" : "Spend key (таен)", + "spend_key_public" : "Spend key (публичен)", + "copied_key_to_clipboard" : "Копиран ключ: ${key}", + + + "new_subaddress_title" : "Нов адрес", + "new_subaddress_label_name" : "Име на Label", + "new_subaddress_create" : "Създаване", + + "address_label" : "Адресен label", + + "subaddress_title" : "Лист от подадреси", + + + "trade_details_title" : "Подробности на сделката", + "trade_details_id" : "ID", + "trade_details_state" : "Статус", + "trade_details_fetching" : "Обработка", + "trade_details_provider" : "Provider", + "trade_details_created_at" : "Създадено", + "trade_details_pair" : "Pair", + "trade_details_copied" : "${title} копирано", + + + "trade_history_title" : "История на сделките", + + + "transaction_details_title" : "Подробности на транзакцията", + "transaction_details_transaction_id" : "Transaction ID", + "transaction_details_date" : "Дата", + "transaction_details_height" : "Height", + "transaction_details_amount" : "Сума", + "transaction_details_fee" : "Такса", + "transaction_details_copied" : "${title} копирано", + "transaction_details_recipient_address" : "Адрес на получател", + + + "wallet_list_title" : "Monero портфейл", + "wallet_list_create_new_wallet" : "Създаване на нов портфейл", + "wallet_list_restore_wallet" : "Възстановяване на портфейл", + "wallet_list_load_wallet" : "Зареждане на портфейл", + "wallet_list_loading_wallet" : "Зареждане на портфейл ${wallet_name}", + "wallet_list_failed_to_load" : "Грешка при зареждането на портфейл ${wallet_name}. ${error}", + "wallet_list_removing_wallet" : "Премахване на портфейл ${wallet_name}", + "wallet_list_failed_to_remove" : "Грешка при премахването на портфейл${wallet_name}. ${error}", + + + "widgets_address" : "Адрес", + "widgets_restore_from_blockheight" : "Възстановяване от blockheight", + "widgets_restore_from_date" : "Възстановяване от дата", + "widgets_or" : "или", + "widgets_seed" : "Seed", + + + "router_no_route" : "Няма дефиниран път за ${name}", + + + "error_text_account_name" : "Името на профила може да съдържа само букви и числа \nи трябва да е между 1 и 15 символа", + "error_text_contact_name" : "Името на контакта не може да съдържа символите ` , ' \" \nи и трябва да е между 1 и 32 символа", + "error_text_address" : "Адресът на портфейла трябва да отговаря \n на вида криптовалута", + "error_text_node_address" : "Моля, въведете iPv4 адрес", + "error_text_node_port" : "Node port-ът е цяло число между 0 и 65535", + "error_text_payment_id" : "Payment ID-то може да съдържа само между 16 и 64 шестнайсетични символа", + "error_text_xmr" : "XMR сумата не може да надхвърля наличния баланс.\nБроят на цифрите след десетичната запетая може да бъде най-много 12", + "error_text_fiat" : "Сумата не може да надвишава наличния баланс.\nThe number of fraction digits must be less or equal to 2", + "error_text_subaddress_name" : "Името на подадреса не може да съдържат символите ` , ' \" \n и трябва да е между 1 и 20 символа", + "error_text_amount" : "Сумата може да съдържа само числа", + "error_text_wallet_name" : "Името на портфейла може да съдържа само букви, цифри, и символите _ и - \n и трябва да е между 1 и 33 символа", + "error_text_keys" : "Ключовете за портфейл може да съдържат само 64 шестнайсетични символа", + "error_text_crypto_currency" : "Броят на цифрите след десетичната запетая\nможе да бъде най-много 12", + "error_text_minimal_limit" : "Сделка за ${provider} не беше създадена. Сумата е по-малко от минималната: ${min} ${currency}", + "error_text_maximum_limit" : "Сделка за ${provider} не беше създадена. Сумата надвишава максималната: ${max} ${currency}", + "error_text_limits_loading_failed" : "Сделка за ${provider} не беше създадена. Неуспешно зареждане на лимити", + "error_text_template" : "Имената на шаблони и адреси не могат да съдържат ` , ' \" \nи трябва да са между 1 и 106 символа.", + + + "auth_store_ban_timeout" : "ban_timeout", + "auth_store_banned_for" : "Забрана за ", + "auth_store_banned_minutes" : " минути", + "auth_store_incorrect_password" : "Грешен PIN", + "wallet_store_monero_wallet" : "Monero портфейл", + "wallet_restoration_store_incorrect_seed_length" : "Грешна дължина на seed-а", + + + "full_balance" : "Пълен баланс", + "available_balance" : "Наличен баланс", + "hidden_balance" : "Скрит баланс", + + + "sync_status_syncronizing" : "СИНХРОНИЗИРАНЕ", + "sync_status_syncronized" : "СИНХРОНИЗИРАНО", + "sync_status_not_connected" : "НЯМА ВРЪЗКА", + "sync_status_starting_sync" : "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ", + "sync_status_failed_connect" : "НЕУСПЕШНО СВЪРЗВАНЕ", + "sync_status_connecting" : "СВЪРЗВАНЕ", + "sync_status_connected" : "СВЪРЗВАНЕ", + "sync_status_attempting_sync" : "ОПИТ ЗА СИНХРОНИЗАЦИЯ", + + + "transaction_priority_slow" : "Бавно", + "transaction_priority_regular" : "Обичайно", + "transaction_priority_medium" : "Средно", + "transaction_priority_fast" : "Бързо", + "transaction_priority_fastest" : "Най-бързо", + + + "trade_for_not_created" : "Сделка за ${title} не бе създадена.", + "trade_not_created" : "Сделка не бе създадена.", + "trade_id_not_found" : "Сделка ${tradeId} на ${title} не бе намерена.", + "trade_not_found" : "Сделката не бе намерена.", + + + "trade_state_pending" : "Изчаква се", + "trade_state_confirming" : "Потвърждава се", + "trade_state_trading" : "Trading", + "trade_state_traded" : "Traded", + "trade_state_complete" : "Завършено", + "trade_state_to_be_created" : "Изчаква създаване", + "trade_state_unpaid" : "Неплатено", + "trade_state_underpaid" : "Недостатъчно плащане", + "trade_state_paid_unconfirmed" : "Непотвърдено плащане", + "trade_state_paid" : "Платено", + "trade_state_btc_sent" : "Btc изпратен", + "trade_state_timeout" : "Време за изчакване", + "trade_state_created" : "Създадено", + "trade_state_finished" : "Завършено", + + "change_language" : "Смяна на езика", + "change_language_to" : "Смяна на езика на ${language}?", + + "paste" : "Поставяне", + "restore_from_seed_placeholder" : "Моля, въведете своя seed тук", + "add_new_word" : "Добавяне на нова дума", + "incorrect_seed" : "Въведеният текст е невалиден.", + + "biometric_auth_reason" : "Сканирайте своя пръстов отпечатък", + "version" : "Версия ${currentVersion}", + + "extracted_address_content" : "Ще изпратите средства на \n${recipient_name}", + + "card_address" : "Адрес:", + "buy" : "Купуване", + "sell": "Продаване", + + "placeholder_transactions" : "Вашите транзакции ще се покажат тук", + "placeholder_contacts" : "Вашите контакти ще се покажат тук", + + "template" : "Шаблон", + "confirm_delete_template" : "Този шаблон ще бъде изтрит. Искате ли да продължите?", + "confirm_delete_wallet" : "Този портфейл ще бъде изтрит. Искате ли да продължите?", + + "picker_description" : "За да изберете ChangeNOW или MorphToken, моля, първо променете своя trading pair", + + "change_wallet_alert_title" : "Смяна на сегашния портфейл", + "change_wallet_alert_content" : "Искате ли да смените сегашния портфейл на ${wallet_name}?", + + "creating_new_wallet" : "Създаване на нов портфейл", + "creating_new_wallet_error" : "Грешка: ${description}", + + "seed_alert_title" : "Внимание", + "seed_alert_content" : "Seed-ът е единственият начин да възстановите портфейла си. Записахте ли го?", + "seed_alert_back" : "Назад", + "seed_alert_yes" : "Да", + + "exchange_sync_alert_content" : "Моля, изчакайте синхронизирането на Вашия портфейл", + + "pre_seed_title" : "ВАЖНО", + "pre_seed_description" : "На следващата страница ще видите поредица от ${words} думи. Това е вашият таен личен seed и е единственият начин да възстановите портфейла си. Отговорността за съхранението му на сигурно място извън приложението на Cake Wallet е изцяло ВАША.", + "pre_seed_button_text" : "Разбирам. Покажи seed", + + "xmr_to_error" : "XMR.TO грешка", + "xmr_to_error_description" : "Невалидна сума - най-много 8 цифри след десетичната запетая", + + "provider_error" : "Грешка на ${provider} ", + + "use_ssl" : "Използване на SSL", + "trusted" : "Надежден", + + "color_theme" : "Цвят", + "light_theme" : "Светло", + "bright_theme" : "Ярко", + "dark_theme" : "Тъмно", + "enter_your_note" : "Въвеждане на бележка…", + "note_optional" : "Бележка (не е задължително)", + "note_tap_to_change" : "Бележка (натиснете за промяна)", + "view_in_block_explorer" : "Вижте в Block Explorer", + "view_transaction_on" : "Вижте транзакция на ", + "transaction_key" : "Transaction Key", + "confirmations" : "потвърждения", + "recipient_address" : "Адрес на получател", + + "extra_id" : "Допълнително ID:", + "destination_tag" : "Destination tag:", + "memo" : "Мемо:", + + "backup" : "Резервно копие", + "change_password" : "Смяна на парола", + "backup_password" : "Парола за възстановяване", + "write_down_backup_password" : "Моля, запишете своята парола за възстановяване. Тя се използва за импортиране на резервни копия на Вашите файлове.", + "export_backup" : "Експортиране на резервно копие", + "save_backup_password" : "Моля, запишете своята парола за възстановяване. Импортирането на резервни копия не е възможно без нея.", + "backup_file" : "Резервно копие", + + "edit_backup_password" : "Промяна на паролата за възстановяване", + "save_backup_password_alert" : "Запазване на паролата за възстановяване", + "change_backup_password_alert" : "Предишните резервни копия не могат да бъдат импортирани с новата парола. Те ще се използва само за нови такива. Are you sure that you want to change backup password?", + + "enter_backup_password" : "Въведете парола за възстановяване", + "select_backup_file" : "Избор на резервно копие", + "import" : "Импортиране", + "please_select_backup_file" : "Моля, изберете резервно копие и въведете парола за възстановяване.", + + "fixed_rate" : "Постоянен обменен курс", + "fixed_rate_alert" : "Ще можете да въведете сумата за получаване, когато е избранен постоянен обменен курс. Искате ли да изберете постоянен обменен курс?", + + "xlm_extra_info" : "Не забравяйте да дадете Memo ID-то, докато изпращате XLM транзакцията за обмена", + "xrp_extra_info" : "Не забравяйте да дадете Destination Tag-а, когато изпращате XRP транзакцията за обмена", + + "exchange_incorrect_current_wallet_for_xmr" : "Ако искате да обмените XMR от своя Cake Wallet Monero баланс, първо изберете своя Monero портфейл.", + "confirmed" : "Потвърдено", + "unconfirmed" : "Непотвърдено", + "displayable" : "Възможност за показване", + + "submit_request" : "изпращане на заявка", + + "buy_alert_content" : "В момента поддържаме покупката само на Bitcoin и Litecoin. За да закупите Bitcoin или Litecoin, създайте или изберете своя Bitcoin или Litecoin портфейл.", + "sell_alert_content": "В момента поддържаме само продажбата на Bitcoin. За да продавате Bitcoin, създайте или изберете своя Bitcoin портфейл.", + + "outdated_electrum_wallet_description" : "Нови Bitcoin портфейли, създадени в Cake, сега имат seed от 24 думи. Трябва да създадете нов Bitcoin адрес и да прехвърлите всичките си средства в него и веднага да спрете използването на стари портфейли. Моля, напревете това незабавно, за да подсигурите средствата си.", + "understand" : "Разбирам", + + "apk_update" : "APK ъпдейт", + + "buy_bitcoin" : "Купуване на Bitcoin", + "buy_with" : "Купуване чрез", + "moonpay_alert_text" : "Сумата трябва да бъде най-малко ${minAmount} ${fiatCurrency}", + + "outdated_electrum_wallet_receive_warning": "Ако този адрес има seed от 12 думи и е създаден чрез Cake, НЕ добавяйте Bitcoin в него. Всякакъв Bitcoin, изпратен на този адрес, може да бъде загубен завинаги. Създайте нов портфейл от 24 думи (натиснете менюто горе, вдясно, изберете Портфейли, изберете Създаване на нов портфейл, след това изберете Bitcoin) и НЕЗАБАВНО преместете своя Bitcoin там. Нови (такива с 24 думи) Bitcoin портфейли от Cake са надеждни", + "do_not_show_me": "Не показвай повече това", + + "unspent_coins_title" : "Неизползвани монети", + "unspent_coins_details_title" : "Подробности за неизползваните монети", + "freeze" : "Замразяване", + "frozen" : "Замразени", + "coin_control" : "Управление на монетите (не е задължително)", + + "address_detected" : "Открит е адрес", + "address_from_domain" : "Този адрес е от ${domain} на Unstoppable Domains", + + "add_receiver" : "Добавяне на друг получател (не е задължително)", + + "manage_yats" : "Управление на Yats", + "yat_alert_title" : "Търгувайте с крипто много по-лесно чрез Yat", + "yat_alert_content" : "Потребителите на Cake Wallet вече могат да изпращат и получават любимите си валути чрез неповторимо потребителско име от емоджита.", + "get_your_yat" : "Получете своя Yat", + "connect_an_existing_yat" : "Добавете съществуващ Yat", + "connect_yats": "Добавете Yats", + "yat_address" : "Yat Адрес", + "yat" : "Yat", + "address_from_yat" : "Този адрес е от ${emoji} в Yat", + "yat_error" : "Yat грешка", + "yat_error_content" : "Няма адреси, свързани с този Yat. Опитайте с друг Yat", + "choose_address" : "\n\nМоля, изберете адреса:", + "yat_popup_title" : "Адресът на вашия портфейл може да съдържа емоджита.", + "yat_popup_content" : "Вече можете да изпращате и да получавате крипто в Cake Wallet с вашия Yat - кратко потребителско име във формата на емоджи. Управлявайте своите Yats по всяко време в настройките", + "second_intro_title" : "Един емоджи адрес, обединяващ всички останали.", + "second_intro_content" : "Вашият Yat е уникален адрес във формата на емоджи, който играе ролята на всички Ваши дълги шестнайсетични портфейли за всяка валута.", + "third_intro_title" : "Yat добре се сработва с други", + "third_intro_content" : "Yats също живее извън Cake Wallet. Всеки адрес на портфейл може да бъде заменен с Yat!", + "learn_more" : "Научете още", + "search": "Търсене", + "search_language": "Търсене на език", + "search_currency": "Търсене на валута", + "new_template" : "Нов шаблон", + "electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят", + "wallet_name_exists": "Вече има портфейл с това име. Моля, изберете друго име или преименувайте другия портфейл.", + "market_place": "Магазин", + "cake_pay_title": "Cake Pay Gift Карти", + "cake_pay_subtitle": "Купете гифткарти на намалени цени (само за САЩ)", + "cake_pay_web_cards_title": "Cake Pay Онлайн Карти", + "cake_pay_web_cards_subtitle": "Купете световно признати предплатени и гифт карти", + "about_cake_pay": "Cake Pay Ви позволява лесно да купувате предплатени карти, които веднага могат да се използват с над 150,000 търговци на територията на САЩ.", + "cake_pay_account_note": "Регистрайте се само с един имейл, за да виждате и купувате карти. За някои има дори и отстъпка!", + "already_have_account": "Вече имате профил?", + "create_account": "Създаване на профил", + "privacy_policy": "Политика за поверителността", + "welcome_to_cakepay": "Добре дошли в Cake Pay!", + "sign_up": "Регистрация", + "forgot_password": "Забравена парола", + "reset_password": "Нулиране на парола", + "gift_cards": "Gift Карти", + "setup_your_debit_card": "Настройте своята дебитна карта", + "no_id_required": "Без нужда от документ за самоличност. Използвайте навсякъде", + "how_to_use_card": "Как се ползва тази карта", + "purchase_gift_card": "Купуване на Gift Card", + "verification": "Потвърждаване", + "fill_code": "Моля, въведето кода за потвърждаване, изпратен на Вашия имейл", + "dont_get_code": "Не получихте код?", + "resend_code": "Повторно изпращане", + "debit_card": "Дебитна карта", + "cakepay_prepaid_card": "CakePay предплатена дебитна карта", + "no_id_needed": "Без нужда от документ за самоличност!", + "frequently_asked_questions": "Често задавани въпроси", + "debit_card_terms": "Съхранението и използването на данните от вашата платежна карта в този дигитален портфейл подлежат на условията на съответното съгласие за картодържец от издателя на картата.", + "please_reference_document": "Моля, вижте документите по-долу за повече информация.", + "cardholder_agreement": "Съгласие за картодържец", + "e_sign_consent": "E-Sign съгласие", + "agree_and_continue": "Съгласяване и продължаване", + "email_address": "Имейл адрес", + "agree_to": "Чрез създаването на акаунт вие се съгласявате с ", + "and": "и", + "enter_code": "Въведете код", + "congratulations": "Поздравления!", + "you_now_have_debit_card": "Вече имате дебитна карта", + "min_amount" : "Мин: ${value}", + "max_amount" : "Макс: ${value}", + "enter_amount": "Въведете сума", + "billing_address_info": "Ако Ви попитат за билинг адрес, въведето своя адрес за доставка", + "order_physical_card": "Поръчка на физическа карта", + "add_value": "Добавяне на стойност", + "activate": "Активиране", + "get_a": "Вземете ", + "digital_and_physical_card": " дигитална или физическа предплатена дебитна карта", + "get_card_note": ", която можете да заредите с дигитална валута. Без нужда от допълнителна информация!", + "signup_for_card_accept_terms": "Регистрайте се за картата и приемете условията.", + "add_fund_to_card": "Добавете предплатени средства в картите (до ${value})", + "use_card_info_two": "Средствата се обръщат в USD, когато биват запазени в предплатената карта, а не в дигитална валута.", + "use_card_info_three": "Използвайте дигиталната карта онлайн или чрез безконтактен метод на плащане.", + "optionally_order_card": "По желание поръчайте и физическа карта.", + "hide_details" : "Скриване на подробностите", + "show_details" : "Показване на подробностите", + "upto": "до ${value}", + "discount": "Спестете ${value}%", + "gift_card_amount": "Сума в Gift Card", + "bill_amount": "Искана сума", + "you_pay": "Вие плащате", + "tip": "Tip:", + "custom": "персонализирано", + "by_cake_pay": "от Cake Pay", + "expires": "Изтича", + "mm": "мм", + "yy": "гг", + "online": "Онлайн", + "offline": "Офлайн", + "gift_card_number": "Номер на Gift Card", + "pin_number": "PIN код", + "total_saving": "Общо спестявания", + "last_30_days": "Последните 30 дни", + "avg_savings": "Средни спестявания", + "view_all": "Виж всички", + "active_cards": "Активни карти", + "delete_account": "Изтриване на акаунт", + "cards": "Карти", + "active": "Активиране", + "redeemed": "Използвани", + "gift_card_balance_note": "Гифткарти с наличен баланс ще се покажат тук", + "gift_card_redeemed_note": "Използваните гифткарти ще се покажат тук", + "logout": "Logout", + "add_tip": "Add Tip", + "percentageOf": "от ${amount}", + "is_percentage": "е", + "search_category": "Търсене в категория", + "mark_as_redeemed": "Отбележи като използван", + "more_options": "Още настройки", + "awaiting_payment_confirmation": "Чака се потвърждение на плащането", + "transaction_sent_notice": "Ако процесът продължи повече от 1 минута, проверете някой block explorer и своя имейл.", + "agree": "Съгласен/а съм", + "in_store": "In Store", + "generating_gift_card": "Създаване на Gift Card", + "payment_was_received": "Плащането бе получено.", + "proceed_after_one_minute": "Ако процесът продължи повече от 1 минута, проверете своя имейл.", + "order_id": "ID на поръчка", + "gift_card_is_generated": "Gift Card бе създадена", + "open_gift_card": "Отвори Gift Card", + "contact_support": "Свържи се с отдел поддръжка", + "gift_cards_unavailable": "В момента гифткарти могат да бъдат закупени само с Monero, Bitcoin и Litecoin", + "introducing_cake_pay": "Запознайте се с Cake Pay!", + "cake_pay_learn_more": "Купете и използвайте гифткарти директно в приложението!\nПлъзнете отляво надясно, за да научите още.", + "automatic": "Автоматично", + "fixed_pair_not_supported": "Този fixed pair не се поддържа от избраната борса", + "variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса", + "none_of_selected_providers_can_exchange": "Нито един от избраните provider-ъри не може да направи този превод", + "choose_one": "Изберете едно", + "choose_from_available_options": "Изберете от следните опции:", + "custom_redeem_amount": "Персонализирана сума за използване", + "add_custom_redemption": "Добавете персонализиран Redemption", + "remaining": "оставащи", + "delete_wallet": "Изтриване на портфейл", + "delete_wallet_confirm_message" : "Сигурни ли сте, че искате да изтриете протфейла ${wallet_name}?", + "low_fee": "Ниска такса", + "low_fee_alert": "Използвате ниска приоритетност в мрежата. Това може да доведе до дълго чакане, различни обменни курсове или отказани сделки. Препоръчваме използването на по-висока такса.", + "ignor": "Игнориране", + "use_suggested": "Използване на предложеното", + "do_not_share_warning_text" : "Не споделяйте това с никого, дори и отдел поддръжка.\n\nПарите Ви могат и ще бъдат откраднати!", + "help": "Помощ", + "all_transactions": "Всички транзакции", + "all_trades": "Всички сделкки", + "connection_sync": "Свързване и синхронизиране", + "security_and_backup": "Сигурност и резервни копия", + "create_backup": "Създаване на резервно копие", + "privacy_settings": "Настройки за поверителност", + "privacy": "Поверителност", + "display_settings": "Настройки на екрана", + "other_settings": "Други настройки", + "require_pin_after": "Въведете PIN след", + "always": "Винаги", + "minutes_to_pin_code": "${minute} минути", + "disable_exchange": "Деактивиране на борса", + "advanced_privacy_settings": "Допълнителни настройки за поверителност", + "settings_can_be_changed_later": "Тези настройки могат да бъдат променени по-късно от приложението", + "add_custom_node": "Добавяне на нов персонализиран Node", + "disable_fiat": "Деактивиране на fiat", + "fiat_api": "Fiat API", + "disabled": "Деактивирано", + "enabled": "Активирано", + "tor_only": "Само чрез Tor", + "unmatched_currencies": "Валутата на този портфейл не съвпада с тази от сканирания QR код", + "orbot_running_alert": "Моля, включете Orbot преди да свържете към този node.", + "contact_list_contacts": "Контакти", + "contact_list_wallets": "Моите портфейли", + "bitcoin_payments_require_1_confirmation": "Плащанията с Bitcoin изискват потвърждение, което може да отнеме 20 минути или повече. Благодарим за търпението! Ще получите имейл, когато плащането е потвърдено.", + "send_to_this_address" : "Send ${currency} ${tag}to this address", + "arrive_in_this_address" : "${currency} ${tag}ще отидат на този адрес", + "do_not_send": "Не изпращай", + "error_dialog_content": "Получихме грешка.\n\nМоля, изпратете доклада до нашия отдел поддръжка, за да подобрим приложението." +} diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb new file mode 100644 index 000000000..cc66b8144 --- /dev/null +++ b/res/values/strings_cs.arb @@ -0,0 +1,688 @@ +{ + "welcome" : "Vítejte v", + "cake_wallet" : "Cake Wallet", + "first_wallet_text" : "Úžasná peněženka pro Monero, Bitcoin, Litecoin a Haven", + "please_make_selection" : "Prosím vyberte si níže, jestli chcete vytvořit, nebo obnovit peněženku.", + "create_new" : "Vytvořit novou peněženku", + "restore_wallet" : "Obnovit peněženku", + + "monero_com": "Monero.com od Cake Wallet", + "monero_com_wallet_text": "Úžasná peněženka pro Monero", + + "haven_app": "Haven od Cake Wallet", + "haven_app_wallet_text": "Úžasná peněženka pro Haven", + + "accounts" : "Účty", + "edit" : "Upravit", + "account" : "Účet", + "add" : "Přidat", + + + "address_book" : "Adresář", + "contact" : "Kontakt", + "please_select" : "Zvolte si:", + "cancel" : "Zrušit", + "ok" : "OK", + "contact_name" : "Jméno kontaktu", + "reset" : "Vymazat", + "save" : "Uložit", + "address_remove_contact" : "Smazat kontakt", + "address_remove_content" : "Opravdu chcete smazat označený kontakt?", + + + "authenticated" : "Ověřeno", + "authentication" : "Ověřování", + "failed_authentication" : "Ověřování selhalo. ${state_error}", + + + "wallet_menu" : "Menu", + "Blocks_remaining" : "Zbývá ${status} bloků", + "please_try_to_connect_to_another_node" : "Zkuste se prosím připojit k jinému uzlu", + "xmr_hidden" : "Skryto", + "xmr_available_balance" : "Zůstatek (dostupný)", + "xmr_full_balance" : "Zůstatek (celkový)", + "send" : "Poslat", + "receive" : "Přijmout", + "transactions" : "Transakce", + "incoming" : "Příchozí", + "outgoing" : "Odchozí", + "transactions_by_date" : "Transakce podle data", + "trades" : "Obchody", + "filter_by": "Filtrovat podle", + "today" : "Dnes", + "yesterday" : "Včera", + "received" : "Přijato", + "sent" : "Odesláno", + "pending" : " (čeká)", + "rescan" : "Znovu prohledat", + "reconnect" : "Znovu připojit", + "wallets" : "Peněženky", + "show_seed" : "Zobrazit seed", + "show_keys" : "Zobrazit seed/klíče", + "address_book_menu" : "Adresář", + "reconnection" : "Znovu připojit", + "reconnect_alert_text" : "Opravdu se chcete znovu připojit?", + + + "exchange" : "Směnit", + "clear" : "Smazat", + "refund_address" : "Adresa pro vrácení", + "change_exchange_provider" : "Změnit směnárnu", + "you_will_send" : "Směnit z", + "you_will_get" : "Směnit na", + "amount_is_guaranteed" : "Částka, kterou dostanete, je konečná", + "amount_is_estimate" : "Částka, kterou dostanete, je jen odhad.", + "powered_by" : "Zajišťuje ${title}", + "error" : "Chyba", + "estimated" : "Odhadováno", + "min_value" : "Min: ${value} ${currency}", + "max_value" : "Max: ${value} ${currency}", + "change_currency" : "Změnit měnu", + "overwrite_amount" : "Přepsat částku", + "qr_payment_amount" : "Tento QR kód obsahuje i částku. Chcete přepsat současnou hodnotu?", + + "copy_id" : "Kopírovat ID", + "exchange_result_write_down_trade_id" : "Prosím zkopírujte si, nebo zapište si ID transakce (trade ID) pro pokračování.", + "trade_id" : "ID transakce (trade ID):", + "copied_to_clipboard" : "Zkopírováno do schránky", + "saved_the_trade_id" : "Uložil jsem si ID transakce (trade ID)", + "fetching" : "Načítá se", + "id" : "ID: ", + "amount" : "Částka: ", + "payment_id" : "ID platby: ", + "status" : "Status: ", + "offer_expires_in" : "Nabídka vyprší: ", + "trade_is_powered_by" : "Tento obchod zajišťuje ${provider}", + "copy_address" : "Zkopírovat adresu", + "exchange_result_confirm" : "Po stisknutí Potvrdit odešlete ${fetchingLabel} ${from} ze své peněženky s názvem ${walletName} na adresu uvedenou níže. Nebo můžete prostředky poslat ze své externí peněženky na níže uvedenou adresu/QR kód.\n\nProsím stiskněte Potvrdit pro pokračování, nebo se vraťte zpět pro změnu částky.", + "exchange_result_description" : "Musíte poslat minimálně ${fetchingLabel} ${from} na adresu uvedenou na následující stránce. Pokud pošlete nižší částku než ${fetchingLabel} ${from} nemusí dojít ke směně, ani k jejímu vrácení.", + "exchange_result_write_down_ID" : "*Prosím zkopírujte si, nebo zapište si výše uvedené ID.", + "confirm" : "Potvrdit", + "confirm_sending" : "Potvrdit odeslání", + "commit_transaction_amount_fee" : "Odeslat transakci\nČástka: ${amount}\nPoplatek: ${fee}", + "sending" : "Odesílání", + "transaction_sent" : "Transakce odeslána!", + "expired" : "Vypršelo", + "time" : "${minutes}m ${seconds}s", + "send_xmr" : "Odeslat XMR", + "exchange_new_template" : "Nová šablona", + + "faq" : "FAQ", + + + "enter_your_pin" : "Zadejte svůj PIN", + "loading_your_wallet" : "Načítám peněženku", + + + "new_wallet" : "Nová peněženka", + "wallet_name" : "Název peněženky", + "continue_text" : "Pokračovat", + "choose_wallet_currency" : "Prosím zvolte si měnu pro peněženku:", + + + "node_new" : "Nový uzel", + "node_address" : "Adresa uzlu", + "node_port" : "Port uzlu", + "login" : "Login", + "password" : "Heslo", + "nodes" : "Uzly", + "node_reset_settings_title" : "Zrušit nastavení", + "nodes_list_reset_to_default_message" : "Opravdu chcete zrušit nastavení a vrátit výchozí hodnotu?", + "change_current_node" : "Opravdu chcete změnit současný uzel na ${node}?", + "change" : "Změnit", + "remove_node" : "Odstranit uzel", + "remove_node_message" : "Opravdu chcete odstranit označený uzel?", + "remove" : "Odstranit", + "delete" : "Smazat", + "add_new_node" : "Přidat nový uzel", + "change_current_node_title" : "Změnit současný uzel", + "node_test" : "Otestovat", + "node_connection_successful" : "Připojení bylo úspěšné", + "node_connection_failed" : "Připojení selhalo", + "new_node_testing" : "Testování nového uzlu", + + + "use" : "Přepnout na ", + "digit_pin" : "-číselný PIN", + + + "share_address" : "Sdílet adresu", + "receive_amount" : "Částka", + "subaddresses" : "Subadresy", + "addresses" : "Adresy", + "scan_qr_code" : "Naskenujte QR kód pro získání adresy", + "qr_fullscreen" : "Poklepáním otevřete QR kód na celé obrazovce", + "rename" : "Přejmenovat", + "choose_account" : "Zvolte částku", + "create_new_account" : "Vytvořit nový účet", + "accounts_subaddresses" : "Účty a subadresy", + + + "restore_restore_wallet" : "Obnovit peněženku", + "restore_title_from_seed_keys" : "Obnovit ze seedu/klíčů", + "restore_description_from_seed_keys" : "Obnovte svou peněženku ze seedu/klíčů, které jste si uložili na bezpečném místě", + "restore_next" : "Další", + "restore_title_from_backup" : "Obnovit ze zálohy", + "restore_description_from_backup" : "Můžete obnovit celou Cake Wallet aplikaci ze souboru se zálohou", + "restore_seed_keys_restore" : "Obnovit ze seedu/klíčů", + "restore_title_from_seed" : "Obnovit ze seedu", + "restore_description_from_seed" : "Obnovte svou peněženku pomocí kombinace 25, nebo 13 slov", + "restore_title_from_keys" : "Obnovit z klíčů", + "restore_description_from_keys" : "Obnovte svou peněženku pomocí generovaných stisků kláves uložených z vašich soukromých klíčů", + "restore_wallet_name" : "Jméno peněženky", + "restore_address" : "Adresa", + "restore_view_key_private" : "Klíč pro zobrazení (soukromý)", + "restore_spend_key_private" : "Klíč pro platby (soukromý)", + "restore_recover" : "Obnovit", + "restore_wallet_restore_description" : "Popis obnovení peněženky", + "restore_new_seed" : "Nový seed", + "restore_active_seed" : "Aktivní seed", + "restore_bitcoin_description_from_seed" : "Obnovte svou peněženku pomocí kombinace 24 slov", + "restore_bitcoin_description_from_keys" : "Obnovte svou peněženku pomocí vygenerovaného WIF řetězce z vašich soukromých klíčů", + "restore_bitcoin_title_from_keys" : "Obnovit z WIF", + "restore_from_date_or_blockheight" : "Prosím zadejte datum z doby několik dnů před tím, než jste si zakládali tuto peněženku. Nebo místo toho zadejte výšku bloku, pokud ji znáte.", + + + "seed_reminder" : "Prosím zapište si toto pro případ ztráty, nebo poškození telefonu", + "seed_title" : "Seed", + "seed_share" : "Sdílet seed", + "copy" : "Kopírovat", + + + "seed_language_choose" : "Prosím zvolte si jazyk seedu:", + "seed_choose" : "Zvolte si jazyk seedu", + "seed_language_next" : "Další", + "seed_language_english" : "Angličtina", + "seed_language_chinese" : "Čínština", + "seed_language_dutch" : "Nizozemština", + "seed_language_german" : "Němčina", + "seed_language_japanese" : "Japonština", + "seed_language_portuguese" : "Portugalština", + "seed_language_russian" : "Ruština", + "seed_language_spanish" : "Španělština", + "seed_language_french": "Francouzština", + "seed_language_italian": "Italština", + + + "send_title" : "Poslat", + "send_your_wallet" : "Vaše peněženka", + "send_address" : "${cryptoCurrency} adresa", + "send_payment_id" : "ID platby (nepovinné)", + "all" : "VŠE", + "send_error_minimum_value" : "Minimální částka je 0,01", + "send_error_currency" : "Měna může obsahovat pouze čísla", + "send_estimated_fee" : "Odhadovaný poplatek:", + "send_priority" : "Momentálně je poplatek nastaven na prioritu: ${transactionPriority}.\nPriorita transakce může být upravena v nastavení.", + "send_creating_transaction" : "Vytváření transakce", + "send_templates" : "Šablony", + "send_new" : "Nová", + "send_amount" : "Částka:", + "send_fee" : "Poplatek:", + "send_name" : "Název", + "send_got_it" : "Rozumím", + "send_sending" : "Odesílání...", + "send_success" : "Vaše ${crypto} bylo úspěšně odesláno", + + + "settings_title" : "Nastavení", + "settings_nodes" : "Uzly", + "settings_current_node" : "Aktuální uzel", + "settings_wallets" : "Peněženky", + "settings_display_balance" : "Zobrazovat zůstatek", + "settings_currency" : "Měna", + "settings_fee_priority" : "Priorita (poplatky)", + "settings_save_recipient_address" : "Ukládat adresu příjemce", + "settings_personal" : "Osobní", + "settings_change_pin" : "Změnit PIN", + "settings_change_language" : "Změnit jazyk", + "settings_allow_biometrical_authentication" : "Povolit biometrické ověření", + "settings_dark_mode" : "Tmavý režim", + "settings_transactions" : "Transakce", + "settings_trades" : "Obchody", + "settings_display_on_dashboard_list" : "Zobrazit na seznamu na dashboardu", + "settings_all" : "VŠE", + "settings_only_trades" : "Pouze obchody", + "settings_only_transactions" : "Pouze transakce", + "settings_none" : "Žádný", + "settings_support" : "Podpora", + "settings_terms_and_conditions" : "Obchodní podmínky", + "pin_is_incorrect" : "PIN není správný", + + + "setup_pin" : "Nastavit PIN", + "enter_your_pin_again" : "Zadejte znovu svůj PIN", + "setup_successful" : "Váš PIN byl úspěšně nastaven!", + + + "wallet_keys" : "Seed/klíče peněženky", + "wallet_seed" : "Seed peněženky", + "private_key" : "Soukromý klíč", + "public_key" : "Veřejný klíč", + "view_key_private" : "Klíč pro zobrazení (soukromý)", + "view_key_public" : "Klíč pro zobrazení (veřejný)", + "spend_key_private" : "Klíč pro platby (soukromý)", + "spend_key_public" : "Klíč pro platby (veřejný)", + "copied_key_to_clipboard" : "Zkopírován ${key} do schránky", + + + "new_subaddress_title" : "Nová adresa", + "new_subaddress_label_name" : "Popisek", + "new_subaddress_create" : "Vytvořit", + + "address_label" : "Popisek adresy", + + "subaddress_title" : "Seznam subadres", + + + "trade_details_title" : "Podrobnosti k obchodu", + "trade_details_id" : "ID", + "trade_details_state" : "Stav", + "trade_details_fetching" : "Získávám", + "trade_details_provider" : "Poskytovatel", + "trade_details_created_at" : "Vytvořeno v", + "trade_details_pair" : "Pár", + "trade_details_copied" : "${title} zkopírováno do schránky", + + + "trade_history_title" : "Historie obchodů", + + + "transaction_details_title" : "Podrobnosti o transakci", + "transaction_details_transaction_id" : "ID transakce", + "transaction_details_date" : "Datum", + "transaction_details_height" : "Výška", + "transaction_details_amount" : "Částka", + "transaction_details_fee" : "Poplatek", + "transaction_details_copied" : "${title} zkopírováno do schránky", + "transaction_details_recipient_address" : "Adresa příjemce", + + + "wallet_list_title" : "Monero Wallet", + "wallet_list_create_new_wallet" : "Vytvořit novou peněženku", + "wallet_list_restore_wallet" : "Obnovit peněženku", + "wallet_list_load_wallet" : "Načíst peněženku", + "wallet_list_loading_wallet" : "Načítám ${wallet_name} peněženku", + "wallet_list_failed_to_load" : "Chyba při načítání ${wallet_name} peněženky. ${error}", + "wallet_list_removing_wallet" : "Odstraňuji ${wallet_name} peněženku", + "wallet_list_failed_to_remove" : "Chyba při odstraňování ${wallet_name} peněženky. ${error}", + + + "widgets_address" : "Adresa", + "widgets_restore_from_blockheight" : "Obnovit z výšky bloku", + "widgets_restore_from_date" : "Obnovit z data", + "widgets_or" : "nebo", + "widgets_seed" : "Seed", + + + "router_no_route" : "Pro ${name} není definována žádná cesta", + + + "error_text_account_name" : "Název účtu může obsahovat jen písmena a čísla\na musí mít délku 1 až 15 znaků", + "error_text_contact_name" : "Jméno kontaktu nemůže obsahovat symboly ` , ' \" \na musí mít délku 1 až 32 znaků", + "error_text_address" : "Adresa peněženky musí odpovídat typu\nkryptoměny", + "error_text_node_address" : "prosím zadejte IPv4 adresu", + "error_text_node_port" : "Port uzlu musí být číslo mezi 0 a 65535", + "error_text_payment_id" : "ID platby se musí skládat z 16 až 64 hexadecimálních znaků", + "error_text_xmr" : "Hodnota XMR nemůže překročit dostupný zůstatek.\nPočet desetinných míst musí být menší, nebo roven 12", + "error_text_fiat" : "Částka nemůže překročit dostupný zůstatek.\nPočet desetinných míst musí být menší, nebo roven 2", + "error_text_subaddress_name" : "Subadresa nemůže obsahovat symboly ` , ' \" \na musí mít délku 1 až 20 znaků", + "error_text_amount" : "Částka může obsahovat pouze čísla", + "error_text_wallet_name" : "Jméno peněženky může obsahovat pouze písmena, čísla, symbol _ \na musí mít délku 1 až 33 znaků", + "error_text_keys" : "Klíče peněženky musí obsahovat 64 hexadecimálních znaků", + "error_text_crypto_currency" : "Počet desetinných míst\nmusí být menší, nebo roven 12", + "error_text_minimal_limit" : "Obchod pro ${provider} nebyl vytvořen. Částka je menší než minimální hodnota: ${min} ${currency}", + "error_text_maximum_limit" : "Obchod pro ${provider} nebyl vytvořen. Částka je větší než maximální hodnota: ${max} ${currency}", + "error_text_limits_loading_failed" : "Obchod pro ${provider} nebyl vytvořen. Selhalo načítání limitů", + "error_text_template" : "Jméno šablony a adresa nemohou obsahovat symboly ` , ' \" \na musí mít délku 1 až 106 znaků", + + + "auth_store_ban_timeout" : "ban_timeout", + "auth_store_banned_for" : "Zablokován na ", + "auth_store_banned_minutes" : " minut", + "auth_store_incorrect_password" : "Nesprávný PIN", + "wallet_store_monero_wallet" : "Monero Wallet", + "wallet_restoration_store_incorrect_seed_length" : "Nesprávná délka seedu", + + + "full_balance" : "Celkový zůstatek", + "available_balance" : "Dostupný zůstatek", + "hidden_balance" : "Skrytý zůstatek", + + + "sync_status_syncronizing" : "SYNCHRONIZUJI", + "sync_status_syncronized" : "SYNCHRONIZOVÁNO", + "sync_status_not_connected" : "NEPŘIPOJENO", + "sync_status_starting_sync" : "SPOUŠTĚNÍ SYNCHRONIZACE", + "sync_status_failed_connect" : "ODPOJENO", + "sync_status_connecting" : "PŘIPOJOVÁNÍ", + "sync_status_connected" : "PŘIPOJENO", + "sync_status_attempting_sync" : "ZAHAJUJI SYNCHR.", + + + "transaction_priority_slow" : "Pomalá", + "transaction_priority_regular" : "Běžná", + "transaction_priority_medium" : "Střední", + "transaction_priority_fast" : "Rychlá", + "transaction_priority_fastest" : "Nejrychlejší", + + + "trade_for_not_created" : "Obchod pro ${title} nebyl vytvořen.", + "trade_not_created" : "Obchod nebyl vytvořen", + "trade_id_not_found" : "Obchod ${tradeId} z ${title} nenalezen.", + "trade_not_found" : "Obchod nenalezen.", + + + "trade_state_pending" : "Čekající", + "trade_state_confirming" : "Ověřování", + "trade_state_trading" : "Obchoduji", + "trade_state_traded" : "Zobchodováno", + "trade_state_complete" : "Kompletní", + "trade_state_to_be_created" : "Bude vytvořen", + "trade_state_unpaid" : "Nezaplaceno", + "trade_state_underpaid" : "Zaplaceno méně", + "trade_state_paid_unconfirmed" : "Nepotvrzeně zaplaceno", + "trade_state_paid" : "Zaplaceno", + "trade_state_btc_sent" : "BTC odesláno", + "trade_state_timeout" : "Vypršel časový limit", + "trade_state_created" : "Vytvořeno", + "trade_state_finished" : "Hotovo", + + "change_language" : "Změnit jazyk", + "change_language_to" : "Změnit jazyk na ${language}?", + + "paste" : "Vložit", + "restore_from_seed_placeholder" : "Prosím zadejte, nebo vložte ze schránky svůj seed.", + "add_new_word" : "Přidat nové slovo", + "incorrect_seed" : "Zadaný text není správný.", + + "biometric_auth_reason" : "Naskenujte otisk prstu pro ověření", + "version" : "Verze ${currentVersion}", + + "extracted_address_content" : "Prostředky budete posílat na\n${recipient_name}", + + "card_address" : "Adresa:", + "buy" : "Koupit", + "sell": "Prodat", + + "placeholder_transactions" : "Vaše transakce budou zobrazeny zde", + "placeholder_contacts" : "Vaše kontakty budou zobrazeny zde", + + "template" : "Šablona", + "confirm_delete_template" : "Tato akce smaže tuto šablonu. Přejete si pokračovat?", + "confirm_delete_wallet" : "Tato akce smaže tuto peněženku. Přejete si pokračovat?", + + "picker_description" : "Pro volbu ChangeNOW, nebo MorphToken si prosím vyberte nejprve pár pro obchodování", + + "change_wallet_alert_title" : "Přepnout peněženku", + "change_wallet_alert_content" : "Opravdu chcete změnit aktivní peněženku na ${wallet_name}?", + + "creating_new_wallet" : "Vytvářím novou peněženku", + "creating_new_wallet_error" : "Chyba: ${description}", + + "seed_alert_title" : "Pozor", + "seed_alert_content" : "Tento seed představuje jedinou možnost, jak obnovit peněženku. Zapsali jste si ho?", + "seed_alert_back" : "Zpět", + "seed_alert_yes" : "Ano", + + "exchange_sync_alert_content" : "Prosím počkejte, dokud nebude vaše peněženka synchronizována", + + "pre_seed_title" : "DŮLEŽITÉ", + "pre_seed_description" : "Na následující stránce uvidíte sérii ${words} slov. Je to váš tzv. seed a je to JEDINÁ možnost, jak můžete později obnovit svou peněženku v případě ztráty nebo poruchy. Je VAŠÍ zodpovědností zapsat si ho a uložit si ho na bezpečném místě mimo aplikaci Cake Wallet.", + "pre_seed_button_text" : "Rozumím. Ukaž mi můj seed.", + + "xmr_to_error" : "XMR.TO chyba", + "xmr_to_error_description" : "Neplatná částka. Maximálně lze použít 8 desetinných míst", + + "provider_error" : "${provider} chyba", + + "use_ssl" : "Použít SSL", + "trusted" : "Důvěřovat", + + "color_theme" : "Barevný motiv", + "light_theme" : "Světlý", + "bright_theme" : "Jasný", + "dark_theme" : "Tmavý", + "enter_your_note" : "Zadejte poznámku…", + "note_optional" : "Poznámka (nepovinné)", + "note_tap_to_change" : "Poznámka (poklepáním upravit)", + "view_in_block_explorer" : "Zobrazit v Block Exploreru", + "view_transaction_on" : "Zobrazit transakci na ", + "transaction_key" : "Klíč transakce", + "confirmations" : "Potvrzení", + "recipient_address" : "Adresa příjemce", + + "extra_id" : "Extra ID:", + "destination_tag" : "Destination Tag:", + "memo" : "Memo:", + + "backup" : "Záloha", + "change_password" : "Změnit heslo", + "backup_password" : "Heslo pro zálohy", + "write_down_backup_password" : "Prosím zapište si své heslo pro zálohy, které se používá pro import vašich souborů se zálohami.", + "export_backup" : "Exportovat zálohu", + "save_backup_password" : "Prosím ujistěte se, že máte uschováno heslo pro zálohy. Bez něj nebudete moci naimportovat soubory se zálohami.", + "backup_file" : "Soubor se zálohou", + + "edit_backup_password" : "Upravit heslo pro zálohy", + "save_backup_password_alert" : "Uložit heslo pro zálohy", + "change_backup_password_alert" : "Vaše předchozí soubory se zálohami nebude možné naimportovat s novým heslem. Nové heslo bude použito pouze pro nové zálohy. Opravdu chcete změnit heslo pro zálohy?", + + "enter_backup_password" : "Zde zadejte své heslo pro zálohy", + "select_backup_file" : "Vybrat soubor se zálohou", + "import" : "Importovat", + "please_select_backup_file" : "Prosím vyberte soubor se zálohou a zadejte heslo pro zálohy.", + + "fixed_rate" : "Pevný kurz", + "fixed_rate_alert" : "Když je zvolený pevný kurz, můžete zadat konkrétní částku, kterou chcete dostat. Chcete se přepnout do režimu s pevným kurzem?", + + "xlm_extra_info" : "Prosím nezapomeňte zadat Memo ID, když posíláte XLM transakce ke směně", + "xrp_extra_info" : "Prosím nezapomeňte zadat Destination Tag, když posíláte XRP transakce ke směně", + + "exchange_incorrect_current_wallet_for_xmr" : "Pokud chcete směnit XMR z Monero částky v Cake Wallet, prosím přepněte se nejprve do své Monero peněženky.", + "confirmed" : "Potvrzeno", + "unconfirmed" : "Nepotvrzeno", + "displayable" : "Zobrazitelné", + + "submit_request" : "odeslat požadavek", + + "buy_alert_content" : "V současné době podporujeme nákup pouze Bitcoinu a Litecoinu. Pro nákup Bitcoinu, nebo Litecoinu si prosím vytvořte Bitcoinovou, nebo Litecoinovou peněženku, nebo se do ní přepněte.", + "sell_alert_content": "V současné době podporujeme pouze prodej Bitcoinu. Pro prodej Bitcoinu si prosím vytvořte Bitcoinovou peněženku, nebo se do ní přepněte.", + + "outdated_electrum_wallet_description" : "Nové Bitcoinové peněženky vytvořené v Cake mají nyní seed se 24 slovy. Je třeba si vytvořit novou Bitcoinovou peněženku se 24 slovy, převést na ni všechny prostředky a přestat používat seed se 12 slovy. Prosím udělejte to hned pro zabezpečení svých prostředků.", + "understand" : "Rozumím", + + "apk_update" : "aktualizace APK", + + "buy_bitcoin" : "Nakoupit Bitcoin", + "buy_with" : "Nakoupit pomocí", + "moonpay_alert_text" : "Částka musí být větší nebo rovna ${minAmount} ${fiatCurrency}", + + "outdated_electrum_wallet_receive_warning": "Tato peněženka má seed se 12 slovy a byla vytvořena pomocí Cake, NEUKLÁDEJTE Bitcoin na tuto peněženku. Jakékoliv BTC převedené na tuto peněženku může být ztraceno. Vytvořte si novou peněženku s 24 slovy (otevřete menu vpravo nahoře, vyberte Peněženky, zvolte Vytvořit novou peněženku a pak zvolte Bitcoin) a IHNED tam přesuňte své BTC. Nové (24-slovní) BTC peněženky z Cake jsou bezpečné", + "do_not_show_me": "Příště nezobrazovat", + + "unspent_coins_title" : "Neutracené mince", + "unspent_coins_details_title" : "Podrobnosti o neutracených mincích", + "freeze" : "Zmrazit", + "frozen" : "Zmraženo", + "coin_control" : "Volba mincí (nepovinné)", + + "address_detected" : "Adresa detekována", + "address_from_domain" : "Tato adresa je z ${domain} na Unstoppable Domains", + + "add_receiver" : "Přidat dalšího příjemce (nepovinné)", + + "manage_yats" : "Spravovat Yaty", + "yat_alert_title" : "Posílejte a přijímejte crypto jednodušeji s Yat", + "yat_alert_content" : "Uživatelé Cake Wallet mohou nyní posílat a přijímat všechny své oblíbené měny pomocí něco jako uživatelského jména tvořeného emoji.", + "get_your_yat" : "Získat Yat", + "connect_an_existing_yat" : "Připojit existující Yat", + "connect_yats": "Připojit Yaty", + "yat_address" : "Yat adresa", + "yat" : "Yat", + "address_from_yat" : "Tato adresa je z ${emoji} na Yatu", + "yat_error" : "Yat chyba", + "yat_error_content" : "Žádná adresa není spojena s tímto Yatem. Zkuste jiný Yat", + "choose_address" : "\n\nProsím vyberte adresu:", + "yat_popup_title" : "Adresa Vaší peněženky může být emojifikována.", + "yat_popup_content" : "Nyní můžete posílat a přijímat crypto v Cake Wallet se svým Yatem - krátkým uživatelským jménem složeným z emoji. Spravujte kdykoliv Yaty na stránce s nastavením", + "second_intro_title" : "Jedna emoji adresa vládne všem", + "second_intro_content" : "Váš Yat je jediná unikátní emoji adresa, která nahrazuje všechny Vaše dlouhé hexadecimální adresy pro všechny Vaše měny.", + "third_intro_title" : "Yat dobře spolupracuje s ostatními", + "third_intro_content" : "Yat existuje i mimo Cake Wallet. Jakákoliv adresa peněženky na světě může být nahrazena Yatem!", + "learn_more" : "Zjistit více", + "search": "Hledat", + "search_language": "Hledat jazyk", + "search_currency": "Hledat měnu", + "new_template" : "Nová šablona", + "electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují", + "wallet_name_exists": "Peněženka s tímto názvem už existuje. Prosím zvolte si jiný název, nebo nejprve přejmenujte nejprve druhou peněženku.", + "market_place": "Obchod", + "cake_pay_title": "Cake Pay dárkové karty", + "cake_pay_subtitle": "Kupte si zlevněné dárkové karty (pouze USA)", + "cake_pay_web_cards_title": "Cake Pay webové karty", + "cake_pay_web_cards_subtitle": "Kupte si celosvětové předplacené a dárkové karty", + "about_cake_pay": "Cake Pay umožňuje jednoduše nakupovat dárkové karty pomocí virtuálních prostředků, které lze okamžitě uplatnit u více než 150 000 obchodníků ve Spojených státech.", + "cake_pay_account_note": "Přihlaste se svou e-mailovou adresou pro zobrazení a nákup karet. Některé jsou dostupné ve slevě!", + "already_have_account": "Máte už účet?", + "create_account": "Vytvořit účet", + "privacy_policy": "Zásady ochrany soukromí", + "welcome_to_cakepay": "Vítejte v Cake Pay!", + "sign_up": "Registrovat se", + "forgot_password": "Zapomenuté heslo", + "reset_password": "Resetovat heslo", + "gift_cards": "Dárkové karty", + "setup_your_debit_card": "Nastavit debetní kartu", + "no_id_required": "Žádní ID není potřeba. Dobijte si a utrácejte kdekoliv", + "how_to_use_card": "Jak použít tuto kartu", + "purchase_gift_card": "Objednat dárkovou kartu", + "verification": "Ověření", + "fill_code": "Prosím vyplňte ověřovací kód zaslaný na Váš e-mail", + "dont_get_code": "Nepřišel Vám kód?", + "resend_code": "Prosím poslat znovu", + "debit_card": "Debetní karta", + "cakepay_prepaid_card": "CakePay předplacená debetní karta", + "no_id_needed": "Žádné ID není potřeba!", + "frequently_asked_questions": "Často kladené otázky", + "debit_card_terms": "Uložení a použití vašeho čísla platební karty (a přihlašovací údaje k vašemu číslu karty) v této digitální peněžence se řídí Obchodními podmínkami smlouvy příslušného držitele karty s vydavatelem karty (v jejich nejaktuálnější verzi).", + "please_reference_document": "Více informací naleznete v dokumentu níže.", + "cardholder_agreement": "Smlouva držitele karty", + "e_sign_consent": "E-Sign souhlas", + "agree_and_continue": "Souhlasím & pokračovat", + "email_address": "E-mailová adresa", + "agree_to": "Vytvořením účtu souhlasíte s ", + "and": "a", + "enter_code": "Zadejte kód", + "congratulations": "Gratulujeme!", + "you_now_have_debit_card": "Nyní máte debetní kartu", + "min_amount" : "Min: ${value}", + "max_amount" : "Max: ${value}", + "enter_amount": "Zadejte částku", + "billing_address_info": "Při dotazu na fakturační adresu, zadejte svou doručovací adresu", + "order_physical_card": "Objednat fyzickou kartu", + "add_value": "Přidat hodnotu", + "activate": "Aktivovat", + "get_a": "Získejte ", + "digital_and_physical_card": " digitální a fyzické předplacené debetní karty,", + "get_card_note": " které můžete nabít digitální měnou. Žádné další informace nejsou vyžadovány!", + "signup_for_card_accept_terms": "Zaregistrujte se pro kartu a souhlaste s podmínkami.", + "add_fund_to_card": "Všechny předplacené prostředky na kartě (až ${value})", + "use_card_info_two": "Prostředky jsou převedeny na USD, když jsou drženy na předplaceném účtu, nikoliv na digitální měnu.", + "use_card_info_three": "Použijte tuto digitální kartu online nebo bezkontaktními platebními metodami.", + "optionally_order_card": "Volitelně objednat fyzickou kartu.", + "hide_details" : "Skrýt detaily", + "show_details" : "Zobrazit detaily", + "upto": "až ${value}", + "discount": "Ušetříte ${value}%", + "gift_card_amount": "Hodnota dárkové karty", + "bill_amount": "Účtovaná částka", + "you_pay": "Zaplatíte", + "tip": "Spropitné:", + "custom": "vlastní", + "by_cake_pay": "od Cake Pay", + "expires": "Vyprší", + "mm": "MM", + "yy": "YY", + "online": "Online", + "offline": "Offline", + "gift_card_number": "Číslo dárkové karty", + "pin_number": "Číslo PIN", + "total_saving": "Celkem ušetřeno", + "last_30_days": "Posledních 30 dnů", + "avg_savings": "Prům. ušetřeno", + "view_all": "Zobrazit vše", + "active_cards": "Aktivní karty", + "delete_account": "Smazat účet", + "cards": "Karty", + "active": "Aktivní", + "redeemed": "Uplatněné", + "gift_card_balance_note": "Dárkové karty se zbývající částkou se zobrazí zde", + "gift_card_redeemed_note": "Dárkové karty, které jste uplatnili, se zobrazí zde", + "logout": "Odhlásit", + "add_tip": "Přidat spropitné", + "percentageOf": "z ${amount}", + "is_percentage": "je", + "search_category": "Hledat kategorii", + "mark_as_redeemed": "Označit jako uplatněný", + "more_options": "Více možností", + "awaiting_payment_confirmation": "Čeká se na potvrzení platby", + "transaction_sent_notice": "Pokud proces nepokročí během 1 minuty, zkontrolujte block explorer a svůj e-mail.", + "agree": "Souhlasím", + "in_store": "V obchodě", + "generating_gift_card": "Generuji dárkovou kartu", + "payment_was_received": "Vaše platba byla přijata.", + "proceed_after_one_minute": "Pokud proces nepokročí během 1 minuty, zkontrolujte svůj e-mail.", + "order_id": "ID objednávky", + "gift_card_is_generated": "Generuje se dárková karta", + "open_gift_card": "Otevřít dárkovou kartu", + "contact_support": "Kontaktovat podporu", + "gift_cards_unavailable": "Dárkové karty jsou v tuto chvíli dostupné pro zakoupení pouze pomocí Monera, Bitcoinu a Litecoinu.", + "introducing_cake_pay": "Představujeme Cake Pay!", + "cake_pay_learn_more": "Okamžitý nákup a uplatnění dárkových karet v aplikaci!\nPřejeďte prstem zleva doprava pro další informace.", + "automatic": "Automatický", + "fixed_pair_not_supported": "Tento pár s pevným kurzem není ve zvolené směnárně podporován", + "variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován", + "none_of_selected_providers_can_exchange": "Žádný ze zvolených poskytovatelů nemůže provést tuto směnu", + "choose_one": "Zvolte si", + "choose_from_available_options": "Zvolte si z dostupných možností:", + "custom_redeem_amount": "Vlastní částka pro uplatnění", + "add_custom_redemption": "Přidat vlastní uplatnění", + "remaining": "zbývá", + "delete_wallet": "Smazat peněženku", + "delete_wallet_confirm_message" : "Opravdu chcete smazat ${wallet_name} peněženku?", + "low_fee": "Nízký poplatek", + "low_fee_alert": "Momentálně máte nastavené nízké poplatky pro transakce. To může způsobovat dlouhé čekání, změnu směnného kurzu, nebo zrušení směny. Doporučujeme nastavit vyšší poplatek.", + "ignor": "Ignorovat", + "use_suggested": "Použít doporučený", + "do_not_share_warning_text" : "Toto nesdílejte s nikým jiným, ani s podporou.\n\nJinak mohou být Vaše prostředky ukradeny!", + "help": "pomoc", + "all_transactions": "Všechny transakce", + "all_trades": "Všechny obchody", + "connection_sync": "Připojení a synch.", + "security_and_backup": "Bezpečnost a zálohy", + "create_backup": "Vytvořit zálohu", + "privacy_settings": "Nastavení soukromí", + "privacy": "Soukromí", + "display_settings": "Nastavení zobrazení", + "other_settings": "Další nastavení", + "require_pin_after": "Vyžadovat PIN po", + "always": "Vždy", + "minutes_to_pin_code": "${minute} minutách", + "disable_exchange": "Zakázat směnárny", + "advanced_privacy_settings": "Pokročilá nastavení soukromí", + "settings_can_be_changed_later": "Tato nastavení mohou být změněna později v nastavení v této aplikaci", + "add_custom_node": "Přidat vlastní uzel", + "disable_fiat": "Zakázat fiat", + "fiat_api": "Fiat API", + "disabled": "Zakázáno", + "enabled": "Povoleno", + "tor_only": "Pouze Tor", + "unmatched_currencies": "Měna vaší současné peněženky neodpovídá té v naskenovaném QR kódu", + "orbot_running_alert": "Prosím ujistěte se, že je Orbot spuštěný, před tím, než se připojíte k tomuto uzlu.", + "contact_list_contacts": "Kontakty", + "contact_list_wallets": "Moje peněženky", + "bitcoin_payments_require_1_confirmation": "U plateb Bitcoinem je vyžadováno alespoň 1 potvrzení, což může trvat 20 minut i déle. Děkujeme za vaši trpělivost! Až bude platba potvrzena, budete informováni e-mailem.", + "send_to_this_address" : "Poslat ${currency} ${tag}na tuto adresu", + "arrive_in_this_address" : "${currency} ${tag}přijde na tuto adresu", + "do_not_send": "Neodesílat", + "error_dialog_content": "Nastala chyba.\n\nProsím odešlete zprávu o chybě naší podpoře, aby mohli zajistit opravu." +} diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb new file mode 100644 index 000000000..b69f7641b --- /dev/null +++ b/res/values/strings_id.arb @@ -0,0 +1,670 @@ +{ + "welcome" : "Selamat datang di", + "cake_wallet" : "Cake Wallet", + "first_wallet_text" : "Dompet luar biasa untuk Monero, Bitcoin, Litecoin, dan Haven", + "please_make_selection" : "Silahkan membuat pilihan di bawah ini untuk membuat atau memulihkan dompet Anda.", + "create_new" : "Buat Dompet Baru", + "restore_wallet" : "Pulihkan Dompet", + + "monero_com": "Monero.com Oleh Cake Wallet", + "monero_com_wallet_text": "Dompet luar biasa untuk Monero", + + "haven_app": "Haven Oleh Cake Wallet", + "haven_app_wallet_text": "Dompet luar biasa untuk Haven", + + "accounts" : "Akun", + "edit" : "Edit", + "account" : "Akun", + "add" : "Menambahkan", + + + "address_book" : "Buku Alamat", + "contact" : "Kontak", + "please_select" : "Silakan pilih:", + "cancel" : "Batal", + "ok" : "OK", + "contact_name" : "Nama Kontak", + "reset" : "Reset", + "save" : "Simpan", + "address_remove_contact" : "Hapus kontak", + "address_remove_content" : "Apakah Anda yakin ingin menghapus kontak yang dipilih?", + + "authenticated" : "Terotentikasi", + "authentication" : "Otentikasi", + "failed_authentication" : "Otentikasi gagal. ${state_error}", + + + "wallet_menu" : "Menu", + "Blocks_remaining" : "${status} Blok Tersisa", + "please_try_to_connect_to_another_node" : "Silakan coba untuk terhubung ke node lain", + "xmr_hidden" : "Tersembunyi", + "xmr_available_balance" : "Saldo Tersedia", + "xmr_full_balance" : "Saldo Penuh", + "send" : "Mengirim", + "receive" : "Menerima", + "transactions" : "Transaksi", + "incoming" : "Masuk", + "outgoing" : "Keluar", + "transactions_by_date" : "Transaksi berdasarkan tanggal", + "trades" : "Perdagangan", + "filter_by": "Filter berdasarkan", + "today" : "Hari ini", + "yesterday" : "Kemarin", + "received" : "Diterima", + "sent" : "Dikirim", + "pending" : " (pending)", + "rescan" : "Pindai ulang", + "reconnect" : "Sambungkan kembali", + "wallets" : "Dompet", + "show_seed" : "Tampilkan seed", + "show_keys" : "Tampilkan seed/kunci", + "address_book_menu" : "Buku alamat", + "reconnection" : "Koneksi kembali", + "reconnect_alert_text" : "Apakah Anda yakin ingin menyambungkan kembali?", + + + "exchange" : "Tukar", + "clear" : "Hapus", + "refund_address" : "Alamat pengembalian", + "change_exchange_provider" : "Ganti Penyedia Tukar", + "you_will_send" : "Konversi dari", + "you_will_get" : "Konversi ke", + "amount_is_guaranteed" : "Jumlah penerimaan dijamin", + "amount_is_estimate" : "Jumlah penerimaan diperkirakan", + "powered_by" : "Didukung oleh ${title}", + "error" : "Kesalahan", + "estimated" : "Diperkirakan", + "min_value" : "Min: ${value} ${currency}", + "max_value" : "Max: ${value} ${currency}", + "change_currency" : "Ganti Mata Uang", + "overwrite_amount" : "Timpa jumlah", + "qr_payment_amount" : "QR code ini berisi jumlah pembayaran. Apakah Anda ingin menimpa nilai saat ini?", + + "copy_id" : "Salin ID", + "exchange_result_write_down_trade_id" : "Silakan salin atau tulis ID perdagangan untuk melanjutkan.", + "trade_id" : "ID Perdagangan:", + "copied_to_clipboard" : "Disalin ke Clipboard", + "saved_the_trade_id" : "Saya telah menyimpan ID perdagangan", + "fetching" : "Mengambil", + "id" : "ID: ", + "amount" : "Jumlah: ", + "payment_id" : "ID Pembayaran: ", + "status" : "Status: ", + "offer_expires_in" : "Penawaran kedaluwarsa dalam: ", + "trade_is_powered_by" : "Perdagangan ini didukung oleh ${provider}", + "copy_address" : "Salin Alamat", + "exchange_result_confirm" : "Dengan menekan tombol konfirmasi, Anda akan mengirimkan ${fetchingLabel} ${from} dari dompet Anda yang disebut ${walletName} ke alamat yang ditampilkan di bawah. Anda juga dapat mengirim dari dompet eksternal Anda ke alamat/QR code di bawah.\n\nSilakan tekan konfirmasi untuk melanjutkan atau kembali untuk mengubah jumlah.", + "exchange_result_description" : "Anda harus mengirimkan minimal ${fetchingLabel} ${from} ke alamat yang ditampilkan di halaman berikutnya. Jika Anda mengirimkan jumlah yang lebih rendah dari ${fetchingLabel} ${from} maka uang tersebut mungkin tidak akan diubah dan mungkin tidak akan dikembalikan.", + "exchange_result_write_down_ID" : "*Silakan salin atau tulis ID Anda yang ditampilkan di atas.", + "confirm" : "Konfirmasi", + "confirm_sending" : "Konfirmasi pengiriman", + "commit_transaction_amount_fee" : "Lakukan transaksi\nJumlah: ${amount}\nBiaya: ${fee}", + "sending" : "Mengirim", + "transaction_sent" : "Transaksi terkirim!", + "expired" : "Kedaluwarsa", + "time" : "${minutes}m ${seconds}s", + "send_xmr" : "Kirim XMR", + "exchange_new_template" : "Template baru", + + "faq" : "Pertanyaan yang Sering Diajukan", + + + "enter_your_pin" : "Masukkan PIN Anda", + "loading_your_wallet" : "Memuat dompet Anda", + + + "new_wallet" : "Dompet Baru", + "wallet_name" : "Nama Dompet", + "continue_text" : "Lanjutkan", + "choose_wallet_currency" : "Silahkan pilih mata uang dompet:", + + "node_new" : "Node Baru", + "node_address" : "Alamat Node", + "node_port" : "Port Node", + "login" : "Masuk", + "password" : "Kata Sandi", + "nodes" : "Node", + "node_reset_settings_title" : "Atur ulang pengaturan", + "nodes_list_reset_to_default_message" : "Apakah Anda yakin ingin mengatur ulang pengaturan ke default?", + "change_current_node" : "Apakah Anda yakin ingin mengubah node saat ini menjadi ${node}?", + "change" : "Ubah", + "remove_node" : "Hapus node", + "remove_node_message" : "Apakah Anda yakin ingin menghapus node yang dipilih?", + "remove" : "Hapus", + "delete" : "Hapus", + "add_new_node" : "Tambah node baru", + "change_current_node_title" : "Ubah node saat ini", + "node_test" : "Uji", + "node_connection_successful" : "Koneksi berhasil", + "node_connection_failed" : "Koneksi gagal", + "new_node_testing" : "Pengujian node baru", + + + "use" : "Beralih ke ", + "digit_pin" : "-digit PIN", + + "share_address" : "Bagikan alamat", + "receive_amount" : "Jumlah", + "subaddresses" : "Sub-alamat", + "addresses" : "Alamat", + "scan_qr_code" : "Scan kode QR untuk mendapatkan alamat", + "qr_fullscreen" : "Tap untuk membuka layar QR code penuh", + "rename" : "Ganti nama", + "choose_account" : "Pilih akun", + "create_new_account" : "Buat akun baru", + "accounts_subaddresses" : "Akun dan sub-alamat", + + + "restore_restore_wallet" : "Pulihkan Dompet", + "restore_title_from_seed_keys" : "Pulihkan dari seed/kunci", + "restore_description_from_seed_keys" : "Dapatkan kembali dompet Anda dari seed/kunci yang Anda simpan di tempat yang aman", + "restore_next" : "Selanjutnya", + "restore_title_from_backup" : "Pulihkan dari cadangan", + "restore_description_from_backup" : "Anda dapat memulihkan seluruh aplikasi Cake Wallet dari file cadangan Anda", + "restore_seed_keys_restore" : "Pulihkan Seed/Kunci", + "restore_title_from_seed" : "Pulihkan dari seed", + "restore_description_from_seed" : "Pulihkan dompet Anda dari kombinasi kode 25 atau 13 kata", + "restore_title_from_keys" : "Pulihkan dari kunci", + "restore_description_from_keys" : "Pulihkan dompet Anda dari tombol yang dihasilkan yang disimpan dari kunci pribadi Anda", + "restore_wallet_name" : "Nama dompet", + "restore_address" : "Alamat", + "restore_view_key_private" : "Lihat kunci (pribadi)", + "restore_spend_key_private" : "Habiskan kunci (pribadi)", + "restore_recover" : "Pulihkan", + "restore_wallet_restore_description" : "Deskripsi pemulihan dompet", + "restore_new_seed" : "Seed baru", + "restore_active_seed" : "Seed aktif", + "restore_bitcoin_description_from_seed" : "Pulihkan dompet Anda dari kombinasi kode 24 kata", + "restore_bitcoin_description_from_keys" : "Pulihkan dompet Anda dari string WIF yang dihasilkan dari private keys Anda", + "restore_bitcoin_title_from_keys" : "Pulihkan dari WIF", + "restore_from_date_atau_blockheight" : "Silakan masukkan tanggal beberapa hari sebelum Anda membuat dompet ini. Atau jika Anda tahu blockheight, silakan masukkannya sebagai gantinya", + + + "seed_reminder" : "Silakan tulis ini di tempat yang aman jika kamu kehilangan atau menghapus ponselmu", + "seed_title" : "Bibit", + "seed_share" : "Bagikan bibit", + "copy" : "Salin", + + + "seed_language_choose" : "Silakan pilih bahasa bibit:", + "seed_choose" : "Pilih bahasa bibit", + "seed_language_next" : "Selanjutnya", + "seed_language_english" : "Inggris", + "seed_language_chinese" : "Cina", + "seed_language_dutch" : "Belanda", + "seed_language_german" : "Jerman", + "seed_language_japanese" : "Jepang", + "seed_language_portuguese" : "Portugis", + "seed_language_russian" : "Rusia", + "seed_language_spanish" : "Spanyol", + "seed_language_french": "Perancis", + "seed_language_italian": "Italia", + + + "send_title" : "Kirim", + "send_your_wallet" : "Dompetmu", + "send_address" : "Alamat ${cryptoCurrency}", + "send_payment_id" : "ID Pembayaran (opsional)", + "all" : "SEMUA", + "send_error_minimum_value" : "Nilai minimum jumlah adalah 0.01", + "send_error_currency" : "Mata uang hanya dapat berisi angka", + "send_estimated_fee" : "Biaya yang diperkirakan:", + "send_priority" : "Saat ini biaya diatur dengan prioritas ${transactionPriority}.\nPrioritas transaksi dapat diubah pada pengaturan", + "send_creating_transaction" : "Membuat transaksi", + "send_templates" : "Template", + "send_new" : "Baru", + "send_amount" : "Jumlah:", + "send_fee" : "Biaya:", + "send_name" : "Nama", + "send_got_it" : "Sudah paham", + "send_sending" : "Mengirim...", + "send_success" : "${crypto}mu berhasil dikirim", + + + "settings_title" : "Pengaturan", + "settings_nodes" : "Nodes", + "settings_current_node" : "Node saat ini", + "settings_wallets" : "Dompet", + "settings_display_balance" : "Tampilkan saldo", + "settings_currency" : "Mata uang", + "settings_fee_priority" : "Prioritas biaya", + "settings_save_recipient_address" : "Simpan alamat penerima", + "settings_personal" : "Pribadi", + "settings_change_pin" : "Ganti PIN", + "settings_change_language" : "Ganti bahasa", + "settings_allow_biometrical_authentication" : "Izinkan otentikasi biometrik", + "settings_dark_mode" : "Mode gelap", + "settings_transactions" : "Transaksi", + "settings_trades" : "Perdagangan", + "settings_display_on_dashboard_list" : "Tampilkan di daftar dashboard", + "settings_all" : "SEMUA", + "settings_only_trades" : "Hanya perdagangan", + "settings_only_transactions" : "Hanya transaksi", + "settings_none" : "Tidak ada", + "settings_support" : "Dukungan", + "settings_terms_and_conditions" : "Syarat dan Ketentuan", + "pin_is_incorrect" : "PIN salah", + + + "setup_pin" : "Pasang PIN", + "enter_your_pin_again" : "Masukkan PIN Anda lagi", + "setup_successful" : "PIN Anda telah berhasil diatur!", + + "wallet_keys" : "Seed/kunci dompet", + "wallet_seed" : "Seed dompet", + "private_key" : "Kunci privat", + "public_key" : "Kunci publik", + "view_key_private" : "Kunci tampilan (privat)", + "view_key_public" : "Kunci tampilan (publik)", + "spend_key_private" : "Kunci pengeluaran (privat)", + "spend_key_public" : "Kunci pengeluaran (publik)", + "copied_key_to_clipboard" : "Kunci ${key} disalin ke Clipboard", + + "new_subaddress_title" : "Alamat baru", + "new_subaddress_label_name" : "Nama label", + "new_subaddress_create" : "Buat", + + "address_label" : "Label alamat", + + "subaddress_title" : "Daftar sub-alamat", + + "trade_details_title" : "Detail Transaksi", + "trade_details_id" : "ID", + "trade_details_state" : "Status", + "trade_details_fetching" : "Mengambil", + "trade_details_provider" : "Penyedia", + "trade_details_created_at" : "Dibuat pada", + "trade_details_pair" : "Pasangan", + "trade_details_copied" : "${title} disalin ke Clipboard", + + "trade_history_title" : "Riwayat Transaksi", + + + "transaction_details_title" : "Rincian Transaksi", + "transaction_details_transaction_id" : "ID Transaksi", + "transaction_details_date" : "Tanggal", + "transaction_details_height" : "Tinggi", + "transaction_details_amount" : "Jumlah", + "transaction_details_fee" : "Biaya", + "transaction_details_copied" : "${title} disalin ke Clipboard", + "transaction_details_recipient_address" : "Alamat Penerima", + + "wallet_list_title" : "Dompet Monero", + "wallet_list_create_new_wallet" : "Buat Dompet Baru", + "wallet_list_restore_wallet" : "Pulihkan Dompet", + "wallet_list_load_wallet" : "Muat dompet", + "wallet_list_loading_wallet" : "Memuat ${wallet_name} dompet", + "wallet_list_failed_to_load" : "Gagal memuat ${wallet_name} dompet. ${error}", + "wallet_list_removing_wallet" : "Menghapus ${wallet_name} dompet", + "wallet_list_failed_to_remove" : "Gagal menghapus ${wallet_name} dompet. ${error}", + + "widgets_address" : "Alamat", + "widgets_restore_from_blockheight" : "Pulihkan dari tinggi blok", + "widgets_restore_from_date" : "Pulihkan dari tanggal", + "widgets_or" : "atau", + "widgets_seed" : "Biji", + + "router_no_route" : "Tidak ada rute yang ditentukan untuk ${name}", + + + "error_text_account_name" : "Nama akun hanya dapat berisi huruf, angka\ndan harus antara 1 dan 15 karakter panjang", + "error_text_contact_name" : "Nama kontak tidak boleh berisi simbol `, ' \"\ndan harus antara 1 dan 32 karakter panjang", + "error_text_address" : "Alamat dompet harus sesuai dengan tipe\nmata uang kripto", + "error_text_node_address" : "Silakan masukkan alamat iPv4", + "error_text_node_port" : "Port node hanya dapat berisi angka antara 0 dan 65535", + "error_text_payment_id" : "ID pembayaran hanya dapat berisi dari 16 hingga 64 karakter dalam hex", + "error_text_xmr" : "Nilai XMR tidak boleh melebihi saldo yang tersedia.\nJumlah digit pecahan harus kurang atau sama dengan 12", + "error_text_fiat" : "Nilai jumlah tidak boleh melebihi saldo yang tersedia.\nJumlah digit pecahan harus kurang atau sama dengan 2", + "error_text_subaddress_name" : "Nama subalamat tidak boleh berisi simbol `, ' \"\ndan harus antara 1 dan 20 karakter panjang", + "error_text_amount" : "Jumlah hanya dapat berisi angka", + "error_text_wallet_name" : "Nama dompet hanya dapat berisi huruf, angka, _ - simbol\ndan harus antara 1 dan 33 karakter panjang", + "error_text_keys" : "Kunci dompet hanya dapat berisi 64 karakter dalam hex", + "error_text_crypto_currency" : "Jumlah digit pecahan harus kurang atau sama dengan 12", + "error_text_minimal_limit" : "Perdagangan untuk ${provider} tidak dibuat. Jumlah kurang dari minimal: ${min} ${currency}", + "error_text_maximum_limit" : "Perdagangan untuk ${provider} tidak dibuat. Jumlah lebih dari maksimal: ${max} ${currency}", + "error_text_limits_loading_failed" : "Perdagangan untuk ${provider} tidak dibuat. Gagal memuat batas", + "error_text_template" : "Nama template dan alamat tidak boleh berisi simbol ` , ' \"\ndan harus antara 1 dan 106 karakter panjang", + + + "auth_store_ban_timeout" : "ban_timeout", + "auth_store_banned_for" : "Dilarang selama ", + "auth_store_banned_minutes" : "menit", + "auth_store_incorrect_password" : "PIN yang salah", + "wallet_store_monero_wallet" : "Dompet Monero", + "wallet_restoration_store_incorrect_seed_length" : "Panjang seed yang salah", + + + "full_balance" : "Saldo Penuh", + "available_balance" : "Saldo Tersedia", + "hidden_balance" : "Saldo Tersembunyi", + + "sync_status_syncronizing" : "SEDANG SINKRONISASI", + "sync_status_syncronized" : "SUDAH TERSINKRONISASI", + "sync_status_not_connected" : "TIDAK TERHUBUNG", + "sync_status_starting_sync" : "MULAI SINKRONISASI", + "sync_status_failed_connect" : "GAGAL TERHUBUNG", + "sync_status_connecting" : "MENGHUBUNGKAN", + "sync_status_connected" : "TERHUBUNG", + "sync_status_attempting_sync" : "MENCOBA SINKRONISASI", + + "transaction_priority_slow" : "Lambat", + "transaction_priority_regular" : "Normal", + "transaction_priority_medium" : "Sedang", + "transaction_priority_fast" : "Cepat", + "transaction_priority_fastest" : "Tercepat", + + "trade_for_not_created" : "Perdagangan untuk ${title} belum dibuat.", + "trade_not_created" : "Perdagangan belum dibuat", + "trade_id_not_found" : "Perdagangan ${tradeId} dari ${title} tidak ditemukan.", + "trade_not_found" : "Perdagangan tidak ditemukan.", + + "trade_state_pending" : "Menunggu", + "trade_state_confirming" : "Menegkonfirmasi", + "trade_state_trading" : "Berdagang", + "trade_state_traded" : "Telah Berdagang", + "trade_state_complete" : "Selesai", + "trade_state_to_be_created" : "Akan dibuat", + "trade_state_unpaid" : "Belum dibayar", + "trade_state_underpaid" : "Kurang bayar", + "trade_state_paid_unconfirmed" : "Dibayar belum dikonfirmasi", + "trade_state_paid" : "Dibayar", + "trade_state_btc_sent" : "Btc dikirim", + "trade_state_timeout" : "Waktu habis", + "trade_state_created" : "Dibuat", + "trade_state_finished" : "Selesai", + + "change_language" : "Ganti bahasa", + "change_language_to" : "Ganti bahasa ke ${language}?", + + "paste" : "Tempel", + "restore_from_seed_placeholder" : "Silakan masukkan atau tempel seed Anda di sini", + "add_new_word" : "Tambahkan kata baru", + "incorrect_seed" : "Teks yang dimasukkan tidak valid.", + + "biometric_auth_reason" : "Pindai sidik jari Anda untuk mengautentikasi", + "version" : "Versi ${currentVersion}", + + "openalias_alert_title" : "Alamat Terdeteksi", + "openalias_alert_content" : "Anda akan mengirim dana ke\n${recipient_name}", + + "card_address" : "Alamat:", + "buy" : "Beli", + "sell": "Jual", + + "placeholder_transactions" : "Transaksi Anda akan ditampilkan di sini", + "placeholder_contacts" : "Kontak Anda akan ditampilkan di sini", + + "template" : "Template", + "confirm_delete_template" : "Tindakan ini akan menghapus template ini. Apakah Anda ingin melanjutkan?", + "confirm_delete_wallet" : "Tindakan ini akan menghapus dompet ini. Apakah Anda ingin melanjutkan?", + + "picker_description" : "Untuk memilih ChangeNOW atau MorphToken, silakan ubah pasangan perdagangan Anda terlebih dahulu", + + "change_wallet_alert_title" : "Ganti dompet saat ini", + "change_wallet_alert_content" : "Apakah Anda ingin mengganti dompet saat ini ke ${wallet_name}?", + + "creating_new_wallet" : "Membuat dompet baru", + "creating_new_wallet_error" : "Error: ${description}", + + "seed_alert_title" : "Perhatian", + "seed_alert_content" : "Seed adalah satu-satunya cara untuk mengembalikan dompet Anda. Apakah Anda sudah menuliskannya?", + "seed_alert_back" : "Kembali", + "seed_alert_yes" : "Ya, sudah", + + "exchange_sync_alert_content" : "Silakan tunggu sampai dompet Anda tersinkronisasi", + + "pre_seed_title" : "PENTING", + "pre_seed_description" : "Di halaman berikutnya Anda akan melihat serangkaian kata ${words}. Ini adalah seed unik dan pribadi Anda dan itu SATU-SATUNYA cara untuk mengembalikan dompet Anda jika hilang atau rusak. Ini adalah TANGGUNG JAWAB Anda untuk menuliskannya dan menyimpan di tempat yang aman di luar aplikasi Cake Wallet.", + "pre_seed_button_text" : "Saya mengerti. Tampilkan seed saya", + + "xmr_to_error" : "XMR.TO error", + "xmr_to_error_description" : "Jumlah tidak valid. Batas maksimal 8 digit setelah koma", + + "provider_error" : "${provider} error", + + "use_ssl" : "Gunakan SSL", + "trusted" : "Dipercayai", + + "color_theme" : "Tema warna", + "light_theme" : "Terang", + "bright_theme" : "Cerah", + "dark_theme" : "Gelap", + "enter_your_note" : "Masukkan catatan Anda...", + "note_optional" : "Catatan (opsional)", + "note_tap_to_change" : "Catatan (tap untuk mengubah)", + "view_in_block_explorer" : "Lihat di Block Explorer", + "view_transaction_on" : "Lihat Transaksi di ", + "transaction_key" : "Kunci transaksi", + "confirmations" : "Konfirmasi", + "recipient_address" : "Alamat penerima", + + "extra_id" : "ID tambahan:", + "destination_tag" : "Tag tujuan:", + "memo" : "Memo:", + + "backup" : "Cadangan", + "change_password" : "Ubah kata sandi", + "backup_password" : "Kata sandi cadangan", + "write_down_backup_password" : "Silakan menuliskan kata sandi cadangan Anda, yang digunakan untuk impor file cadangan Anda.", + "export_backup" : "Ekspor cadangan", + "save_backup_password" : "Pastikan Anda telah menyimpan kata sandi cadangan Anda. Anda tidak akan dapat mengimpor file cadangan Anda tanpa itu.", + "backup_file" : "File cadangan", + + "edit_backup_password" : "Edit Kata Sandi Cadangan", + "save_backup_password_alert" : "Simpan kata sandi cadangan", + "change_backup_password_alert" : "File cadangan sebelumnya tidak akan tersedia untuk diimpor dengan kata sandi cadangan baru. Kata sandi cadangan baru hanya akan digunakan untuk file cadangan baru. Apakah Anda yakin ingin mengubah kata sandi cadangan?", + + "enter_backup_password" : "Masukkan kata sandi cadangan di sini", + "select_backup_file" : "Pilih file cadangan", + "import" : "Impor", + "please_select_backup_file" : "Silakan pilih file cadangan dan masukkan kata sandi cadangan.", + + "fixed_rate" : "Rate tetap", + "fixed_rate_alert" : "Anda akan dapat memasukkan jumlah penerimaan saat mode rate tetap dicentang. Apakah Anda ingin beralih ke mode rate tetap?", + + "xlm_extra_info" : "Jangan lupa untuk menentukan ID Memo saat mengirim transaksi XLM untuk pertukaran", + "xrp_extra_info" : "Jangan lupa untuk menentukan Tag Tujuan saat mengirim transaksi XRP untuk pertukaran", + + "exchange_incorrect_current_wallet_for_xmr" : "Jika Anda ingin menukar XMR dari saldo Monero Cake Wallet Anda, silakan beralih ke dompet Monero Anda terlebih dahulu.", + "confirmed" : "Dikonfirmasi", + "unconfirmed" : "Tidak dikonfirmasi", + "displayable" : "Dapat ditampilkan", + + "submit_request" : "kirim permintaan", + + "buy_alert_content" : "Saat ini kami hanya mendukung pembelian Bitcoin dan Litecoin. Untuk membeli Bitcoin atau Litecoin, silakan buat atau beralih ke dompet Bitcoin atau Litecoin Anda.", + "sell_alert_content": "Saat ini kami hanya mendukung penjualan Bitcoin. Untuk menjual Bitcoin, silakan buat atau beralih ke dompet Bitcoin Anda.", + + "outdated_electrum_wallet_description" : "Dompet Bitcoin baru yang dibuat di Cake sekarang memiliki biji semai 24 kata. Wajib bagi Anda untuk membuat dompet Bitcoin baru dan mentransfer semua dana Anda ke dompet 24 kata baru, dan berhenti menggunakan dompet dengan biji semai 12 kata. Silakan lakukan ini segera untuk mengamankan dana Anda.", + "understand" : "Saya mengerti", + + "apk_update" : "Pembaruan APK", + + "buy_bitcoin" : "Beli Bitcoin", + "buy_with" : "Beli dengan", + "moonpay_alert_text" : "Nilai jumlah harus lebih atau sama dengan ${minAmount} ${fiatCurrency}", + + "outdated_electrum_wallet_receive_warning": "Jika dompet ini memiliki biji semai 12 kata dan dibuat di Cake, JANGAN deposit Bitcoin ke dalam dompet ini. BTC apapun yang ditransfer ke dompet ini mungkin hilang. Buat dompet 24 kata baru (ketuk menu di pojok kanan atas, pilih Dompet, pilih Buat Dompet Baru, lalu pilih Bitcoin) dan SEGERA pindahkan BTC Anda ke sana. Dompet BTC (24 kata) baru dari Cake aman", + "do_not_show_me": "Jangan tampilkan ini lagi", + + "unspent_coins_title" : "Koin yang tidak terpakai", + "unspent_coins_details_title" : "Rincian koin yang tidak terpakai", + "freeze" : "Freeze", + "frozen" : "Dibekukan", + "coin_control" : "Kontrol koin (opsional)", + + "address_detected" : "Alamat terdeteksi", + "address_from_domain" : "Alamat ini dari ${domain} di Unstoppable Domains", + + "add_receiver" : "Tambahkan penerima lain (opsional)", + + "manage_yats" : "Kelola Yats", + "yat_alert_title" : "Kirim dan terima crypto dengan lebih mudah dengan Yat", + "yat_alert_content" : "Pengguna Cake Wallet sekarang dapat mengirim dan menerima semua mata uang favorit mereka dengan nama pengguna berbasis emoji yang satu-of-a-kind.", + "get_your_yat" : "Dapatkan Yat Anda", + "connect_an_existing_yat" : "Hubungkan Yat yang ada", + "connect_yats": "Hubungkan Yats", + "yat_address" : "Alamat Yat", + "yat" : "Yat", + "address_from_yat" : "Alamat ini berasal dari ${emoji} di Yat", + "yat_error" : "Kesalahan Yat", + "yat_error_content" : "Tidak ada alamat yang terkait dengan Yat ini. Coba Yat lain", + "choose_address" : "\n\nSilakan pilih alamat:", + "yat_popup_title" : "Alamat dompet Anda dapat diubah menjadi emoji.", + "yat_popup_content" : "Anda sekarang dapat mengirim dan menerima crypto di Cake Wallet dengan Yat Anda - nama pengguna berbasis emoji yang pendek. Kelola Yats kapan saja pada layar pengaturan", + "second_intro_title" : "Satu alamat emoji untuk menguasainya semua", + "second_intro_content" : "Yat Anda adalah satu alamat emoji yang unik yang menggantikan semua alamat heksadesimal panjang Anda untuk semua mata uang Anda.", + "third_intro_title" : "Yat bermain baik dengan yang lain", + "third_intro_content" : "Yats hidup di luar Cake Wallet juga. Setiap alamat dompet di dunia dapat diganti dengan Yat!", + "learn_more" : "Pelajari Lebih Lanjut", + "search": "Cari", + "search_language": "Cari bahasa", + "search_currency": "Cari mata uang", + "new_template" : "Template Baru", + "electrum_address_disclaimer": "Kami menghasilkan alamat baru setiap kali Anda menggunakan satu, tetapi alamat sebelumnya tetap berfungsi", + "wallet_name_exists": "Nama dompet sudah ada. Silakan pilih nama yang berbeda atau ganti nama dompet yang lain terlebih dahulu.", + "market_place": "Pasar", + "cake_pay_title": "Kartu Hadiah Cake Pay", + "cake_pay_subtitle": "Beli kartu hadiah dengan harga diskon (hanya USA)", + "cake_pay_web_cards_title": "Kartu Web Cake Pay", + "cake_pay_web_cards_subtitle": "Beli kartu prabayar dan kartu hadiah secara global", + "about_cake_pay": "Cake Pay memungkinkan Anda untuk dengan mudah membeli kartu hadiah dengan aset virtual, yang dapat digunakan segera di lebih dari 150.000 pedagang di Amerika Serikat.", + "cake_pay_account_note": "Daftar hanya dengan alamat email untuk melihat dan membeli kartu. Beberapa di antaranya bahkan tersedia dengan diskon!", + "already_have_account": "Sudah punya akun?", + "create_account": "Buat Akun", + "privacy_policy": "Kebijakan Privasi", + "welcome_to_cakepay": "Selamat Datang di Cake Pay!", + "sign_up": "Daftar", + "forgot_password": "Lupa Kata Sandi", + "reset_password": "Atur Ulang Kata Sandi", + "gift_cards": "Kartu Hadiah", + "setup_your_debit_card": "Pasang kartu debit Anda", + "no_id_required": "Tidak perlu ID. Isi ulang dan belanja di mana saja", + "how_to_use_card": "Bagaimana menggunakan kartu ini", + "purchase_gift_card": "Beli Kartu Hadiah", + "verification": "Verifikasi", + "fill_code": "Silakan isi kode verifikasi yang diterima di email Anda", + "dont_get_code": "Tidak mendapatkan kode?", + "resend_code": "Silakan kirim ulang", + "debit_card": "Kartu Debit", + "cakepay_prepaid_card": "Kartu Debit Prabayar CakePay", + "no_id_needed": "Tidak perlu ID!", + "frequently_asked_questions": "Pertanyaan yang sering diajukan", + "debit_card_terms": "Penyimpanan dan penggunaan nomor kartu pembayaran Anda (dan kredensial yang sesuai dengan nomor kartu pembayaran Anda) dalam dompet digital ini tertakluk pada Syarat dan Ketentuan persetujuan pemegang kartu yang berlaku dengan penerbit kartu pembayaran, seperti yang berlaku dari waktu ke waktu.", + "please_reference_document": "Silakan referensikan dokumen di bawah ini untuk informasi lebih lanjut.", + "cardholder_agreement": "Persetujuan Pemegang Kartu", + "e_sign_consent": "E-Sign Consent", + "agree_and_continue": "Setuju & Lanjutkan", + "email_address": "Alamat Email", + "agree_to": "Dengan membuat akun Anda setuju dengan ", + "and": "dan", + "enter_code": "Masukkan kode", + "congratulations": "Selamat!", + "you_now_have_debit_card": "Anda sekarang memiliki kartu debit", + "min_amount" : "Min: ${value}", + "max_amount" : "Max: ${value}", + "enter_amount": "Masukkan Jumlah", + "billing_address_info": "Jika diminta alamat billing, berikan alamat pengiriman Anda", + "order_physical_card": "Pesan Kartu Fisik", + "add_value": "Tambahkan nilai", + "activate": "Aktifkan", + "get_a": "Dapatkan ", + "digital_and_physical_card": " kartu debit pra-bayar digital dan fisik", + "get_card_note": " yang dapat Anda muat ulang dengan mata uang digital. Tidak perlu informasi tambahan!", + "signup_for_card_accept_terms": "Daftar untuk kartu dan terima syarat dan ketentuan.", + "add_fund_to_card": "Tambahkan dana pra-bayar ke kartu (hingga ${value})", + "use_card_info_two": "Dana dikonversi ke USD ketika disimpan dalam akun pra-bayar, bukan dalam mata uang digital.", + "use_card_info_three": "Gunakan kartu digital secara online atau dengan metode pembayaran tanpa kontak.", + "optionally_order_card": "Opsional memesan kartu fisik.", + "hide_details" : "Sembunyikan Rincian", + "show_details" : "Tampilkan Rincian", + "upto": "hingga ${value}", + "discount": "Hemat ${value}%", + "gift_card_amount": "Jumlah Kartu Hadiah", + "bill_amount": "Jumlah Tagihan", + "you_pay": "Anda Membayar", + "tip": "Tip:", + "custom": "kustom", + "by_cake_pay": "oleh Cake Pay", + "expires": "Kadaluarsa", + "mm": "MM", + "yy": "YY", + "online": "Online", + "offline": "Offline", + "gift_card_number": "Nomor Kartu Hadiah", + "pin_number": "Nomor PIN", + "total_saving": "Total Pembayaran", + "last_30_days": "30 hari terakhir", + "avg_savings": "Rata-rata Pembayaran", + "view_all": "Lihat Semua", + "active_cards": "Kartu Aktif", + "delete_account": "Hapus Akun", + "cards": "Kartu", + "active": "Aktif", + "redeemed": "Ditukar", + "gift_card_balance_note": "Kartu hadiah dengan saldo yang tersisa akan muncul di sini", + "gift_card_redeemed_note": "Kartu hadiah yang sudah Anda tukar akan muncul di sini", + "logout": "Keluar", + "add_tip": "Tambahkan Tip", + "percentageOf": "dari ${amount}", + "is_percentage": "adalah", + "search_category": "Cari kategori", + "mark_as_redeemed": "Tandai sebagai Ditukar", + "more_options": "Opsi Lainnya", + "awaiting_payment_confirmation": "Menunggu Konfirmasi Pembayaran", + "transaction_sent_notice": "Jika layar tidak bergerak setelah 1 menit, periksa block explorer dan email Anda.", + "agree": "Setuju", + "in_store": "Di Toko", + "generating_gift_card": "Membuat Kartu Hadiah", + "payment_was_received": "Pembayaran Anda telah diterima.", + "proceed_after_one_minute": "Jika layar tidak bergerak setelah 1 menit, periksa email Anda.", + "order_id": "ID Pesanan", + "gift_card_is_generated": "Kartu Hadiah telah dibuat", + "open_gift_card": "Buka Kartu Hadiah", + "contact_support": "Hubungi Dukungan", + "gift_cards_unavailable": "Kartu hadiah hanya tersedia untuk dibeli dengan Monero, Bitcoin, dan Litecoin saat ini", + "introducing_cake_pay": "Perkenalkan Cake Pay!", + "cake_pay_learn_more": "Beli dan tukar kartu hadiah secara instan di aplikasi!\nGeser ke kanan untuk informasi lebih lanjut.", + "automatic": "Otomatis", + "fixed_pair_not_supported": "Pasangan tetap ini tidak didukung dengan bursa yang dipilih", + "variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih", + "none_of_selected_providers_can_exchange": "Tidak ada dari penyedia yang dipilih yang dapat melakukan pertukaran ini", + "choose_one": "Pilih satu", + "choose_from_available_options": "Pilih dari pilihan yang tersedia:", + "custom_redeem_amount": "Jumlah Tukar Kustom", + "add_custom_redemption": "Tambahkan Tukar Kustom", + "remaining": "sisa", + "delete_wallet": "Hapus dompet", + "delete_wallet_confirm_message" : "Apakah Anda yakin ingin menghapus dompet ${wallet_name}?", + "low_fee": "Biaya rendah", + "low_fee_alert": "Anda saat ini menggunakan prioritas biaya jaringan rendah. Ini dapat menyebabkan tunggu yang lama, kurs yang berbeda, atau perdagangan yang dibatalkan. Kami merekomendasikan menetapkan biaya yang lebih tinggi untuk pengalaman yang lebih baik.", + "ignor": "Abaikan", + "use_suggested": "Gunakan yang Disarankan", + "do_not_share_warning_text" : "Jangan berikan ini pada siapapun, termasuk dukungan.\n\nDana Anda bisa dan akan dicuri!", + "help": "bantuan", + "all_transactions": "Semua transaksi", + "all_trades": "Semua perdagangan", + "connection_sync": "Koneksi dan sinkronisasi", + "security_and_backup": "Keamanan dan cadangan", + "create_backup": "Buat cadangan", + "privacy_settings": "Pengaturan privasi", + "privacy": "Privasi", + "display_settings": "Pengaturan tampilan", + "other_settings": "Pengaturan lainnya", + "require_pin_after": "Meminta PIN setelah", + "always": "Selalu", + "minutes_to_pin_code": "${minute} menit", + "disable_exchange": "Nonaktifkan pertukaran", + "advanced_privacy_settings": "Pengaturan Privasi Lanjutan", + "settings_can_be_changed_later": "Pengaturan ini dapat diubah nanti di pengaturan aplikasi", + "add_custom_node": "Tambahkan Node Kustom Baru", + "disable_fiat": "Nonaktifkan fiat", + "fiat_api": "API fiat", + "disabled": "Dinonaktifkan", + "enabled": "Diaktifkan", + "tor_only": "Hanya Tor", + "unmatched_currencies": "Mata uang dompet Anda saat ini tidak cocok dengan yang ditandai QR", + "orbot_running_alert": "Pastikan Orbot sedang berjalan sebelum menghubungkan ke node ini.", + "contact_list_contacts": "Kontak", + "contact_list_wallets": "Dompet Saya" +} diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index eabd192ce..d2bee1773 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -66,4 +66,4 @@ export APP_ANDROID_NAME export APP_ANDROID_VERSION export APP_ANDROID_BUILD_NUMBER export APP_ANDROID_BUNDLE_ID -export APP_ANDROID_PACKAGE +export APP_ANDROID_PACKAGE \ No newline at end of file diff --git a/tool/utils/secret_key.dart b/tool/utils/secret_key.dart index d0fa39bfc..c27bc5ff7 100644 --- a/tool/utils/secret_key.dart +++ b/tool/utils/secret_key.dart @@ -6,17 +6,12 @@ class SecretKey { static final base = [ SecretKey('salt', () => hex.encode(encrypt.Key.fromSecureRandom(16).bytes)), - SecretKey('keychainSalt', - () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), + SecretKey('keychainSalt', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), SecretKey('key', () => hex.encode(encrypt.Key.fromSecureRandom(16).bytes)), - SecretKey( - 'walletSalt', () => hex.encode(encrypt.Key.fromSecureRandom(4).bytes)), - SecretKey( - 'shortKey', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), - SecretKey( - 'backupSalt', () => hex.encode(encrypt.Key.fromSecureRandom(8).bytes)), - SecretKey('backupKeychainSalt', - () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), + SecretKey('walletSalt', () => hex.encode(encrypt.Key.fromSecureRandom(4).bytes)), + SecretKey('shortKey', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), + SecretKey('backupSalt', () => hex.encode(encrypt.Key.fromSecureRandom(8).bytes)), + SecretKey('backupKeychainSalt', () => hex.encode(encrypt.Key.fromSecureRandom(12).bytes)), SecretKey('changeNowApiKey', () => ''), SecretKey('wyreSecretKey', () => ''), SecretKey('wyreApiKey', () => ''), @@ -29,6 +24,8 @@ class SecretKey { SecretKey('anypayToken', () => ''), SecretKey('onramperApiKey', () => ''), SecretKey('ioniaClientId', () => ''), + SecretKey('trocadorApiKey', () => ''), + SecretKey('trocadorExchangeMarkup', () => ''), SecretKey('twitterBearerToken', () => ''), ];