diff --git a/cw_bitcoin/lib/bitcoin_transaction_credentials.dart b/cw_bitcoin/lib/bitcoin_transaction_credentials.dart index bd8f1763c..bda7c39ae 100644 --- a/cw_bitcoin/lib/bitcoin_transaction_credentials.dart +++ b/cw_bitcoin/lib/bitcoin_transaction_credentials.dart @@ -2,7 +2,8 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_core/output_info.dart'; class BitcoinTransactionCredentials { - BitcoinTransactionCredentials(this.outputs, {required this.priority, this.feeRate}); + BitcoinTransactionCredentials(this.outputs, + {required this.priority, this.feeRate}); final List outputs; final BitcoinTransactionPriority? priority; diff --git a/cw_bitcoin/lib/bitcoin_transaction_priority.dart b/cw_bitcoin/lib/bitcoin_transaction_priority.dart index 10953a2e0..d51775368 100644 --- a/cw_bitcoin/lib/bitcoin_transaction_priority.dart +++ b/cw_bitcoin/lib/bitcoin_transaction_priority.dart @@ -4,13 +4,15 @@ class BitcoinTransactionPriority extends TransactionPriority { const BitcoinTransactionPriority({required String title, required int raw}) : super(title: title, raw: raw); - static const List all = [fast, medium, slow]; + static const List all = [fast, medium, slow, custom]; static const BitcoinTransactionPriority slow = BitcoinTransactionPriority(title: 'Slow', raw: 0); static const BitcoinTransactionPriority medium = BitcoinTransactionPriority(title: 'Medium', raw: 1); static const BitcoinTransactionPriority fast = BitcoinTransactionPriority(title: 'Fast', raw: 2); + static const BitcoinTransactionPriority custom = + BitcoinTransactionPriority(title: 'Custom', raw: 3); static BitcoinTransactionPriority deserialize({required int raw}) { switch (raw) { @@ -20,6 +22,8 @@ class BitcoinTransactionPriority extends TransactionPriority { return medium; case 2: return fast; + case 3: + return custom; default: throw Exception('Unexpected token: $raw for BitcoinTransactionPriority deserialize'); } @@ -39,7 +43,10 @@ class BitcoinTransactionPriority extends TransactionPriority { label = 'Medium'; // S.current.transaction_priority_medium; break; case BitcoinTransactionPriority.fast: - label = 'Fast'; // S.current.transaction_priority_fast; + label = 'Fast'; + break; // S.current.transaction_priority_fast; + case BitcoinTransactionPriority.custom: + label = 'Custom'; break; default: break; @@ -48,7 +55,10 @@ class BitcoinTransactionPriority extends TransactionPriority { return label; } - String labelWithRate(int rate) => '${toString()} ($rate ${units}/byte)'; + String labelWithRate(int rate, int? customRate) { + final rateValue = this == custom ? customRate ??= 0 : rate; + return '${toString()} ($rateValue ${units}/byte)'; + } } class LitecoinTransactionPriority extends BitcoinTransactionPriority { diff --git a/cw_bitcoin/lib/electrum_transaction_info.dart b/cw_bitcoin/lib/electrum_transaction_info.dart index cfea0e089..f980bd884 100644 --- a/cw_bitcoin/lib/electrum_transaction_info.dart +++ b/cw_bitcoin/lib/electrum_transaction_info.dart @@ -11,12 +11,11 @@ import 'package:cw_core/wallet_type.dart'; class ElectrumTransactionBundle { ElectrumTransactionBundle(this.originalTransaction, - {required this.ins, required this.confirmations, this.time, required this.height}); + {required this.ins, required this.confirmations, this.time}); final BtcTransaction originalTransaction; final List ins; final int? time; final int confirmations; - final int height; } class ElectrumTransactionInfo extends TransactionInfo { @@ -25,6 +24,8 @@ class ElectrumTransactionInfo extends TransactionInfo { required int height, required int amount, int? fee, + List? inputAddresses, + List? outputAddresses, required TransactionDirection direction, required bool isPending, required DateTime date, @@ -32,6 +33,8 @@ class ElectrumTransactionInfo extends TransactionInfo { this.id = id; this.height = height; this.amount = amount; + this.inputAddresses = inputAddresses; + this.outputAddresses = outputAddresses; this.fee = fee; this.direction = direction; this.date = date; @@ -100,6 +103,8 @@ class ElectrumTransactionInfo extends TransactionInfo { var amount = 0; var inputAmount = 0; var totalOutAmount = 0; + List inputAddresses = []; + List outputAddresses = []; for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) { final input = bundle.originalTransaction.inputs[i]; @@ -108,6 +113,7 @@ class ElectrumTransactionInfo extends TransactionInfo { inputAmount += outTransaction.amount.toInt(); if (addresses.contains(addressFromOutputScript(outTransaction.scriptPubKey, network))) { direction = TransactionDirection.outgoing; + inputAddresses.add(addressFromOutputScript(outTransaction.scriptPubKey, network)); } } @@ -115,6 +121,7 @@ class ElectrumTransactionInfo extends TransactionInfo { for (final out in bundle.originalTransaction.outputs) { totalOutAmount += out.amount.toInt(); final addressExists = addresses.contains(addressFromOutputScript(out.scriptPubKey, network)); + outputAddresses.add(addressFromOutputScript(out.scriptPubKey, network)); if (addressExists) { receivedAmounts.add(out.amount.toInt()); @@ -137,6 +144,8 @@ class ElectrumTransactionInfo extends TransactionInfo { id: bundle.originalTransaction.txId(), height: height, isPending: bundle.confirmations == 0, + inputAddresses: inputAddresses, + outputAddresses: outputAddresses, fee: fee, direction: direction, amount: amount, @@ -187,6 +196,8 @@ class ElectrumTransactionInfo extends TransactionInfo { direction: parseTransactionDirectionFromInt(data['direction'] as int), date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), isPending: data['isPending'] as bool, + inputAddresses: data['inputAddresses'] as List, + outputAddresses: data['outputAddresses'] as List, confirmations: data['confirmations'] as int); } @@ -218,6 +229,8 @@ class ElectrumTransactionInfo extends TransactionInfo { direction: direction, date: date, isPending: isPending, + inputAddresses: inputAddresses, + outputAddresses: outputAddresses, confirmations: info.confirmations); } @@ -231,6 +244,8 @@ class ElectrumTransactionInfo extends TransactionInfo { m['isPending'] = isPending; m['confirmations'] = confirmations; m['fee'] = fee; + m['inputAddresses'] = inputAddresses; + m['outputAddresses'] = outputAddresses; return m; } } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 9c144ac74..5bed6a449 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -7,6 +7,7 @@ import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin_base; import 'package:collection/collection.dart'; +import 'package:cw_bitcoin/address_from_output.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; @@ -188,11 +189,9 @@ abstract class ElectrumWalletBase } } - int _getDustAmount() { - return 546; - } + int get _dustAmount => 546; - bool _isBelowDust(int amount) => amount <= _getDustAmount() && network != BitcoinNetwork.testnet; + bool _isBelowDust(int amount) => amount <= _dustAmount && network != BitcoinNetwork.testnet; Future estimateSendAllTx( List outputs, @@ -418,7 +417,7 @@ abstract class ElectrumWalletBase } // Estimate to user how much is needed to send to cover the fee - final maxAmountWithReturningChange = allInputsAmount - _getDustAmount() - fee - 1; + final maxAmountWithReturningChange = allInputsAmount - _dustAmount - fee - 1; throw BitcoinTransactionNoDustOnChangeException( bitcoinAmountToString(amount: maxAmountWithReturningChange), bitcoinAmountToString(amount: estimatedSendAll.amount), @@ -532,6 +531,7 @@ abstract class ElectrumWalletBase network: network, memo: estimatedTx.memo, outputOrdering: BitcoinOrdering.none, + enableRBF: true, ); } else { txb = BitcoinTransactionBuilder( @@ -541,6 +541,7 @@ abstract class ElectrumWalletBase network: network, memo: estimatedTx.memo, outputOrdering: BitcoinOrdering.none, + enableRBF: true, ); } @@ -794,8 +795,180 @@ abstract class ElectrumWalletBase } } - Future getTransactionExpanded( - {required String hash, required int height}) async { + Future canReplaceByFee(String hash) async { + final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash); + final confirmations = verboseTransaction['confirmations'] as int? ?? 0; + final transactionHex = verboseTransaction['hex'] as String?; + + if (confirmations > 0) return false; + + if (transactionHex == null) { + return false; + } + + final original = bitcoin.Transaction.fromHex(transactionHex); + + return original.ins + .any((element) => element.sequence != null && element.sequence! < 4294967293); + } + + Future isChangeSufficientForFee(String txId, int newFee) async { + final bundle = await getTransactionExpanded(hash: txId); + final outputs = bundle.originalTransaction.outputs; + + final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden); + + // look for a change address in the outputs + final changeOutput = outputs.firstWhereOrNull((output) => changeAddresses.any( + (element) => element.address == addressFromOutputScript(output.scriptPubKey, network))); + + var allInputsAmount = 0; + + for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) { + final input = bundle.originalTransaction.inputs[i]; + final inputTransaction = bundle.ins[i]; + final vout = input.txIndex; + final outTransaction = inputTransaction.outputs[vout]; + allInputsAmount += outTransaction.amount.toInt(); + } + + int totalOutAmount = bundle.originalTransaction.outputs + .fold(0, (previousValue, element) => previousValue + element.amount.toInt()); + + var currentFee = allInputsAmount - totalOutAmount; + + int remainingFee = (newFee - currentFee > 0) ? newFee - currentFee : newFee; + + return changeOutput != null && changeOutput.amount.toInt() - remainingFee >= 0; + } + + Future replaceByFee(String hash, int newFee) async { + try { + final bundle = await getTransactionExpanded(hash: hash); + + final utxos = []; + List privateKeys = []; + + var allInputsAmount = 0; + + // Add inputs + for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) { + final input = bundle.originalTransaction.inputs[i]; + final inputTransaction = bundle.ins[i]; + final vout = input.txIndex; + final outTransaction = inputTransaction.outputs[vout]; + final address = addressFromOutputScript(outTransaction.scriptPubKey, network); + allInputsAmount += outTransaction.amount.toInt(); + + final addressRecord = + walletAddresses.allAddresses.firstWhere((element) => element.address == address); + + final btcAddress = addressTypeFromStr(addressRecord.address, network); + final privkey = generateECPrivate( + hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, + index: addressRecord.index, + network: network); + + privateKeys.add(privkey); + + utxos.add( + UtxoWithAddress( + utxo: BitcoinUtxo( + txHash: input.txId, + value: outTransaction.amount, + vout: vout, + scriptType: _getScriptType(btcAddress), + ), + ownerDetails: + UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: btcAddress), + ), + ); + } + + int totalOutAmount = bundle.originalTransaction.outputs + .fold(0, (previousValue, element) => previousValue + element.amount.toInt()); + + var currentFee = allInputsAmount - totalOutAmount; + int remainingFee = newFee - currentFee; + + final outputs = []; + + // Add outputs and deduct the fees from it + for (int i = bundle.originalTransaction.outputs.length - 1; i >= 0; i--) { + final out = bundle.originalTransaction.outputs[i]; + final address = addressFromOutputScript(out.scriptPubKey, network); + final btcAddress = addressTypeFromStr(address, network); + + int newAmount; + if (out.amount.toInt() >= remainingFee) { + newAmount = out.amount.toInt() - remainingFee; + remainingFee = 0; + + // if new amount of output is less than dust amount, then don't add this output as well + if (newAmount <= _dustAmount) { + continue; + } + } else { + remainingFee -= out.amount.toInt(); + continue; + } + + outputs.add(BitcoinOutput(address: btcAddress, value: BigInt.from(newAmount))); + } + + final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden); + + // look for a change address in the outputs + final changeOutput = outputs.firstWhereOrNull((output) => + changeAddresses.any((element) => element.address == output.address.toAddress(network))); + + // deduct the change amount from the output amount + if (changeOutput != null) { + totalOutAmount -= changeOutput.value.toInt(); + } + + final txb = BitcoinTransactionBuilder( + utxos: utxos, + outputs: outputs, + fee: BigInt.from(newFee), + network: network, + enableRBF: true, + ); + + final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) { + final key = + privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey); + + if (key == null) { + throw Exception("Cannot find private key"); + } + + if (utxo.utxo.isP2tr()) { + return key.signTapRoot(txDigest, sighash: sighash); + } else { + return key.signInput(txDigest, sigHash: sighash); + } + }); + + return PendingBitcoinTransaction( + transaction, + type, + electrumClient: electrumClient, + amount: totalOutAmount, + fee: newFee, + network: network, + hasChange: changeOutput != null, + feeRate: newFee.toString(), + )..addListener((transaction) async { + transactionHistory.addOne(transaction); + await updateBalance(); + }); + } catch (e) { + throw e; + } + } + + Future getTransactionExpanded({required String hash}) async { String transactionHex; int? time; int confirmations = 0; @@ -826,8 +999,12 @@ abstract class ElectrumWalletBase ins.add(tx); } - return ElectrumTransactionBundle(original, - ins: ins, time: time, confirmations: confirmations, height: height); + return ElectrumTransactionBundle( + original, + ins: ins, + time: time, + confirmations: confirmations, + ); } Future fetchTransactionInfo( @@ -837,7 +1014,7 @@ abstract class ElectrumWalletBase bool? retryOnFailure}) async { try { return ElectrumTransactionInfo.fromElectrumBundle( - await getTransactionExpanded(hash: hash, height: height), walletInfo.type, network, + await getTransactionExpanded(hash: hash), walletInfo.type, network, addresses: myAddresses, height: height); } catch (e) { if (e is FormatException && retryOnFailure == true) { diff --git a/cw_bitcoin/lib/pending_bitcoin_transaction.dart b/cw_bitcoin/lib/pending_bitcoin_transaction.dart index eb4274e78..529ac61da 100644 --- a/cw_bitcoin/lib/pending_bitcoin_transaction.dart +++ b/cw_bitcoin/lib/pending_bitcoin_transaction.dart @@ -17,7 +17,7 @@ class PendingBitcoinTransaction with PendingTransaction { required this.feeRate, this.network, required this.hasChange, - required this.isSendAll, + this.isSendAll = false, this.hasTaprootInputs = false, }) : _listeners = []; diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index b39dcae07..3d828243c 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -70,8 +70,8 @@ packages: dependency: "direct main" description: path: "." - ref: master - resolved-ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11 + ref: Add-Support-For-OP-Return-data + resolved-ref: "57b78afb85bd2c30d3cdb9f7884f3878a62be442" url: "https://github.com/cake-tech/bitbox-flutter.git" source: git version: "1.0.1" diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index bcbb55e11..632a3140a 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: bitbox: git: url: https://github.com/cake-tech/bitbox-flutter.git - ref: master + ref: Add-Support-For-OP-Return-data rxdart: ^0.27.5 unorm_dart: ^0.2.0 cryptography: ^2.0.5 diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index 7130b3c58..37827f1ba 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: bitbox: git: url: https://github.com/cake-tech/bitbox-flutter.git - ref: master + ref: Add-Support-For-OP-Return-data bitcoin_base: git: url: https://github.com/cake-tech/bitcoin_base.git diff --git a/cw_core/lib/transaction_info.dart b/cw_core/lib/transaction_info.dart index 7624b147f..992582ff8 100644 --- a/cw_core/lib/transaction_info.dart +++ b/cw_core/lib/transaction_info.dart @@ -16,6 +16,8 @@ abstract class TransactionInfo extends Object with Keyable { void changeFiatAmount(String amount); String? to; String? from; + List? inputAddresses; + List? outputAddresses; @override dynamic get keyIndex => id; diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart index 49f1bdc94..037a26d38 100644 --- a/cw_core/lib/wallet_base.dart +++ b/cw_core/lib/wallet_base.dart @@ -67,6 +67,7 @@ abstract class WalletBase outputs, - {required TransactionPriority priority, int? feeRate}) => - BitcoinTransactionCredentials( - outputs - .map((out) => OutputInfo( - fiatAmount: out.fiatAmount, - cryptoAmount: out.cryptoAmount, - address: out.address, - note: out.note, - sendAll: out.sendAll, - extractedAddress: out.extractedAddress, - isParsedAddress: out.isParsedAddress, - formattedCryptoAmount: out.formattedCryptoAmount, - memo: out.memo)) - .toList(), - priority: priority as BitcoinTransactionPriority, - feeRate: feeRate); + {required TransactionPriority priority, int? feeRate}) { + final bitcoinFeeRate = + priority == BitcoinTransactionPriority.custom && feeRate != null ? feeRate : null; + return BitcoinTransactionCredentials( + outputs + .map((out) => OutputInfo( + fiatAmount: out.fiatAmount, + cryptoAmount: out.cryptoAmount, + address: out.address, + note: out.note, + sendAll: out.sendAll, + extractedAddress: out.extractedAddress, + isParsedAddress: out.isParsedAddress, + formattedCryptoAmount: out.formattedCryptoAmount, + memo: out.memo)) + .toList(), + priority: priority as BitcoinTransactionPriority, + feeRate: bitcoinFeeRate + ); + } @override Object createBitcoinTransactionCredentialsRaw(List outputs, @@ -172,8 +176,9 @@ class CWBitcoin extends Bitcoin { int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount); @override - String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate) => - (priority as BitcoinTransactionPriority).labelWithRate(rate); + String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate, + {int? customRate}) => + (priority as BitcoinTransactionPriority).labelWithRate(rate, customRate); @override List getUnspents(Object wallet) { @@ -199,6 +204,9 @@ class CWBitcoin extends Bitcoin { @override TransactionPriority getBitcoinTransactionPriorityMedium() => BitcoinTransactionPriority.medium; + @override + TransactionPriority getBitcoinTransactionPriorityCustom() => BitcoinTransactionPriority.custom; + @override TransactionPriority getLitecoinTransactionPriorityMedium() => LitecoinTransactionPriority.medium; @@ -244,4 +252,43 @@ class CWBitcoin extends Bitcoin { bool hasTaprootInput(PendingTransaction pendingTransaction) { return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs; } + + @override + Future replaceByFee( + Object wallet, String transactionHash, String fee) async { + final bitcoinWallet = wallet as ElectrumWallet; + return await bitcoinWallet.replaceByFee(transactionHash, int.parse(fee)); + } + + @override + Future canReplaceByFee(Object wallet, String transactionHash) async { + final bitcoinWallet = wallet as ElectrumWallet; + return bitcoinWallet.canReplaceByFee(transactionHash); + } + + @override + Future isChangeSufficientForFee(Object wallet, String txId, String newFee) async { + final bitcoinWallet = wallet as ElectrumWallet; + return bitcoinWallet.isChangeSufficientForFee(txId, int.parse(newFee)); + } + + @override + int getFeeAmountForPriority( + Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, + {int? size}) { + final bitcoinWallet = wallet as ElectrumWallet; + return bitcoinWallet.feeAmountForPriority( + priority as BitcoinTransactionPriority, inputsCount, outputsCount); + } + + @override + int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, + {int? size}) { + final bitcoinWallet = wallet as ElectrumWallet; + return bitcoinWallet.feeAmountWithFeeRate( + feeRate, + inputsCount, + outputsCount, + ); + } } diff --git a/lib/core/execution_state.dart b/lib/core/execution_state.dart index 18dc81030..6bc906010 100644 --- a/lib/core/execution_state.dart +++ b/lib/core/execution_state.dart @@ -14,4 +14,13 @@ class FailureState extends ExecutionState { FailureState(this.error); final String error; +} + +class AwaitingConfirmationState extends ExecutionState { + AwaitingConfirmationState({this.title, this.message, this.onConfirm, this.onCancel}); + + final String? title; + final String? message; + final Function()? onConfirm; + final Function()? onCancel; } \ No newline at end of file diff --git a/lib/di.dart b/lib/di.dart index 291555330..5262a01e6 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -13,6 +13,7 @@ import 'package:cake_wallet/core/yat_service.dart'; import 'package:cake_wallet/entities/background_tasks.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/parse_address_from_domain.dart'; +import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; import 'package:cw_core/receive_page_option.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/nano/nano.dart'; @@ -914,7 +915,8 @@ Future setup({ transactionInfo: transactionInfo, transactionDescriptionBox: _transactionDescriptionBox, wallet: wallet, - settingsStore: getIt.get()); + settingsStore: getIt.get(), + sendViewModel: getIt.get()); }); getIt.registerFactoryParam( @@ -1137,6 +1139,11 @@ Future setup({ getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get())); + getIt.registerFactoryParam( + (TransactionInfo transactionInfo, _) => RBFDetailsPage( + transactionDetailsViewModel: + getIt.get(param1: transactionInfo))); + getIt.registerFactory(() => AnonPayApi( useTorOnly: getIt.get().exchangeStatus == ExchangeApiMode.torOnly, wallet: getIt.get().wallet!)); diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 5c22455d2..ba6d6ef4f 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -42,6 +42,7 @@ class PreferencesKey { static const ethereumTransactionPriority = 'current_fee_priority_ethereum'; static const polygonTransactionPriority = 'current_fee_priority_polygon'; static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash'; + static const customBitcoinFeeRate = 'custom_electrum_fee_rate'; static const shouldShowReceiveWarning = 'should_show_receive_warning'; static const shouldShowYatPopup = 'should_show_yat_popup'; static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1'; diff --git a/lib/router.dart b/lib/router.dart index ef7b7f31e..9f5dfb838 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -54,6 +54,7 @@ import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart'; import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart'; +import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart'; @@ -253,6 +254,12 @@ Route createRoute(RouteSettings settings) { builder: (_) => getIt.get(param1: settings.arguments as TransactionInfo)); + case Routes.bumpFeePage: + return CupertinoPageRoute( + fullscreenDialog: true, + builder: (_) => + getIt.get(param1: settings.arguments as TransactionInfo)); + case Routes.newSubaddress: return CupertinoPageRoute( builder: (_) => getIt.get(param1: settings.arguments)); diff --git a/lib/routes.dart b/lib/routes.dart index 7ad5c70bc..9c4e21651 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -12,6 +12,7 @@ class Routes { static const dashboard = '/dashboard'; static const send = '/send'; static const transactionDetails = '/transaction_info'; + static const bumpFeePage = '/bump_fee_page'; static const receive = '/receive'; static const newSubaddress = '/new_subaddress'; static const walletEdit = '/walletEdit'; diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 56b1b7af7..970bb31f2 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -100,7 +100,10 @@ class SendPage extends BasePage { AppBarStyle get appBarStyle => AppBarStyle.transparent; double _sendCardHeight(BuildContext context) { - final double initialHeight = sendViewModel.hasCoinControl ? 500 : 465; + double initialHeight = 450; + if (sendViewModel.hasCoinControl) { + initialHeight += 35; + } if (!responsiveLayoutUtil.shouldRenderMobileUI) { return initialHeight - 66; @@ -190,7 +193,7 @@ class SendPage extends BasePage { }, )), Padding( - padding: EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10), + padding: EdgeInsets.only(left: 24, right: 24, bottom: 10), child: Container( height: 10, child: Observer( @@ -456,7 +459,7 @@ class SendPage extends BasePage { ? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' : ''; final newContactMessage = newContactAddress != null - ? '\n${S.of(context).add_contact_to_address_book}' : ''; + ? '\n${S.of(_dialogContext).add_contact_to_address_book}' : ''; final alertContent = "$successMessage$waitMessage$newContactMessage"; diff --git a/lib/src/screens/send/widgets/send_card.dart b/lib/src/screens/send/widgets/send_card.dart index d36997814..7c2bfedd0 100644 --- a/lib/src/screens/send/widgets/send_card.dart +++ b/lib/src/screens/send/widgets/send_card.dart @@ -1,16 +1,17 @@ -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/currency.dart'; -import 'package:cw_core/transaction_priority.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; -import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/view_model/send/output.dart'; +import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -456,7 +457,7 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin GestureDetector( onTap: sendViewModel.hasFeesPriority - ? () => _setTransactionPriority(context) + ? () => pickTransactionPriority(context) : () {}, child: Container( padding: EdgeInsets.only(top: 24), @@ -669,22 +670,41 @@ class SendCardState extends State with AutomaticKeepAliveClientMixin _setTransactionPriority(BuildContext context) async { + Future pickTransactionPriority(BuildContext context) async { final items = priorityForWalletType(sendViewModel.walletType); final selectedItem = items.indexOf(sendViewModel.transactionPriority); + final customItemIndex = sendViewModel.getCustomPriorityIndex(items); + final isBitcoinWallet = sendViewModel.walletType == WalletType.bitcoin; + double? customFeeRate = isBitcoinWallet ? sendViewModel.customBitcoinFeeRate.toDouble() : null; await showPopUp( context: context, - builder: (_) => Picker( - items: items, - displayItem: sendViewModel.displayFeeRate, - selectedAtIndex: selectedItem, - title: S.of(context).please_select, - mainAxisAlignment: MainAxisAlignment.center, - onItemSelected: (TransactionPriority priority) => - sendViewModel.setTransactionPriority(priority), - ), + builder: (BuildContext context) { + int selectedIdx = selectedItem; + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Picker( + items: items, + displayItem: (TransactionPriority priority) => + sendViewModel.displayFeeRate(priority, customFeeRate?.round()), + selectedAtIndex: selectedIdx, + customItemIndex: customItemIndex, + title: S.of(context).please_select, + headerEnabled: !isBitcoinWallet, + closeOnItemSelected: !isBitcoinWallet, + mainAxisAlignment: MainAxisAlignment.center, + sliderValue: customFeeRate, + onSliderChanged: (double newValue) => setState(() => customFeeRate = newValue), + onItemSelected: (TransactionPriority priority) { + sendViewModel.setTransactionPriority(priority); + setState(() => selectedIdx = items.indexOf(priority)); + }, + ); + }, + ); + }, ); + if (isBitcoinWallet) sendViewModel.customBitcoinFeeRate = customFeeRate!.round(); } void _presentPicker(BuildContext context) { diff --git a/lib/src/screens/settings/other_settings_page.dart b/lib/src/screens/settings/other_settings_page.dart index fcf683050..90139e8c4 100644 --- a/lib/src/screens/settings/other_settings_page.dart +++ b/lib/src/screens/settings/other_settings_page.dart @@ -2,11 +2,12 @@ import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart'; -import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -27,13 +28,23 @@ class OtherSettingsPage extends BasePage { child: Column( children: [ if (_otherSettingsViewModel.displayTransactionPriority) - SettingsPickerCell( - title: S.current.settings_fee_priority, - items: priorityForWalletType(_otherSettingsViewModel.walletType), - displayItem: _otherSettingsViewModel.getDisplayPriority, - selectedItem: _otherSettingsViewModel.transactionPriority, - onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected, - ), + _otherSettingsViewModel.walletType == WalletType.bitcoin ? + SettingsPriorityPickerCell( + title: S.current.settings_fee_priority, + items: priorityForWalletType(_otherSettingsViewModel.walletType), + displayItem: _otherSettingsViewModel.getDisplayBitcoinPriority, + selectedItem: _otherSettingsViewModel.transactionPriority, + customItemIndex: _otherSettingsViewModel.customPriorityItemIndex, + onItemSelected: _otherSettingsViewModel.onDisplayBitcoinPrioritySelected, + customValue: _otherSettingsViewModel.customBitcoinFeeRate, + ) : + SettingsPickerCell( + title: S.current.settings_fee_priority, + items: priorityForWalletType(_otherSettingsViewModel.walletType), + displayItem: _otherSettingsViewModel.getDisplayPriority, + selectedItem: _otherSettingsViewModel.transactionPriority, + onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected, + ), if (_otherSettingsViewModel.changeRepresentativeEnabled) SettingsCellWithArrow( title: S.current.change_rep, diff --git a/lib/src/screens/settings/widgets/setting_priority_picker_cell.dart b/lib/src/screens/settings/widgets/setting_priority_picker_cell.dart new file mode 100644 index 000000000..bba44606d --- /dev/null +++ b/lib/src/screens/settings/widgets/setting_priority_picker_cell.dart @@ -0,0 +1,78 @@ +import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/src/widgets/standard_list.dart'; + +class SettingsPriorityPickerCell extends StandardListRow { + SettingsPriorityPickerCell( + {required String title, + required this.selectedItem, + required this.items, + this.displayItem, + this.images, + this.searchHintText, + this.isGridView = false, + this.matchingCriteria, + this.customValue, + this.customItemIndex, + this.onItemSelected}) + : super( + title: title, + isSelected: false, + onTap: (BuildContext context) async { + var selectedAtIndex = items.indexOf(selectedItem); + double sliderValue = customValue ?? 0.0; + + await showPopUp( + context: context, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return Picker( + items: items, + displayItem: (ItemType item) => displayItem!(item, sliderValue.round()), + selectedAtIndex: selectedAtIndex, + customItemIndex: customItemIndex, + headerEnabled: false, + closeOnItemSelected: false, + mainAxisAlignment: MainAxisAlignment.center, + sliderValue: sliderValue, + onSliderChanged: (double newValue) => + setState(() => sliderValue = newValue), + onItemSelected: (ItemType priority) { + setState(() => selectedAtIndex = items.indexOf(priority)); + onItemSelected?.call(priority, sliderValue); + }, + ); + }, + ); + }, + ); + onItemSelected?.call(items[selectedAtIndex], sliderValue); + }); + + final ItemType selectedItem; + final List items; + final void Function(ItemType item, double customValue)? onItemSelected; + final String Function(ItemType item, int value)? displayItem; + final List? images; + final String? searchHintText; + final bool isGridView; + final bool Function(ItemType, String)? matchingCriteria; + double? customValue; + int? customItemIndex; + + @override + Widget buildTrailing(BuildContext context) { + return Text( + displayItem?.call(selectedItem,customValue?.round() ?? 0) ?? selectedItem.toString(), + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.detailsTitlesColor, + ), + ); + } +} diff --git a/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart b/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart new file mode 100644 index 000000000..8f722ee7e --- /dev/null +++ b/lib/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart @@ -0,0 +1,23 @@ +import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; + +class StandardPickerListItem extends TransactionDetailsListItem { + StandardPickerListItem( + {required String title, + required String value, + required this.items, + required this.displayItem, + required this.onSliderChanged, + required this.onItemSelected, + required this.selectedIdx, + required this.customItemIndex, + required this.customValue}) + : super(title: title, value: value); + + final List items; + final String Function(T item, double sliderValue) displayItem; + final Function(double) onSliderChanged; + final Function(T) onItemSelected; + final int selectedIdx; + final int customItemIndex; + double customValue; +} diff --git a/lib/src/screens/transaction_details/rbf_details_page.dart b/lib/src/screens/transaction_details/rbf_details_page.dart new file mode 100644 index 000000000..875e0a4ef --- /dev/null +++ b/lib/src/screens/transaction_details/rbf_details_page.dart @@ -0,0 +1,199 @@ +import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; +import 'package:cake_wallet/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/transaction_expandable_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/list_row.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/standard_expandable_list.dart'; +import 'package:cake_wallet/src/widgets/standard_list.dart'; +import 'package:cake_wallet/src/widgets/standard_picker_list.dart'; +import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/send/send_view_model_state.dart'; +import 'package:cake_wallet/view_model/transaction_details_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; + +class RBFDetailsPage extends BasePage { + RBFDetailsPage({required this.transactionDetailsViewModel}); + + @override + String get title => S.current.bump_fee; + + final TransactionDetailsViewModel transactionDetailsViewModel; + + bool _effectsInstalled = false; + + @override + Widget body(BuildContext context) { + _setEffects(context); + + return Column( + children: [ + Expanded( + child: SectionStandardList( + sectionCount: 1, + itemCounter: (int _) => transactionDetailsViewModel.RBFListItems.length, + itemBuilder: (__, index) { + final item = transactionDetailsViewModel.RBFListItems[index]; + + if (item is StandartListItem) { + return GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData(text: item.value)); + showBar(context, S.of(context).transaction_details_copied(item.title)); + }, + child: ListRow(title: '${item.title}:', value: item.value), + ); + } + + if (item is StandardExpandableListItem) { + return StandardExpandableList( + title: '${item.title}: ${item.expandableItems.length}', + expandableItems: item.expandableItems, + ); + } + + if (item is StandardPickerListItem) { + return StandardPickerList( + title: item.title, + value: item.value, + items: item.items, + displayItem: item.displayItem, + onSliderChanged: item.onSliderChanged, + onItemSelected: item.onItemSelected, + selectedIdx: item.selectedIdx, + customItemIndex: item.customItemIndex, + customValue: item.customValue, + ); + } + + if (item is TextFieldListItem) { + return TextFieldListRow( + title: item.title, + value: item.value, + onSubmitted: item.onSubmitted, + ); + } + + return Container(); + }), + ), + Padding( + padding: const EdgeInsets.all(24), + child: Observer( + builder: (_) => LoadingPrimaryButton( + onPressed: () async { + transactionDetailsViewModel + .replaceByFee(transactionDetailsViewModel.newFee.toString()); + }, + text: S.of(context).send, + isLoading: + transactionDetailsViewModel.sendViewModel.state is IsExecutingState, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + ))), + ], + ); + } + + void _setEffects(BuildContext context) { + if (_effectsInstalled) { + return; + } + + reaction((_) => transactionDetailsViewModel.sendViewModel.state, (ExecutionState state) { + if (state is FailureState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showPopUp( + context: context, + builder: (BuildContext popupContext) { + return AlertWithOneAction( + alertTitle: S.of(popupContext).error, + alertContent: state.error, + buttonText: S.of(popupContext).ok, + buttonAction: () => Navigator.of(popupContext).pop()); + }); + }); + } + if (state is AwaitingConfirmationState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showPopUp( + context: context, + builder: (BuildContext popupContext) { + return AlertWithTwoActions( + alertTitle: state.title ?? '', + alertContent: state.message ?? '', + rightButtonText: S.of(context).ok, + leftButtonText: S.of(context).cancel, + actionRightButton: () { + state.onConfirm?.call(); + Navigator.of(popupContext).pop(); + }, + actionLeftButton: () { + state.onCancel?.call(); + Navigator.of(popupContext).pop(); + }); + }); + }); + } + + if (state is ExecutedSuccessfullyState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showPopUp( + context: context, + builder: (BuildContext popupContext) { + return ConfirmSendingAlert( + alertTitle: S.of(popupContext).confirm_sending, + amount: S.of(popupContext).send_amount, + amountValue: transactionDetailsViewModel + .sendViewModel.pendingTransaction!.amountFormatted, + fee: S.of(popupContext).send_fee, + feeValue: + transactionDetailsViewModel.sendViewModel.pendingTransaction!.feeFormatted, + rightButtonText: S.of(popupContext).send, + leftButtonText: S.of(popupContext).cancel, + actionRightButton: () async { + Navigator.of(popupContext).pop(); + await transactionDetailsViewModel.sendViewModel.commitTransaction(); + // transactionStatePopup(); + }, + actionLeftButton: () => Navigator.of(popupContext).pop(), + feeFiatAmount: + transactionDetailsViewModel.pendingTransactionFeeFiatAmountFormatted, + fiatAmountValue: + transactionDetailsViewModel.pendingTransactionFiatAmountValueFormatted, + outputs: transactionDetailsViewModel.sendViewModel.outputs); + }); + }); + } + + if (state is TransactionCommitted) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (context.mounted) { + showPopUp( + context: context, + builder: (BuildContext popupContext) { + return AlertWithOneAction( + alertTitle: S.of(popupContext).sending, + alertContent: S.of(popupContext).transaction_sent, + buttonText: S.of(popupContext).ok, + buttonAction: () => Navigator.of(popupContext).pop()); + }); + } + }); + } + }); + + _effectsInstalled = true; + } +} diff --git a/lib/src/screens/transaction_details/transaction_details_page.dart b/lib/src/screens/transaction_details/transaction_details_page.dart index a6f60a52d..7734f37ed 100644 --- a/lib/src/screens/transaction_details/transaction_details_page.dart +++ b/lib/src/screens/transaction_details/transaction_details_page.dart @@ -1,15 +1,18 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart'; +import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart'; +import 'package:cake_wallet/src/widgets/list_row.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/view_model/transaction_details_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/widgets/list_row.dart'; -import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; -import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; class TransactionDetailsPage extends BasePage { TransactionDetailsPage({required this.transactionDetailsViewModel}); @@ -21,41 +24,62 @@ class TransactionDetailsPage extends BasePage { @override Widget body(BuildContext context) { - return SectionStandardList( - sectionCount: 1, - itemCounter: (int _) => transactionDetailsViewModel.items.length, - itemBuilder: (__, index) { - final item = transactionDetailsViewModel.items[index]; + return Column( + children: [ + Expanded( + child: SectionStandardList( + sectionCount: 1, + itemCounter: (int _) => transactionDetailsViewModel.items.length, + itemBuilder: (__, index) { + final item = transactionDetailsViewModel.items[index]; - if (item is StandartListItem) { - return GestureDetector( - onTap: () { - Clipboard.setData(ClipboardData(text: item.value)); - showBar(context, - S.of(context).transaction_details_copied(item.title)); - }, - child: - ListRow(title: '${item.title}:', value: item.value), - ); - } + if (item is StandartListItem) { + return GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData(text: item.value)); + showBar(context, S.of(context).transaction_details_copied(item.title)); + }, + child: ListRow(title: '${item.title}:', value: item.value), + ); + } - if (item is BlockExplorerListItem) { - return GestureDetector( - onTap: item.onTap, - child: - ListRow(title: '${item.title}:', value: item.value), - ); - } + if (item is BlockExplorerListItem) { + return GestureDetector( + onTap: item.onTap, + child: ListRow(title: '${item.title}:', value: item.value), + ); + } - if (item is TextFieldListItem) { - return TextFieldListRow( - title: item.title, - value: item.value, - onSubmitted: item.onSubmitted, - ); - } + if (item is TextFieldListItem) { + return TextFieldListRow( + title: item.title, + value: item.value, + onSubmitted: item.onSubmitted, + ); + } - return Container(); - }); + return Container(); + }), + ), + Observer( + builder: (_) { + if (transactionDetailsViewModel.canReplaceByFee) { + return Padding( + padding: const EdgeInsets.all(24), + child: SelectButton( + text: S.of(context).bump_fee, + onTap: () async { + Navigator.of(context).pushNamed(Routes.bumpFeePage, + arguments: transactionDetailsViewModel.transactionInfo); + }, + ), + ); + } + + return const SizedBox(); + }, + ), + ], + ); } } diff --git a/lib/src/screens/transaction_details/transaction_expandable_list_item.dart b/lib/src/screens/transaction_details/transaction_expandable_list_item.dart new file mode 100644 index 000000000..e87405de3 --- /dev/null +++ b/lib/src/screens/transaction_details/transaction_expandable_list_item.dart @@ -0,0 +1,7 @@ +import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; + +class StandardExpandableListItem extends TransactionDetailsListItem { + StandardExpandableListItem({required String title, required this.expandableItems}) + : super(title: title, value: ''); + final List expandableItems; +} diff --git a/lib/src/widgets/checkbox_widget.dart b/lib/src/widgets/checkbox_widget.dart index 1ea3ee698..a3c78d0cf 100644 --- a/lib/src/widgets/checkbox_widget.dart +++ b/lib/src/widgets/checkbox_widget.dart @@ -31,7 +31,6 @@ class CheckboxWidgetState extends State { }, child: Row( mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 24.0, diff --git a/lib/src/widgets/picker.dart b/lib/src/widgets/picker.dart index 01b869b1b..d87b5721e 100644 --- a/lib/src/widgets/picker.dart +++ b/lib/src/widgets/picker.dart @@ -24,6 +24,13 @@ class Picker extends StatefulWidget { this.isGridView = false, this.isSeparated = true, this.hintText, + this.headerEnabled = true, + this.closeOnItemSelected = true, + this.sliderValue, + this.customItemIndex, + this.isWrapped = true, + this.borderColor, + this.onSliderChanged, this.matchingCriteria, }) : assert(hintText == null || matchingCriteria != @@ -40,6 +47,13 @@ class Picker extends StatefulWidget { final bool isGridView; final bool isSeparated; final String? hintText; + final bool headerEnabled; + final bool closeOnItemSelected; + final double? sliderValue; + final int? customItemIndex; + final bool isWrapped; + final Color? borderColor; + final Function(double)? onSliderChanged; final bool Function(Item, String)? matchingCriteria; @override @@ -124,8 +138,7 @@ class _PickerState extends State> { containerHeight = height * 0.75; } - return PickerWrapperWidget( - hasTitle: widget.title?.isNotEmpty ?? false, + final content = Column ( children: [ if (widget.title?.isNotEmpty ?? false) Container( @@ -144,61 +157,71 @@ class _PickerState extends State> { ), Padding( padding: EdgeInsets.symmetric(horizontal: padding), - child: ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(30)), - child: Container( - color: Theme.of(context).dialogTheme.backgroundColor, - child: ConstrainedBox( - constraints: BoxConstraints( - maxHeight: containerHeight, - maxWidth: ResponsiveLayoutUtilBase.kPopupWidth, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.hintText != null) - Padding( - padding: const EdgeInsets.all(16), - child: SearchBarWidget(searchController: searchController), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(30), + border: Border.all( + color: widget.borderColor ?? Colors.transparent, + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(30)), + child: Container( + color: Theme.of(context).dialogTheme.backgroundColor, + child: ConstrainedBox( + constraints: BoxConstraints( + maxHeight: containerHeight, + maxWidth: ResponsiveLayoutUtilBase.kPopupWidth, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.hintText != null) + Padding( + padding: const EdgeInsets.all(16), + child: SearchBarWidget( + searchController: searchController, hintText: widget.hintText), + ), + Divider( + color: Theme.of(context).extension()!.dividerColor, + height: 1, ), - Divider( - color: Theme.of(context).extension()!.dividerColor, - height: 1, - ), - if (widget.selectedAtIndex != -1) buildSelectedItem(widget.selectedAtIndex), - Flexible( - child: Stack( - alignment: Alignment.center, - children: [ - filteredItems.length > 3 - ? Scrollbar( - controller: controller, - child: itemsList(), - ) - : itemsList(), - (widget.description?.isNotEmpty ?? false) - ? Positioned( - bottom: padding, - left: padding, - right: padding, - child: Text( - widget.description!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - fontFamily: 'Lato', - decoration: TextDecoration.none, - color: - Theme.of(context).extension()!.titleColor, + if (widget.selectedAtIndex != -1 && widget.headerEnabled) + buildSelectedItem(widget.selectedAtIndex), + Flexible( + child: Stack( + alignment: Alignment.center, + children: [ + filteredItems.length > 3 + ? Scrollbar( + controller: controller, + child: itemsList(), + ) + : itemsList(), + (widget.description?.isNotEmpty ?? false) + ? Positioned( + bottom: padding, + left: padding, + right: padding, + child: Text( + widget.description!, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + fontFamily: 'Lato', + decoration: TextDecoration.none, + color: + Theme.of(context).extension()!.titleColor, + ), ), - ), - ) - : Offstage(), - ], + ) + : Offstage(), + ], + ), ), - ), - ], + ], + ), ), ), ), @@ -206,9 +229,23 @@ class _PickerState extends State> { ) ], ); + + if (widget.isWrapped) { + return PickerWrapperWidget( + hasTitle: widget.title?.isNotEmpty ?? false, + children: [content], + ); + } else { + return content; + } } Widget itemsList() { + final itemCount = !widget.headerEnabled + ? items.length + : filteredItems.isEmpty + ? 0 + : filteredItems.length; return Container( color: Theme.of(context).extension()!.dividerColor, child: widget.isGridView @@ -216,13 +253,16 @@ class _PickerState extends State> { padding: EdgeInsets.zero, controller: controller, shrinkWrap: true, - itemCount: filteredItems.isEmpty ? 0 : filteredItems.length, + itemCount: itemCount, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 2, childAspectRatio: 3, ), - itemBuilder: (context, index) => buildItem(index), + itemBuilder: (context, index) => + !widget.headerEnabled && widget.selectedAtIndex == index + ? buildSelectedItem(index) + : buildItem(index), ) : ListView.separated( padding: EdgeInsets.zero, @@ -234,83 +274,97 @@ class _PickerState extends State> { height: 1, ) : const SizedBox(), - itemCount: filteredItems.isEmpty ? 0 : filteredItems.length, - itemBuilder: (context, index) => buildItem(index), + itemCount: itemCount, + itemBuilder: (context, index) => + !widget.headerEnabled && widget.selectedAtIndex == index + ? buildSelectedItem(index) + : buildItem(index), ), ); } Widget buildItem(int index) { - final item = filteredItems[index]; + final item = widget.headerEnabled ? filteredItems[index] : items[index]; final tag = item is Currency ? item.tag : null; final icon = _getItemIcon(item); final image = images.isNotEmpty ? filteredImages[index] : icon; + final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex; + + final itemContent = Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: widget.mainAxisAlignment, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image ?? Offstage(), + Expanded( + child: Padding( + padding: EdgeInsets.only(left: image != null ? 12 : 0), + child: Row( + children: [ + Flexible( + child: Text( + widget.displayItem?.call(item) ?? item.toString(), + softWrap: true, + style: TextStyle( + fontSize: 14, + fontFamily: 'Lato', + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ), + ), + if (tag != null) + Align( + alignment: Alignment.topCenter, + child: Container( + width: 35.0, + height: 18.0, + child: Center( + child: Text( + tag, + style: TextStyle( + fontSize: 7.0, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.thumbColor, + ), + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.0), + //border: Border.all(color: ), + color: Theme.of(context).extension()!.trackColor, + ), + ), + ), + ], + ), + ), + ), + ], + ); + return GestureDetector( onTap: () { - Navigator.of(context).pop(); + if (widget.closeOnItemSelected) Navigator.of(context).pop(); onItemSelected(item!); }, child: Container( - height: 55, + height: isCustomItem ? 95 : 55, color: Theme.of(context).dialogTheme.backgroundColor, padding: EdgeInsets.symmetric(horizontal: 24), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: widget.mainAxisAlignment, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image ?? Offstage(), - Expanded( - child: Padding( - padding: EdgeInsets.only(left: image != null ? 12 : 0), - child: Row( - children: [ - Flexible( - child: Text( - widget.displayItem?.call(item) ?? item.toString(), - softWrap: true, - style: TextStyle( - fontSize: 14, - fontFamily: 'Lato', - fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.titleColor, - decoration: TextDecoration.none, - ), - ), - ), - if (tag != null) - Align( - alignment: Alignment.topCenter, - child: Container( - width: 35.0, - height: 18.0, - child: Center( - child: Text( - tag, - style: TextStyle( - fontSize: 7.0, - fontFamily: 'Lato', - color: - Theme.of(context).extension()!.thumbColor, - ), - ), - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.0), - //border: Border.all(color: ), - color: Theme.of(context).extension()!.trackColor, - ), - ), - ), - ], - ), - ), - ), - ], - ), + child: isCustomItem + ? Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + itemContent, + buildSlider(index: index, isActivated: widget.selectedAtIndex == index) + ], + ) + : itemContent, ), ); } @@ -323,69 +377,80 @@ class _PickerState extends State> { final image = images.isNotEmpty ? images[index] : icon; - return GestureDetector( - onTap: () { - Navigator.of(context).pop(); - }, - child: Container( - height: 55, - color: Theme.of(context).dialogTheme.backgroundColor, - padding: EdgeInsets.symmetric(horizontal: 24), - child: Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: widget.mainAxisAlignment, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - image ?? Offstage(), - Expanded( - child: Padding( - padding: EdgeInsets.only(left: image != null ? 12 : 0), - child: Row( - children: [ - Flexible( - child: Text( - widget.displayItem?.call(item) ?? item.toString(), - softWrap: true, - style: TextStyle( - fontSize: 16, - fontFamily: 'Lato', - fontWeight: FontWeight.w700, - color: Theme.of(context).extension()!.titleColor, - decoration: TextDecoration.none, + final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex; + + final itemContent = Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: widget.mainAxisAlignment, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + image ?? Offstage(), + Expanded( + child: Padding( + padding: EdgeInsets.only(left: image != null ? 12 : 0), + child: Row( + children: [ + Flexible( + child: Text( + widget.displayItem?.call(item) ?? item.toString(), + softWrap: true, + style: TextStyle( + fontSize: 16, + fontFamily: 'Lato', + fontWeight: FontWeight.w700, + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ), + ), + if (tag != null) + Align( + alignment: Alignment.topCenter, + child: Container( + width: 35.0, + height: 18.0, + child: Center( + child: Text( + tag, + style: TextStyle( + fontSize: 7.0, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.thumbColor, + ), ), ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6.0), + //border: Border.all(color: ), + color: Theme.of(context).extension()!.trackColor, + ), ), - if (tag != null) - Align( - alignment: Alignment.topCenter, - child: Container( - width: 35.0, - height: 18.0, - child: Center( - child: Text( - tag, - style: TextStyle( - fontSize: 7.0, - fontFamily: 'Lato', - color: - Theme.of(context).extension()!.thumbColor, - ), - ), - ), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6.0), - //border: Border.all(color: ), - color: Theme.of(context).extension()!.trackColor, - ), - ), - ), - ], - ), - ), + ), + ], ), - Icon(Icons.check_circle, color: Theme.of(context).primaryColor), - ], + ), ), + Icon(Icons.check_circle, color: Theme.of(context).primaryColor), + ], + ); + + return GestureDetector( + onTap: () { + if (widget.closeOnItemSelected) Navigator.of(context).pop(); + }, + child: Container( + height: isCustomItem ? 95 : 55, + color: Theme.of(context).dialogTheme.backgroundColor, + padding: EdgeInsets.symmetric(horizontal: 24), + child: isCustomItem + ? Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + itemContent, + buildSlider(index: index, isActivated: widget.selectedAtIndex == index) + ], + ) + : itemContent, ), ); } @@ -418,4 +483,20 @@ class _PickerState extends State> { return null; } + + Widget buildSlider({required int index, required bool isActivated}) { + return Row( + children: [ + Expanded( + child: Slider( + value: widget.sliderValue ?? 1, + onChanged: isActivated ? widget.onSliderChanged : null, + min: 1, + max: 100, + divisions: 100, + ), + ), + ], + ); + } } diff --git a/lib/src/widgets/search_bar_widget.dart b/lib/src/widgets/search_bar_widget.dart index dc604934f..45155b380 100644 --- a/lib/src/widgets/search_bar_widget.dart +++ b/lib/src/widgets/search_bar_widget.dart @@ -19,7 +19,7 @@ class SearchBarWidget extends StatelessWidget { controller: searchController, style: TextStyle(color: Theme.of(context).extension()!.searchHintColor), decoration: InputDecoration( - hintText: hintText ?? S.of(context).search_currency, + hintText: hintText ?? S.of(context).search, hintStyle: TextStyle(color: Theme.of(context).extension()!.searchHintColor), prefixIcon: Image.asset("assets/images/search_icon.png", color: Theme.of(context).extension()!.searchIconColor), diff --git a/lib/src/widgets/standard_expandable_list.dart b/lib/src/widgets/standard_expandable_list.dart new file mode 100644 index 000000000..d1bcae646 --- /dev/null +++ b/lib/src/widgets/standard_expandable_list.dart @@ -0,0 +1,58 @@ +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; +import 'package:flutter/material.dart'; + +class StandardExpandableList extends StatelessWidget { + StandardExpandableList({ + required this.title, + required this.expandableItems, + this.decoration, + }); + + final String title; + final List expandableItems; + final Decoration? decoration; + + @override + Widget build(BuildContext context) { + return Container( + decoration: decoration ?? + BoxDecoration( + color: Theme.of(context).colorScheme.background, + ), + child: Theme( + data: Theme.of(context).copyWith(dividerColor: Colors.transparent), + child: ExpansionTile( + iconColor: Theme.of(context).extension()!.detailsTitlesColor, + collapsedIconColor: + Theme.of(context).extension()!.detailsTitlesColor, + title: Text( + title, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.detailsTitlesColor, + ), + textAlign: TextAlign.left, + ), + children: expandableItems.map((item) { + return Padding( + padding: const EdgeInsets.only(left: 16.0, bottom: 8.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + item.toString(), + maxLines: 1, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.titleColor), + ), + ), + ); + }).toList(), + ), + ), + ); + } +} diff --git a/lib/src/widgets/standard_picker_list.dart b/lib/src/widgets/standard_picker_list.dart new file mode 100644 index 000000000..eb1d16900 --- /dev/null +++ b/lib/src/widgets/standard_picker_list.dart @@ -0,0 +1,81 @@ +import 'package:cake_wallet/src/widgets/list_row.dart'; +import 'package:cake_wallet/src/widgets/picker.dart'; +import 'package:cake_wallet/themes/extensions/picker_theme.dart'; +import 'package:flutter/material.dart'; + +class StandardPickerList extends StatefulWidget { + StandardPickerList({ + Key? key, + required this.title, + required this.value, + required this.items, + required this.displayItem, + required this.onSliderChanged, + required this.onItemSelected, + required this.selectedIdx, + required this.customItemIndex, + required this.customValue, + }) : super(key: key); + + final String title; + final List items; + final int customItemIndex; + final String Function(T item, double sliderValue) displayItem; + final Function(double) onSliderChanged; + final Function(T) onItemSelected; + final String value; + final int selectedIdx; + final double customValue; + + @override + _StandardPickerListState createState() => _StandardPickerListState(); +} + +class _StandardPickerListState extends State> { + late String value; + late int selectedIdx; + late double customValue; + + @override + void initState() { + super.initState(); + + value = widget.value; + selectedIdx = widget.selectedIdx; + customValue = widget.customValue; + } + + @override + Widget build(BuildContext context) { + String adaptedDisplayItem(T item) => widget.displayItem(item, customValue); + + return Column( + children: [ + ListRow(title: '${widget.title}:', value: value), + Padding( + padding: const EdgeInsets.only(left: 24, right: 24, top: 0, bottom: 24), + child: Picker( + items: widget.items, + displayItem: adaptedDisplayItem, + selectedAtIndex: selectedIdx, + customItemIndex: widget.customItemIndex, + headerEnabled: false, + closeOnItemSelected: false, + mainAxisAlignment: MainAxisAlignment.center, + sliderValue: customValue, + isWrapped: false, + borderColor: Theme.of(context).extension()!.dividerColor, + onSliderChanged: (newValue) { + setState(() => customValue = newValue); + value = widget.onSliderChanged(newValue).toString(); + }, + onItemSelected: (T item) { + setState(() => selectedIdx = widget.items.indexOf(item)); + value = widget.onItemSelected(item).toString(); + }, + ), + ), + ], + ); + } +} diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index 9997e2675..df2b438b4 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -105,6 +105,7 @@ abstract class SettingsStoreBase with Store { required this.lookupsUnstoppableDomains, required this.lookupsOpenAlias, required this.lookupsENS, + required this.customBitcoinFeeRate, TransactionPriority? initialBitcoinTransactionPriority, TransactionPriority? initialMoneroTransactionPriority, TransactionPriority? initialHavenTransactionPriority, @@ -504,6 +505,11 @@ abstract class SettingsStoreBase with Store { (PinCodeRequiredDuration pinCodeInterval) => secureStorage.write( key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString())); + reaction( + (_) => customBitcoinFeeRate, + (int customBitcoinFeeRate) => + _sharedPreferences.setInt(PreferencesKey.customBitcoinFeeRate, customBitcoinFeeRate)); + this.nodes.observe((change) { if (change.newValue != null && change.key != null) { _saveCurrentNode(change.newValue!, change.key!); @@ -690,6 +696,9 @@ abstract class SettingsStoreBase with Store { String deviceName; + @observable + int customBitcoinFeeRate; + final FlutterSecureStorage _secureStorage; final SharedPreferences _sharedPreferences; final BackgroundTasks _backgroundTasks; @@ -834,6 +843,7 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true; final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true; final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true; + final customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1; // If no value if (pinLength == null || pinLength == 0) { @@ -1068,6 +1078,7 @@ abstract class SettingsStoreBase with Store { lookupsUnstoppableDomains: lookupsUnstoppableDomains, lookupsOpenAlias: lookupsOpenAlias, lookupsENS: lookupsENS, + customBitcoinFeeRate: customBitcoinFeeRate, initialMoneroTransactionPriority: moneroTransactionPriority, initialBitcoinTransactionPriority: bitcoinTransactionPriority, initialHavenTransactionPriority: havenTransactionPriority, @@ -1159,7 +1170,8 @@ abstract class SettingsStoreBase with Store { isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure; disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy; disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell; - disableBulletin = sharedPreferences.getBool(PreferencesKey.disableBulletinKey) ?? disableBulletin; + disableBulletin = + sharedPreferences.getBool(PreferencesKey.disableBulletinKey) ?? disableBulletin; walletListOrder = WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0]; walletListAscending = sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true; @@ -1200,7 +1212,7 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true; lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true; lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true; - + customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1; final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); final bitcoinElectrumServerId = sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); diff --git a/lib/view_model/send/output.dart b/lib/view_model/send/output.dart index 62db9cbcd..6bb3fbb31 100644 --- a/lib/view_model/send/output.dart +++ b/lib/view_model/send/output.dart @@ -121,11 +121,19 @@ abstract class OutputBase with Store { return solana!.getEstimateFees(_wallet) ?? 0.0; } - final fee = _wallet.calculateEstimatedFee( + int? fee = _wallet.calculateEstimatedFee( _settingsStore.priority[_wallet.type]!, formattedCryptoAmount); - if (_wallet.type == WalletType.bitcoin || - _wallet.type == WalletType.litecoin || + if (_wallet.type == WalletType.bitcoin) { + if (_settingsStore.priority[_wallet.type] == bitcoin!.getBitcoinTransactionPriorityCustom()) { + fee = bitcoin!.getFeeAmountWithFeeRate( + _settingsStore.customBitcoinFeeRate, formattedCryptoAmount, 1, 1); + } + + return bitcoin!.formatterBitcoinAmountToDouble(amount: fee); + } + + if (_wallet.type == WalletType.litecoin || _wallet.type == WalletType.bitcoinCash) { return bitcoin!.formatterBitcoinAmountToDouble(amount: fee); } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index df1c75def..28cd0128f 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -39,6 +39,7 @@ import 'package:cake_wallet/entities/parsed_address.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:collection/collection.dart'; part 'send_view_model.g.dart'; @@ -68,9 +69,12 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor _settingsStore = appStore.settingsStore, fiatFromSettings = appStore.settingsStore.fiatCurrency, super(appStore: appStore) { + if (wallet.type == WalletType.bitcoin && + _settingsStore.priority[wallet.type] == bitcoinTransactionPriorityCustom) { + setTransactionPriority(bitcoinTransactionPriorityMedium); + } final priority = _settingsStore.priority[wallet.type]; final priorities = priorityForWalletType(wallet.type); - if (!priorityForWalletType(wallet.type).contains(priority) && priorities.isNotEmpty) { _settingsStore.priority[wallet.type] = priorities.first; } @@ -152,6 +156,21 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor return priority; } + + int? getCustomPriorityIndex(List priorities) { + if (wallet.type == WalletType.bitcoin) { + final customItem = priorities.firstWhereOrNull((element) => element == bitcoin!.getBitcoinTransactionPriorityCustom()); + + return customItem != null ? priorities.indexOf(customItem) : null; + } + return null; + } + + @computed + int get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate; + + void set customBitcoinFeeRate(int value) => _settingsStore.customBitcoinFeeRate = value; + CryptoCurrency get currency => wallet.currency; Validator get amountValidator => @@ -323,6 +342,29 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor return null; } + @action + Future replaceByFee(String txId, String newFee) async { + state = IsExecutingState(); + + final isSufficient = await bitcoin!.isChangeSufficientForFee(wallet, txId, newFee); + + if (!isSufficient) { + state = AwaitingConfirmationState( + title: S.current.confirm_fee_deduction, + message: S.current.confirm_fee_deduction_content, + onConfirm: () async { + pendingTransaction = await bitcoin!.replaceByFee(wallet, txId, newFee); + state = ExecutedSuccessfullyState(); + }, + onCancel: () { + state = FailureState('Insufficient change for fee'); + }); + } else { + pendingTransaction = await bitcoin!.replaceByFee(wallet, txId, newFee); + state = ExecutedSuccessfullyState(); + } + } + @action Future commitTransaction() async { if (pendingTransaction == null) { @@ -380,7 +422,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor case WalletType.bitcoin: case WalletType.litecoin: case WalletType.bitcoinCash: - return bitcoin!.createBitcoinTransactionCredentials(outputs, priority: priority!); + return bitcoin!.createBitcoinTransactionCredentials(outputs, + priority: priority!, feeRate: customBitcoinFeeRate); case WalletType.monero: return monero! @@ -406,9 +449,14 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor } } - String displayFeeRate(dynamic priority) { + String displayFeeRate(dynamic priority, int? customValue) { final _priority = priority as TransactionPriority; + if (walletType == WalletType.bitcoin) { + final rate = bitcoin!.getFeeRate(wallet, _priority); + return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate, customRate: customValue); + } + if (isElectrumWallet) { final rate = bitcoin!.getFeeRate(wallet, _priority); return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate); @@ -420,6 +468,12 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor bool _isEqualCurrency(String currency) => wallet.balance.keys.any((e) => currency.toLowerCase() == e.title.toLowerCase()); + TransactionPriority get bitcoinTransactionPriorityCustom => + bitcoin!.getBitcoinTransactionPriorityCustom(); + + TransactionPriority get bitcoinTransactionPriorityMedium => + bitcoin!.getBitcoinTransactionPriorityMedium(); + @action void onClose() => _settingsStore.fiatCurrency = fiatFromSettings; diff --git a/lib/view_model/settings/other_settings_view_model.dart b/lib/view_model/settings/other_settings_view_model.dart index 263532d29..cf410a1a9 100644 --- a/lib/view_model/settings/other_settings_view_model.dart +++ b/lib/view_model/settings/other_settings_view_model.dart @@ -11,6 +11,7 @@ import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; import 'package:package_info/package_info.dart'; +import 'package:collection/collection.dart'; part 'other_settings_view_model.g.dart'; @@ -77,6 +78,8 @@ abstract class OtherSettingsViewModelBase with Store { ProviderType get sellProviderType => _settingsStore.defaultSellProviders[walletType] ?? ProviderType.askEachTime; + + String getDisplayPriority(dynamic priority) { final _priority = priority as TransactionPriority; @@ -90,6 +93,19 @@ abstract class OtherSettingsViewModelBase with Store { return priority.toString(); } + String getDisplayBitcoinPriority(dynamic priority, int customValue) { + final _priority = priority as TransactionPriority; + + if (_wallet.type == WalletType.bitcoin || + _wallet.type == WalletType.litecoin || + _wallet.type == WalletType.bitcoinCash) { + final rate = bitcoin!.getFeeRate(_wallet, _priority); + return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate, customRate: customValue); + } + + return priority.toString(); + } + String getBuyProviderType(dynamic buyProviderType) { final _buyProviderType = buyProviderType as ProviderType; return _buyProviderType == ProviderType.askEachTime @@ -105,7 +121,24 @@ abstract class OtherSettingsViewModelBase with Store { } void onDisplayPrioritySelected(TransactionPriority priority) => - _settingsStore.priority[_wallet.type] = priority; + _settingsStore.priority[walletType] = priority; + + void onDisplayBitcoinPrioritySelected(TransactionPriority priority, double customValue) { + if (_wallet.type == WalletType.bitcoin) { + _settingsStore.customBitcoinFeeRate = customValue.round(); + } + _settingsStore.priority[_wallet.type] = priority; + } + + @computed + double get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate.toDouble(); + + int? get customPriorityItemIndex { + final priorities = priorityForWalletType(walletType); + final customItem = priorities + .firstWhereOrNull((element) => element == bitcoin!.getBitcoinTransactionPriorityCustom()); + return customItem != null ? priorities.indexOf(customItem) : null; + } @action ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) => diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart index 1b1ceb814..fd6d3ef6e 100644 --- a/lib/view_model/transaction_details_view_model.dart +++ b/lib/view_model/transaction_details_view_model.dart @@ -1,20 +1,27 @@ -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/wallet_type.dart'; +import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; +import 'package:cake_wallet/entities/transaction_description.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/monero/monero.dart'; +import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; +import 'package:cake_wallet/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; -import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; -import 'package:cw_core/transaction_direction.dart'; +import 'package:cake_wallet/src/screens/transaction_details/transaction_expandable_list_item.dart'; +import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; -import 'package:cake_wallet/entities/transaction_description.dart'; +import 'package:cake_wallet/view_model/send/send_view_model.dart'; +import 'package:collection/collection.dart'; +import 'package:cw_core/transaction_direction.dart'; +import 'package:cw_core/transaction_info.dart'; +import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/wallet_base.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:hive/hive.dart'; import 'package:intl/src/intl/date_format.dart'; import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/store/settings_store.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:cake_wallet/monero/monero.dart'; part 'transaction_details_view_model.g.dart'; @@ -26,8 +33,11 @@ abstract class TransactionDetailsViewModelBase with Store { {required this.transactionInfo, required this.transactionDescriptionBox, required this.wallet, - required this.settingsStore}) + required this.settingsStore, + required this.sendViewModel}) : items = [], + RBFListItems = [], + newFee = 0, isRecipientAddressShown = false, showRecipientAddress = settingsStore.shouldSaveRecipientAddress { final dateFormat = DateFormatter.withCurrentLocal(); @@ -38,6 +48,10 @@ abstract class TransactionDetailsViewModelBase with Store { _addMoneroListItems(tx, dateFormat); break; case WalletType.bitcoin: + _addElectrumListItems(tx, dateFormat); + _addBumpFeesListItems(tx); + _checkForRBF(); + break; case WalletType.litecoin: case WalletType.bitcoinCash: _addElectrumListItems(tx, dateFormat); @@ -109,10 +123,20 @@ abstract class TransactionDetailsViewModelBase with Store { final Box transactionDescriptionBox; final SettingsStore settingsStore; final WalletBase wallet; + final SendViewModel sendViewModel; final List items; + final List RBFListItems; bool showRecipientAddress; bool isRecipientAddressShown; + int newFee; + TransactionPriority? transactionPriority; + + @observable + bool _canReplaceByFee = false; + + @computed + bool get canReplaceByFee => _canReplaceByFee /*&& transactionInfo.confirmations <= 0*/; String _explorerUrl(WalletType type, String txId) { switch (type) { @@ -305,4 +329,88 @@ abstract class TransactionDetailsViewModelBase with Store { items.addAll(_items); } + + void _addBumpFeesListItems(TransactionInfo tx) { + transactionPriority = bitcoin!.getBitcoinTransactionPriorityMedium(); + + newFee = bitcoin!.getFeeAmountForPriority( + wallet, + bitcoin!.getBitcoinTransactionPriorityMedium(), + transactionInfo.inputAddresses?.length ?? 1, + transactionInfo.outputAddresses?.length ?? 1); + + RBFListItems.add(StandartListItem( + title: S.current.old_fee, + value: tx.feeFormatted() ?? '0.0')); + + final priorities = priorityForWalletType(wallet.type); + final selectedItem = priorities.indexOf(sendViewModel.transactionPriority); + final customItem = priorities.firstWhereOrNull( + (element) => element == sendViewModel.bitcoinTransactionPriorityCustom); + final customItemIndex = customItem != null ? priorities.indexOf(customItem) : null; + + RBFListItems.add(StandardPickerListItem( + title: S.current.estimated_new_fee, + value: bitcoin!.formatterBitcoinAmountToString(amount: newFee) + ' ${walletTypeToCryptoCurrency(wallet.type)}', + items: priorityForWalletType(wallet.type), + customValue: settingsStore.customBitcoinFeeRate.toDouble(), + selectedIdx: selectedItem, + customItemIndex: customItemIndex ?? 0, + displayItem: (dynamic priority, double sliderValue) => + sendViewModel.displayFeeRate(priority, sliderValue.round()), + onSliderChanged: (double newValue) => + setNewFee(value: newValue, priority: transactionPriority!), + onItemSelected: (dynamic item) { + transactionPriority = item as TransactionPriority; + return setNewFee(priority: transactionPriority!); + })); + + if (transactionInfo.inputAddresses != null) { + RBFListItems.add(StandardExpandableListItem( + title: S.current.inputs, expandableItems: transactionInfo.inputAddresses!)); + } + + if (transactionInfo.outputAddresses != null) { + RBFListItems.add(StandardExpandableListItem( + title: S.current.outputs, expandableItems: transactionInfo.outputAddresses!)); + } + } + + @action + Future _checkForRBF() async { + if (wallet.type == WalletType.bitcoin && + transactionInfo.direction == TransactionDirection.outgoing) { + if (await bitcoin!.canReplaceByFee(wallet, transactionInfo.id)) { + _canReplaceByFee = true; + } + } + } + + String setNewFee({double? value, required TransactionPriority priority}) { + newFee = priority == bitcoin!.getBitcoinTransactionPriorityCustom() && value != null + ? bitcoin!.getFeeAmountWithFeeRate( + wallet, + value.round(), + transactionInfo.inputAddresses?.length ?? 1, + transactionInfo.outputAddresses?.length ?? 1) + : bitcoin!.getFeeAmountForPriority( + wallet, + priority, + transactionInfo.inputAddresses?.length ?? 1, + transactionInfo.outputAddresses?.length ?? 1); + + return bitcoin!.formatterBitcoinAmountToString(amount: newFee); + } + + void replaceByFee(String newFee) => sendViewModel.replaceByFee(transactionInfo.id, newFee); + + @computed + String get pendingTransactionFiatAmountValueFormatted => sendViewModel.isFiatDisabled + ? '' + : sendViewModel.pendingTransactionFiatAmount + ' ' + sendViewModel.fiat.title; + + @computed + String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled + ? '' + : sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title; } diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index d4d0d664d..08815bf1d 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.", "Blocks_remaining": "بلوك متبقي ${status}", "bright_theme": "مشرق", + "bump_fee": "رسوم عثرة", "buy": "اشتري", "buy_alert_content": ".ﺎﻬﻴﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ Monero ﻭﺃ Litecoin ﻭﺃ Ethereum ﻭﺃ Bitcoin ﺔﻈﻔﺤﻣ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .", "buy_bitcoin": "شراء Bitcoin", @@ -133,6 +134,8 @@ "confirm": "تأكيد", "confirm_delete_template": "سيؤدي هذا الإجراء إلى حذف هذا القالب. هل ترغب في الاستمرار؟", "confirm_delete_wallet": "سيؤدي هذا الإجراء إلى حذف هذه المحفظة. هل ترغب في الاستمرار؟", + "confirm_fee_deduction": "تأكيد خصم الرسوم", + "confirm_fee_deduction_content": "هل توافق على خصم الرسوم من الإخراج؟", "confirm_sending": "تأكيد الإرسال", "confirmations": "التأكيدات", "confirmed": "رصيد مؤكد", @@ -212,6 +215,7 @@ "edit_token": "تحرير الرمز المميز", "electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل", "email_address": "عنوان البريد الالكترونى", + "enable_replace_by_fee": "تمكين الاستبدال", "enabled": "ممكنة", "enter_amount": "أدخل المبلغ", "enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا", @@ -248,6 +252,7 @@ "errorGettingCredentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻰﻠﻋ ﻝﻮﺼﺤﻟﺍ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ :ﻞﺸﻓ", "errorSigningTransaction": "ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ", "estimated": "مُقدَّر", + "estimated_new_fee": "رسوم جديدة مقدرة", "etherscan_history": "Etherscan تاريخ", "event": "ﺙﺪﺣ", "events": "ﺙﺍﺪﺣﻷﺍ", @@ -314,6 +319,7 @@ "in_store": "في المتجر", "incoming": "الواردة", "incorrect_seed": "النص الذي تم إدخاله غير صالح.", + "inputs": "المدخلات", "introducing_cake_pay": "نقدم لكم Cake Pay!", "invalid_input": "مدخل غير صالح", "invoice_details": "تفاصيل الفاتورة", @@ -381,6 +387,7 @@ "offer_expires_in": "ينتهي العرض في:", "offline": "غير متصل على الانترنت", "ok": "حسناً", + "old_fee": "الرسوم القديمة", "onion_link": "رابط البصل", "online": "متصل", "onramper_option_description": "شراء بسرعة التشفير مع العديد من طرق الدفع. متوفر في معظم البلدان. ينتشر وتختلف الرسوم.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "محافظ Bitcoin الجديدة التي تم إنشاؤها في Cake الآن سييد مكونة من 24 كلمة. من الضروري أن تقوم بإنشاء محفظة Bitcoin جديدة وتحويل جميع أموالك إلى المحفظة الجديدة المكونة من 24 كلمة ، والتوقف عن استخدام محافظ سييد مكونة من 12 كلمة. يرجى القيام بذلك على الفور لتأمين أموالك.", "outdated_electrum_wallet_receive_warning": "إذا كانت هذه المحفظة تحتوي على سييد مكونة من 12 كلمة وتم إنشاؤها في Cake ، فلا تقم بإيداع Bitcoin في هذه المحفظة. قد يتم فقد أي BTC تم تحويله إلى هذه المحفظة. قم بإنشاء محفظة جديدة مكونة من 24 كلمة (انقر فوق القائمة في الجزء العلوي الأيمن ، وحدد محافظ ، واختر إنشاء محفظة جديدة ، ثم حدد Bitcoin) وقم على الفور بنقل BTC الخاص بك هناك. محافظ BTC الجديدة (24 كلمة) من Cake آمنة", "outgoing": "الصادره", + "outputs": "المخرجات", "overwrite_amount": "تغير المبلغ", "pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ", "password": "كلمة المرور", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 6fe29a1a6..49e494394 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Плащанията с Bitcoin изискват потвърждение, което може да отнеме 20 минути или повече. Благодарим за търпението! Ще получите имейл, когато плащането е потвърдено.", "Blocks_remaining": "${status} оставащи блока", "bright_theme": "Ярко", + "bump_fee": "Такса за бум", "buy": "Купуване", "buy_alert_content": "В момента поддържаме само закупуването на Bitcoin, Ethereum, Litecoin и Monero. Моля, създайте или превключете към своя портфейл Bitcoin, Ethereum, Litecoin или Monero.", "buy_bitcoin": "Купуване на Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Потвърждаване", "confirm_delete_template": "Този шаблон ще бъде изтрит. Искате ли да продължите?", "confirm_delete_wallet": "Този портфейл ще бъде изтрит. Искате ли да продължите?", + "confirm_fee_deduction": "Потвърдете приспадането на таксите", + "confirm_fee_deduction_content": "Съгласни ли сте да приспадате таксата от продукцията?", "confirm_sending": "Потвърждаване на изпращането", "confirmations": "потвърждения", "confirmed": "Потвърден баланс", @@ -212,6 +215,7 @@ "edit_token": "Редактиране на токена", "electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят", "email_address": "Имейл адрес", + "enable_replace_by_fee": "Активиране на замяна по забрана", "enabled": "Активирано", "enter_amount": "Въведете сума", "enter_backup_password": "Въведете парола за възстановяване", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Неуспешно: Грешка при получаване на идентификационни данни", "errorSigningTransaction": "Възникна грешка при подписване на транзакция", "estimated": "Изчислено", + "estimated_new_fee": "Прогнозна нова такса", "etherscan_history": "История на Etherscan", "event": "Събитие", "events": "събития", @@ -314,6 +319,7 @@ "in_store": "In Store", "incoming": "Входящи", "incorrect_seed": "Въведеният текст е невалиден.", + "inputs": "Входове", "introducing_cake_pay": "Запознайте се с Cake Pay!", "invalid_input": "Невалиден вход", "invoice_details": "IДанни за фактура", @@ -381,6 +387,7 @@ "offer_expires_in": "Предложението изтича след: ", "offline": "Офлайн", "ok": "Ок", + "old_fee": "Стара такса", "onion_link": "Лукова връзка", "online": "Онлайн", "onramper_option_description": "Бързо купувайте криптовалута с много методи за плащане. Предлага се в повечето страни. Разпространенията и таксите варират.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Нови Bitcoin портфейли, създадени в Cake, сега имат seed от 24 думи. Трябва да създадете нов Bitcoin адрес и да прехвърлите всичките си средства в него и веднага да спрете използването на стари портфейли. Моля, напревете това незабавно, за да подсигурите средствата си.", "outdated_electrum_wallet_receive_warning": "Ако този адрес има seed от 12 думи и е създаден чрез Cake, НЕ добавяйте Bitcoin в него. Всякакъв Bitcoin, изпратен на този адрес, може да бъде загубен завинаги. Създайте нов портфейл от 24 думи (натиснете менюто горе, вдясно, изберете Портфейли, изберете Създаване на нов портфейл, след това изберете Bitcoin) и НЕЗАБАВНО преместете своя Bitcoin там. Нови (такива с 24 думи) Bitcoin портфейли от Cake са надеждни", "outgoing": "Изходящи", + "outputs": "Изходи", "overwrite_amount": "Промени сума", "pairingInvalidEvent": "Невалидно събитие при сдвояване", "password": "Парола", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index a346f9494..348b6fa38 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -79,6 +79,7 @@ "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.", "Blocks_remaining": "Zbývá ${status} bloků", "bright_theme": "Jasný", + "bump_fee": "Bump Fee", "buy": "Koupit", "buy_alert_content": "V současné době podporujeme pouze nákup bitcoinů, etherea, litecoinů a monero. Vytvořte nebo přepněte na svou peněženku bitcoinů, etherea, litecoinů nebo monero.", "buy_bitcoin": "Nakoupit Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Potvrdit", "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?", + "confirm_fee_deduction": "Potvrďte odpočet poplatků", + "confirm_fee_deduction_content": "Souhlasíte s odečtením poplatku z výstupu?", "confirm_sending": "Potvrdit odeslání", "confirmations": "Potvrzení", "confirmed": "Potvrzený zůstatek", @@ -212,6 +215,7 @@ "edit_token": "Upravit token", "electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují", "email_address": "E-mailová adresa", + "enable_replace_by_fee": "Povolit výměnu podle poplatku", "enabled": "Povoleno", "enter_amount": "Zadejte částku", "enter_backup_password": "Zde zadejte své heslo pro zálohy", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Selhalo: Chyba při získávání přihlašovacích údajů", "errorSigningTransaction": "Při podepisování transakce došlo k chybě", "estimated": "Odhadováno", + "estimated_new_fee": "Odhadovaný nový poplatek", "etherscan_history": "Historie Etherscanu", "event": "událost", "events": "Události", @@ -314,6 +319,7 @@ "in_store": "V obchodě", "incoming": "Příchozí", "incorrect_seed": "Zadaný text není správný.", + "inputs": "Vstupy", "introducing_cake_pay": "Představujeme Cake Pay!", "invalid_input": "Neplatný vstup", "invoice_details": "detaily faktury", @@ -381,6 +387,7 @@ "offer_expires_in": "Nabídka vyprší: ", "offline": "Offline", "ok": "OK", + "old_fee": "Starý poplatek", "onion_link": "Cibulový odkaz", "online": "Online", "onramper_option_description": "Rychle si koupte krypto s mnoha metodami plateb. K dispozici ve většině zemí. Rozpětí a poplatky se liší.", @@ -397,6 +404,7 @@ "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ů.", "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é", "outgoing": "Odchozí", + "outputs": "Výstupy", "overwrite_amount": "Přepsat částku", "pairingInvalidEvent": "Neplatná událost párování", "password": "Heslo", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 47375cedf..25ab3a54d 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Bitcoin-Zahlungen erfordern 1 Bestätigung, was 20 Minuten oder länger dauern kann. Danke für Ihre Geduld! Sie erhalten eine E-Mail, wenn die Zahlung bestätigt ist.", "Blocks_remaining": "${status} verbleibende Blöcke", "bright_theme": "Strahlend hell", + "bump_fee": "Beulengebühr", "buy": "Kaufen", "buy_alert_content": "Derzeit unterstützen wir nur den Kauf von Bitcoin, Ethereum, Litecoin und Monero. Bitte erstellen Sie Ihr Bitcoin-, Ethereum-, Litecoin- oder Monero-Wallet oder wechseln Sie zu diesem.", "buy_bitcoin": "Bitcoin kaufen", @@ -133,6 +134,8 @@ "confirm": "Bestätigen", "confirm_delete_template": "Diese Aktion löscht diese Vorlage. Möchten Sie fortfahren?", "confirm_delete_wallet": "Diese Aktion löscht diese Wallet. Möchten Sie fortfahren?", + "confirm_fee_deduction": "Gebührenabzug bestätigen", + "confirm_fee_deduction_content": "Stimmen Sie zu, die Gebühr von der Ausgabe abzuziehen?", "confirm_sending": "Senden bestätigen", "confirmations": "Bestätigungen", "confirmed": "Bestätigter Saldo", @@ -212,6 +215,7 @@ "edit_token": "Token bearbeiten", "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin", "email_address": "E-Mail-Adresse", + "enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee", "enabled": "Ermöglicht", "enter_amount": "Betrag eingeben", "enter_backup_password": "Sicherungskennwort hier eingeben", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Fehlgeschlagen: Fehler beim Abrufen der Anmeldeinformationen", "errorSigningTransaction": "Beim Signieren der Transaktion ist ein Fehler aufgetreten", "estimated": "Geschätzt", + "estimated_new_fee": "Geschätzte neue Gebühr", "etherscan_history": "Etherscan-Geschichte", "event": "Ereignis", "events": "Veranstaltungen", @@ -314,6 +319,7 @@ "in_store": "Im Geschäft", "incoming": "Eingehend", "incorrect_seed": "Der eingegebene Text ist ungültig.", + "inputs": "Eingänge", "introducing_cake_pay": "Einführung von Cake Pay!", "invalid_input": "Ungültige Eingabe", "invoice_details": "Rechnungs-Details", @@ -381,6 +387,7 @@ "offer_expires_in": "Angebot läuft ab in: ", "offline": "offline", "ok": "OK", + "old_fee": "Alte Gebühr", "onion_link": "Zwiebel-Link", "online": "online", "onramper_option_description": "Kaufen Sie schnell Krypto mit vielen Zahlungsmethoden. In den meisten Ländern erhältlich. Spreads und Gebühren variieren.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Neue Bitcoin-Wallets, die in Cake erstellt wurden, haben jetzt einen 24-Wort-Seed. Sie müssen eine neue Bitcoin-Wallet erstellen, Ihr gesamtes Geld in die neue 24-Wort-Wallet überweisen und keine Wallet mit einem 12-Wort-Seed mehr verwenden. Bitte tun Sie dies sofort, um Ihr Geld zu sichern.", "outdated_electrum_wallet_receive_warning": "Wenn diese Wallet einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Wallet ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher", "outgoing": "Ausgehend", + "outputs": "Ausgänge", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Paarung ungültiges Ereignis", "password": "Passwort", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 837033429..45e8ef21b 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Bitcoin payments require 1 confirmation, which can take 20 minutes or longer. Thanks for your patience! You will be emailed when the payment is confirmed.", "Blocks_remaining": "${status} Blocks Remaining", "bright_theme": "Bright", + "bump_fee": "Bump fee", "buy": "Buy", "buy_alert_content": "Currently we only support the purchase of Bitcoin, Ethereum, Litecoin, and Monero. Please create or switch to your Bitcoin, Ethereum, Litecoin, or Monero wallet.", "buy_bitcoin": "Buy Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Confirm", "confirm_delete_template": "This action will delete this template. Do you wish to continue?", "confirm_delete_wallet": "This action will delete this wallet. Do you wish to continue?", + "confirm_fee_deduction": "Confirm Fee Deduction", + "confirm_fee_deduction_content": "Do you agree to deduct the fee from the output?", "confirm_sending": "Confirm sending", "confirmations": "Confirmations", "confirmed": "Confirmed Balance", @@ -212,6 +215,7 @@ "edit_token": "Edit token", "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work", "email_address": "Email Address", + "enable_replace_by_fee": "Enable Replace-By-Fee", "enabled": "Enabled", "enter_amount": "Enter Amount", "enter_backup_password": "Enter backup password here", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Failed: Error while getting credentials", "errorSigningTransaction": "An error has occured while signing transaction", "estimated": "Estimated", + "estimated_new_fee": "Estimated new fee", "etherscan_history": "Etherscan history", "event": "Event", "events": "Events", @@ -314,6 +319,7 @@ "in_store": "In Store", "incoming": "Incoming", "incorrect_seed": "The text entered is not valid.", + "inputs": "Inputs", "introducing_cake_pay": "Introducing Cake Pay!", "invalid_input": "Invalid input", "invoice_details": "Invoice details", @@ -381,6 +387,7 @@ "offer_expires_in": "Offer expires in: ", "offline": "Offline", "ok": "OK", + "old_fee": "Old fee", "onion_link": "Onion link", "online": "Online", "onramper_option_description": "Quickly buy crypto with many payment methods. Available in most countries. Spreads and fees vary.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.", "outdated_electrum_wallet_receive_warning": "If this wallet has a 12-word seed and was created in Cake, DO NOT deposit Bitcoin into this wallet. Any BTC transferred to this wallet may be lost. Create a new 24-word wallet (tap the menu at the top right, select Wallets, choose Create New Wallet, then select Bitcoin) and IMMEDIATELY move your BTC there. New (24-word) BTC wallets from Cake are secure", "outgoing": "Outgoing", + "outputs": "Outputs", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Pairing Invalid Event", "password": "Password", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index b3afbd3a7..e04bc4cfe 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Los pagos de Bitcoin requieren 1 confirmación, que puede demorar 20 minutos o más. ¡Gracias por su paciencia! Se le enviará un correo electrónico cuando se confirme el pago.", "Blocks_remaining": "${status} Bloques restantes", "bright_theme": "Brillante", + "bump_fee": "Tarifa", "buy": "Comprar", "buy_alert_content": "Actualmente solo admitimos la compra de Bitcoin, Ethereum, Litecoin y Monero. Cree o cambie a su billetera Bitcoin, Ethereum, Litecoin o Monero.", "buy_bitcoin": "Comprar Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Confirmar", "confirm_delete_template": "Esta acción eliminará esta plantilla. ¿Desea continuar?", "confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?", + "confirm_fee_deduction": "Confirmar la deducción de la tarifa", + "confirm_fee_deduction_content": "¿Acepta deducir la tarifa de la producción?", "confirm_sending": "Confirmar envío", "confirmations": "Confirmaciones", "confirmed": "Saldo confirmado", @@ -212,6 +215,7 @@ "edit_token": "Editar token", "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando", "email_address": "Dirección de correo electrónico", + "enable_replace_by_fee": "Habilitar reemplazar por tarea", "enabled": "Activado", "enter_amount": "Ingrese la cantidad", "enter_backup_password": "Ingrese la contraseña de respaldo aquí", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Error: error al obtener las credenciales", "errorSigningTransaction": "Se ha producido un error al firmar la transacción.", "estimated": "Estimado", + "estimated_new_fee": "Nueva tarifa estimada", "etherscan_history": "historia de etherscan", "event": "Evento", "events": "Eventos", @@ -314,6 +319,7 @@ "in_store": "En la tienda", "incoming": "Entrante", "incorrect_seed": "El texto ingresado no es válido.", + "inputs": "Entradas", "introducing_cake_pay": "¡Presentamos Cake Pay!", "invalid_input": "Entrada inválida", "invoice_details": "Detalles de la factura", @@ -381,6 +387,7 @@ "offer_expires_in": "Oferta expira en: ", "offline": "fuera de línea", "ok": "OK", + "old_fee": "Tarifa antigua", "onion_link": "Enlace de cebolla", "online": "En línea", "onramper_option_description": "Compre rápidamente cripto con muchos métodos de pago. Disponible en la mayoría de los países. Los diferenciales y las tarifas varían.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Las nuevas carteras de Bitcoin creadas en Cake ahora tienen una semilla de 24 palabras. Es obligatorio que cree una nueva billetera de Bitcoin y transfiera todos sus fondos a la nueva billetera de 24 palabras, y deje de usar billeteras con una semilla de 12 palabras. Haga esto de inmediato para asegurar sus fondos.", "outdated_electrum_wallet_receive_warning": "Si esta billetera tiene una semilla de 12 palabras y se creó en Cake, NO deposite Bitcoin en esta billetera. Cualquier BTC transferido a esta billetera se puede perder. Cree una nueva billetera de 24 palabras (toque el menú en la parte superior derecha, seleccione Monederos, elija Crear nueva billetera, luego seleccione Bitcoin) e INMEDIATAMENTE mueva su BTC allí. Las nuevas carteras BTC (24 palabras) de Cake son seguras", "outgoing": "Saliente", + "outputs": "Salidas", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Evento de emparejamiento no válido", "password": "Contraseña", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 2a62d351d..069f569ba 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Les paiements Bitcoin nécessitent 1 confirmation, ce qui peut prendre 20 minutes ou plus. Merci pour votre patience ! Vous serez averti par e-mail lorsque le paiement sera confirmé.", "Blocks_remaining": "Blocs Restants : ${status}", "bright_theme": "Vif", + "bump_fee": "Frais de bosse", "buy": "Acheter", "buy_alert_content": "Actuellement, nous ne prenons en charge que l'achat de Bitcoin, Ethereum, Litecoin et Monero. Veuillez créer ou basculer vers votre portefeuille Bitcoin, Ethereum, Litecoin ou Monero.", "buy_bitcoin": "Acheter du Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Confirmer", "confirm_delete_template": "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?", "confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous contnuer ?", + "confirm_fee_deduction": "Confirmer la déduction des frais", + "confirm_fee_deduction_content": "Acceptez-vous de déduire les frais de la production?", "confirm_sending": "Confirmer l'envoi", "confirmations": "Confirmations", "confirmed": "Solde confirmé", @@ -212,6 +215,7 @@ "edit_token": "Modifier le token", "electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner", "email_address": "Adresse e-mail", + "enable_replace_by_fee": "Activer Remplace-by-Fee", "enabled": "Activé", "enter_amount": "Entrez le montant", "enter_backup_password": "Entrez le mot de passe de sauvegarde ici", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Échec : erreur lors de l'obtention des informations d'identification", "errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction", "estimated": "Estimé", + "estimated_new_fee": "De nouveaux frais estimés", "etherscan_history": "Historique d'Etherscan", "event": "Événement", "events": "Événements", @@ -314,6 +319,7 @@ "in_store": "En magasin", "incoming": "Entrantes", "incorrect_seed": "Le texte entré est invalide.", + "inputs": "Contributions", "introducing_cake_pay": "Présentation de Cake Pay !", "invalid_input": "Entrée invalide", "invoice_details": "Détails de la facture", @@ -381,6 +387,7 @@ "offer_expires_in": "L'Offre expire dans : ", "offline": "Hors ligne", "ok": "OK", + "old_fee": "Anciens", "onion_link": "Lien .onion", "online": "En ligne", "onramper_option_description": "Achetez rapidement des cryptomonnaies avec de nombreuses méthodes de paiement. Disponible dans la plupart des pays. Les spreads et les frais peuvent varier.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Les nouveaux portefeuilles (wallets) Bitcoin créés dans Cake ont dorénavant une phrase secrète (seed) de 24 mots. Il est impératif que vous créiez un nouveau portefeuille Bitcoin, que vous y transfériez tous vos fonds puis que vous cessiez d'utiliser le portefeuille avec une phrase secrète de 12 mots. Merci de faire cela immédiatement pour assurer la sécurité de vos avoirs.", "outdated_electrum_wallet_receive_warning": "Si ce portefeuille (wallet) a une phrase secrète (seed) de 12 mots et a été créé dans Cake, NE PAS y déposer de Bitcoin. Tous les BTC transférés vers ce portefeuille seront perdus. Créez un nouveau portefeuille avec phrase secrète de 24 mots (appuyez sur le menu en haut à droite, sélectionnez Portefeuilles puis Créer un Nouveau Portefeuille et enfin Bitcoin) et transférez y IMMÉDIATEMENT vos BTC. Les nouveaux portefeuilles BTC Cake (avec phrase secrète de 24 mots) sont sécurisés", "outgoing": "Sortantes", + "outputs": "Les sorties", "overwrite_amount": "Remplacer le montant", "pairingInvalidEvent": "Événement de couplage non valide", "password": "Mot de passe", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 1e18fb692..7dd1cd52e 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Akwatin Bitcoin na buɗe 1 sambumbu, da yake za ta samu mintuna 20 ko yawa. Ina kira ga sabuwar lafiya! Zaka sanarwa ta email lokacin da aka samu akwatin samun lambar waya.", "Blocks_remaining": "${status} Katanga ya rage", "bright_theme": "Mai haske", + "bump_fee": "Buin", "buy": "Sayi", "buy_alert_content": "A halin yanzu muna tallafawa kawai siyan Bitcoin, Ethereum, Litecoin, da Monero. Da fatan za a ƙirƙiri ko canza zuwa Bitcoin, Ethereum, Litecoin, ko Monero walat.", "buy_bitcoin": "Sayi Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Tabbatar", "confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?", "confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?", + "confirm_fee_deduction": "Tabbatar da cire kudade", + "confirm_fee_deduction_content": "Shin kun yarda ku cire kuɗin daga fitarwa?", "confirm_sending": "Tabbatar da aikawa", "confirmations": "Tabbatar", "confirmed": "An tabbatar", @@ -212,6 +215,7 @@ "edit_token": "Gyara alamar", "electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki", "email_address": "Adireshin i-mel", + "enable_replace_by_fee": "Ba da damar maye gurbin-by-kudin", "enabled": "An kunna", "enter_amount": "Shigar da Adadi", "enter_backup_password": "Shigar da kalmar wucewa ta madadin nan", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Ba a yi nasara ba: Kuskure yayin samun takaddun shaida", "errorSigningTransaction": "An sami kuskure yayin sanya hannu kan ciniki", "estimated": "Kiyasta", + "estimated_new_fee": "An kiyasta sabon kudin", "etherscan_history": "Etherscan tarihin kowane zamani", "event": "Lamarin", "events": "Abubuwan da suka faru", @@ -314,6 +319,7 @@ "in_store": "A cikin Store", "incoming": "Mai shigowa", "incorrect_seed": "rubutun da aka shigar ba shi da inganci.", + "inputs": "Abubuwan da ke ciki", "introducing_cake_pay": "Gabatar da Cake Pay!", "invalid_input": "Shigar da ba daidai ba", "invoice_details": "Bayanin wadannan", @@ -381,6 +387,7 @@ "offer_expires_in": "tayin zai ƙare a:", "offline": "Offline", "ok": "OK", + "old_fee": "Tsohon kudin", "onion_link": "Lambar onion", "online": "Kan layi", "onramper_option_description": "Da sauri sayi Crypto tare da hanyoyin biyan kuɗi da yawa. Akwai a yawancin ƙasashe. Yaduwa da kudade sun bambanta.", @@ -399,6 +406,7 @@ "outdated_electrum_wallet_description": "Sabbin walat ɗin Bitcoin da aka kirkira a cikin Cake yanzu suna da nau'in kalma 24. Ya zama dole ka ƙirƙiri sabon walat ɗin Bitcoin kuma canza duk kuɗin ku zuwa sabon walat ɗin kalmomi 24, kuma ku daina amfani da walat tare da iri mai kalma 12. Da fatan za a yi haka nan take don samun kuɗin ku.", "outdated_electrum_wallet_receive_warning": "Idan wannan walat ɗin yana da nau'in kalma 12 kuma an ƙirƙira shi a cikin Cake, KAR KA saka Bitcoin cikin wannan jakar. Duk wani BTC da aka canjawa wuri zuwa wannan walat na iya ɓacewa. Ƙirƙiri sabon walat mai kalmomi 24 (matsa menu a saman dama, zaɓi Wallets, zaɓi Ƙirƙiri Sabon Wallet, sannan zaɓi Bitcoin) kuma NAN nan take matsar da BTC ɗin ku a can. Sabbin (kalmomi 24) BTC wallets daga Cake suna da tsaro", "outgoing": "Mai fita", + "outputs": "Abubuwan fashewa", "overwrite_amount": "Rubuta adadin", "pairingInvalidEvent": "Haɗa Lamarin mara inganci", "password": "Kalmar wucewa", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index b1ef9e4a2..5dbe22f0e 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "बिटकॉइन भुगतान के लिए 1 पुष्टिकरण की आवश्यकता होती है, जिसमें 20 मिनट या अधिक समय लग सकता है। आपके धैर्य के लिए धन्यवाद! भुगतान की पुष्टि होने पर आपको ईमेल किया जाएगा।", "Blocks_remaining": "${status} शेष रहते हैं", "bright_theme": "उज्ज्वल", + "bump_fee": "बम्प फीस", "buy": "खरीदें", "buy_alert_content": "वर्तमान में हम केवल बिटकॉइन, एथेरियम, लाइटकॉइन और मोनेरो की खरीद का समर्थन करते हैं। कृपया अपना बिटकॉइन, एथेरियम, लाइटकॉइन, या मोनेरो वॉलेट बनाएं या उस पर स्विच करें।", "buy_bitcoin": "बिटकॉइन खरीदें", @@ -133,6 +134,8 @@ "confirm": "की पुष्टि करें", "confirm_delete_template": "यह क्रिया इस टेम्पलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?", "confirm_delete_wallet": "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?", + "confirm_fee_deduction": "शुल्क कटौती की पुष्टि करें", + "confirm_fee_deduction_content": "क्या आप आउटपुट से शुल्क में कटौती करने के लिए सहमत हैं?", "confirm_sending": "भेजने की पुष्टि करें", "confirmations": "पुष्टिकरण", "confirmed": "पुष्टि की गई शेष राशिी", @@ -212,6 +215,7 @@ "edit_token": "टोकन संपादित करें", "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं", "email_address": "ईमेल पता", + "enable_replace_by_fee": "प्रतिस्थापित-दर-शुल्क सक्षम करें", "enabled": "सक्रिय", "enter_amount": "राशि दर्ज करें", "enter_backup_password": "यहां बैकअप पासवर्ड डालें", @@ -248,6 +252,7 @@ "errorGettingCredentials": "विफल: क्रेडेंशियल प्राप्त करते समय त्रुटि", "errorSigningTransaction": "लेन-देन पर हस्ताक्षर करते समय एक त्रुटि उत्पन्न हुई है", "estimated": "अनुमानित", + "estimated_new_fee": "अनुमानित नया शुल्क", "etherscan_history": "इथरस्कैन इतिहास", "event": "आयोजन", "events": "आयोजन", @@ -314,6 +319,7 @@ "in_store": "स्टोर में", "incoming": "आने वाली", "incorrect_seed": "दर्ज किया गया पाठ मान्य नहीं है।", + "inputs": "इनपुट", "introducing_cake_pay": "परिचय Cake Pay!", "invalid_input": "अमान्य निवेश", "invoice_details": "चालान विवरण", @@ -381,6 +387,7 @@ "offer_expires_in": "में ऑफर समाप्त हो रहा है: ", "offline": "ऑफ़लाइन", "ok": "ठीक है", + "old_fee": "पुराना फीस", "onion_link": "प्याज का लिंक", "online": "ऑनलाइन", "onramper_option_description": "जल्दी से कई भुगतान विधियों के साथ क्रिप्टो खरीदें। अधिकांश देशों में उपलब्ध है। फैलता है और फीस अलग -अलग होती है।", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "केक में बनाए गए नए बिटकॉइन वॉलेट में अब 24-शब्द का बीज है। यह अनिवार्य है कि आप एक नया बिटकॉइन वॉलेट बनाएं और अपने सभी फंड को नए 24-शब्द वाले वॉलेट में स्थानांतरित करें, और 12-शब्द बीज वाले वॉलेट का उपयोग करना बंद करें। कृपया अपने धन को सुरक्षित करने के लिए इसे तुरंत करें।", "outdated_electrum_wallet_receive_warning": "अगर इस वॉलेट में 12 शब्दों का बीज है और इसे केक में बनाया गया है, तो इस वॉलेट में बिटकॉइन जमा न करें। इस वॉलेट में स्थानांतरित किया गया कोई भी बीटीसी खो सकता है। एक नया 24-शब्द वॉलेट बनाएं (ऊपर दाईं ओर स्थित मेनू पर टैप करें, वॉलेट चुनें, नया वॉलेट बनाएं चुनें, फिर बिटकॉइन चुनें) और तुरंत अपना बीटीसी वहां ले जाएं। केक से नए (24-शब्द) बीटीसी वॉलेट सुरक्षित हैं", "outgoing": "निवर्तमान", + "outputs": "आउटपुट", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना", "password": "पारण शब्द", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 55913f434..4aac8216e 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Bitcoin plaćanja zahtijevaju 1 potvrdu, što može potrajati 20 minuta ili dulje. Hvala na Vašem strpljenju! Dobit ćete e-poruku kada plaćanje bude potvrđeno.", "Blocks_remaining": "${status} preostalih blokova", "bright_theme": "Jarka", + "bump_fee": "Naplata", "buy": "Kupi", "buy_alert_content": "Trenutno podržavamo samo kupnju Bitcoina, Ethereuma, Litecoina i Monera. Izradite ili prijeđite na svoj Bitcoin, Ethereum, Litecoin ili Monero novčanik.", "buy_bitcoin": "Kupite Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Potvrdi", "confirm_delete_template": "Ovom ćete radnjom izbrisati ovaj predložak. Želite li nastaviti?", "confirm_delete_wallet": "Ovom ćete radnjom izbrisati ovaj novčanik. Želite li nastaviti?", + "confirm_fee_deduction": "Potvrdite odbitak naknade", + "confirm_fee_deduction_content": "Slažete li se da ćete odbiti naknadu od izlaza?", "confirm_sending": "Potvrdi slanje", "confirmations": "Potvrde", "confirmed": "Potvrđeno stanje", @@ -212,6 +215,7 @@ "edit_token": "Uredi token", "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek", "email_address": "Adresa e-pošte", + "enable_replace_by_fee": "Omogući zamjenu", "enabled": "Omogućeno", "enter_amount": "Unesite iznos", "enter_backup_password": "Unesite svoju lozinku za sigurnosnu kopiju ovdje", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Neuspješno: Pogreška prilikom dobivanja vjerodajnica", "errorSigningTransaction": "Došlo je do pogreške prilikom potpisivanja transakcije", "estimated": "procijenjen", + "estimated_new_fee": "Procijenjena nova naknada", "etherscan_history": "Etherscan povijest", "event": "Događaj", "events": "Događaji", @@ -314,6 +319,7 @@ "in_store": "U trgovini", "incoming": "Dolazno", "incorrect_seed": "Uneseni tekst nije valjan.", + "inputs": "Unosi", "introducing_cake_pay": "Predstavljamo Cake Pay!", "invalid_input": "Pogrešan unos", "invoice_details": "Podaci o fakturi", @@ -381,6 +387,7 @@ "offer_expires_in": "Ponuda istječe za: ", "offline": "izvan mreže", "ok": "OK", + "old_fee": "Stara naknada", "onion_link": "Poveznica luka", "online": "Na mreži", "onramper_option_description": "Brzo kupite kriptovalute s mnogim načinima plaćanja. Dostupno u većini zemalja. Širenja i naknade variraju.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Novi Bitcoin novčanici stvoreni u Cakeu sada imaju sjeme od 24 riječi. Obavezno je stvoriti novi Bitcoin novčanik i prenijeti sva svoja sredstva u novi novčanik od 24 riječi te prestati koristiti novčanike s sjemenkom od 12 riječi. Učinite to odmah kako biste osigurali svoja sredstva.", "outdated_electrum_wallet_receive_warning": "Ako ovaj novčanik sadrži sjeme od 12 riječi i stvoren je u Torti, NEMOJTE polagati Bitcoin u ovaj novčanik. Bilo koji BTC prebačen u ovaj novčanik može se izgubiti. Stvorite novi novčanik od 24 riječi (taknite izbornik u gornjem desnom dijelu, odaberite Novčanici, odaberite Stvori novi novčanik, a zatim odaberite Bitcoin) i ODMAH premjestite svoj BTC tamo. Novi BTC novčanici (s 24 riječi) tvrtke Cake sigurni su", "outgoing": "Odlazno", + "outputs": "Izlazi", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Nevažeći događaj uparivanja", "password": "Lozinka", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 8546e1f17..09d28e453 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Pembayaran Bitcoin memerlukan 1 konfirmasi, yang bisa memakan waktu 20 menit atau lebih. Terima kasih atas kesabaran Anda! Anda akan diemail saat pembayaran dikonfirmasi.", "Blocks_remaining": "${status} Blok Tersisa", "bright_theme": "Cerah", + "bump_fee": "Biaya benjolan", "buy": "Beli", "buy_alert_content": "Saat ini kami hanya mendukung pembelian Bitcoin, Ethereum, Litecoin, dan Monero. Harap buat atau alihkan ke dompet Bitcoin, Ethereum, Litecoin, atau Monero Anda.", "buy_bitcoin": "Beli Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Konfirmasi", "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?", + "confirm_fee_deduction": "Konfirmasi pengurangan biaya", + "confirm_fee_deduction_content": "Apakah Anda setuju untuk mengurangi biaya dari output?", "confirm_sending": "Konfirmasi pengiriman", "confirmations": "Konfirmasi", "confirmed": "Saldo Terkonfirmasi", @@ -212,6 +215,7 @@ "edit_token": "Mengedit token", "electrum_address_disclaimer": "Kami menghasilkan alamat baru setiap kali Anda menggunakan satu, tetapi alamat sebelumnya tetap berfungsi", "email_address": "Alamat Email", + "enable_replace_by_fee": "Aktifkan ganti-by-fee", "enabled": "Diaktifkan", "enter_amount": "Masukkan Jumlah", "enter_backup_password": "Masukkan kata sandi cadangan di sini", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Gagal: Terjadi kesalahan saat mendapatkan kredensial", "errorSigningTransaction": "Terjadi kesalahan saat menandatangani transaksi", "estimated": "Diperkirakan", + "estimated_new_fee": "Perkiraan biaya baru", "etherscan_history": "Sejarah Etherscan", "event": "Peristiwa", "events": "Acara", @@ -314,6 +319,7 @@ "in_store": "Di Toko", "incoming": "Masuk", "incorrect_seed": "Teks yang dimasukkan tidak valid.", + "inputs": "Input", "introducing_cake_pay": "Perkenalkan Cake Pay!", "invalid_input": "Masukan tidak valid", "invoice_details": "Detail faktur", @@ -381,6 +387,7 @@ "offer_expires_in": "Penawaran kedaluwarsa dalam: ", "offline": "Offline", "ok": "OK", + "old_fee": "Biaya lama", "onion_link": "Tautan bawang", "online": "Online", "onramper_option_description": "Beli crypto dengan cepat dengan banyak metode pembayaran. Tersedia di sebagian besar negara. Spread dan biaya bervariasi.", @@ -399,6 +406,7 @@ "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.", "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", "outgoing": "Keluar", + "outputs": "Output", "overwrite_amount": "Timpa jumlah", "pairingInvalidEvent": "Menyandingkan Acara Tidak Valid", "password": "Kata Sandi", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index ef0ffecde..c9ac60bb5 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "I pagamenti in bitcoin richiedono 1 conferma, che può richiedere 20 minuti o più. Grazie per la vostra pazienza! Riceverai un'e-mail quando il pagamento sarà confermato.", "Blocks_remaining": "${status} Blocchi Rimanenti", "bright_theme": "Colorato", + "bump_fee": "Commissione per bump", "buy": "Comprare", "buy_alert_content": "Attualmente supportiamo solo l'acquisto di Bitcoin, Ethereum, Litecoin e Monero. Crea o passa al tuo portafoglio Bitcoin, Ethereum, Litecoin o Monero.", "buy_bitcoin": "Acquista Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Conferma", "confirm_delete_template": "Questa azione cancellerà questo modello. Desideri continuare?", "confirm_delete_wallet": "Questa azione cancellerà questo portafoglio. Desideri continuare?", + "confirm_fee_deduction": "Conferma la detrazione delle commissioni", + "confirm_fee_deduction_content": "Accetti di detrarre la commissione dall'output?", "confirm_sending": "Conferma l'invio", "confirmations": "Conferme", "confirmed": "Saldo confermato", @@ -213,6 +216,7 @@ "edit_token": "Modifica token", "electrum_address_disclaimer": "Generiamo nuovi indirizzi ogni volta che ne utilizzi uno, ma gli indirizzi precedenti continuano a funzionare", "email_address": "Indirizzo e-mail", + "enable_replace_by_fee": "Abilita sostituzione per fee", "enabled": "Abilitato", "enter_amount": "Inserisci importo", "enter_backup_password": "Inserisci la password di backup qui", @@ -249,6 +253,7 @@ "errorGettingCredentials": "Non riuscito: errore durante il recupero delle credenziali", "errorSigningTransaction": "Si è verificato un errore durante la firma della transazione", "estimated": "Stimato", + "estimated_new_fee": "Nuova commissione stimata", "etherscan_history": "Storia Etherscan", "event": "Evento", "events": "Eventi", @@ -315,6 +320,7 @@ "in_store": "In negozio", "incoming": "In arrivo", "incorrect_seed": "Il testo inserito non è valido.", + "inputs": "Input", "introducing_cake_pay": "Presentazione di Cake Pay!", "invalid_input": "Inserimento non valido", "invoice_details": "Dettagli della fattura", @@ -382,6 +388,7 @@ "offer_expires_in": "Offerta termina tra: ", "offline": "Offline", "ok": "OK", + "old_fee": "Vecchia tassa", "onion_link": "Collegamento a cipolla", "online": "in linea", "onramper_option_description": "Acquista rapidamente la criptovaluta con molti metodi di pagamento. Disponibile nella maggior parte dei paesi. Gli spread e le commissioni variano.", @@ -399,6 +406,7 @@ "outdated_electrum_wallet_description": "I nuovi portafogli Bitcoin creati in Cake ora hanno un seme di 24 parole. È obbligatorio creare un nuovo portafoglio Bitcoin e trasferire tutti i fondi nel nuovo portafoglio di 24 parole e smettere di usare portafogli con un seme di 12 parole. Ti preghiamo di farlo immediatamente per proteggere i tuoi fondi.", "outdated_electrum_wallet_receive_warning": "Se questo portafoglio ha un seme di 12 parole ed è stato creato in Cake, NON depositare Bitcoin in questo portafoglio. Qualsiasi BTC trasferito su questo portafoglio potrebbe andare perso. Crea un nuovo portafoglio di 24 parole (tocca il menu in alto a destra, seleziona Portafogli, scegli Crea nuovo portafoglio, quindi seleziona Bitcoin) e sposta IMMEDIATAMENTE lì il tuo BTC. I nuovi portafogli BTC (24 parole) di Cake sono sicuri", "outgoing": "In uscita", + "outputs": "Output", "overwrite_amount": "Sovrascrivi quantità", "pairingInvalidEvent": "Associazione evento non valido", "password": "Password", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index c3a025a7c..98d87a90c 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "ビットコインの支払いには 1 回の確認が必要で、これには 20 分以上かかる場合があります。お待ち頂きまして、ありがとうございます!支払いが確認されると、メールが送信されます。", "Blocks_remaining": "${status} 残りのブロック", "bright_theme": "明るい", + "bump_fee": "バンプ料金", "buy": "購入", "buy_alert_content": "現在、ビットコイン、イーサリアム、ライトコイン、モネロの購入のみをサポートしています。ビットコイン、イーサリアム、ライトコイン、またはモネロのウォレットを作成するか、これらのウォレットに切り替えてください。", "buy_bitcoin": "ビットコインを購入する", @@ -133,6 +134,8 @@ "confirm": "確認する", "confirm_delete_template": "この操作により、このテンプレートが削除されます。 続行しますか?", "confirm_delete_wallet": "このアクションにより、このウォレットが削除されます。 続行しますか?", + "confirm_fee_deduction": "料金控除を確認します", + "confirm_fee_deduction_content": "出力から料金を差し引くことに同意しますか?", "confirm_sending": "送信を確認", "confirmations": "確認", "confirmed": "確認済み残高", @@ -212,6 +215,7 @@ "edit_token": "トークンの編集", "electrum_address_disclaimer": "使用するたびに新しいアドレスが生成されますが、以前のアドレスは引き続き機能します", "email_address": "メールアドレス", + "enable_replace_by_fee": "交換ごとに有効にします", "enabled": "有効", "enter_amount": "金額を入力", "enter_backup_password": "ここにバックアップパスワードを入力してください", @@ -248,6 +252,7 @@ "errorGettingCredentials": "失敗: 認証情報の取得中にエラーが発生しました", "errorSigningTransaction": "トランザクションの署名中にエラーが発生しました", "estimated": "推定", + "estimated_new_fee": "推定新しい料金", "etherscan_history": "イーサスキャンの歴史", "event": "イベント", "events": "イベント", @@ -315,6 +320,7 @@ "in_store": "インストア", "incoming": "着信", "incorrect_seed": "入力されたテキストは無効です。", + "inputs": "入力", "introducing_cake_pay": "序章Cake Pay!", "invalid_input": "無効入力", "invoice_details": "請求の詳細", @@ -382,6 +388,7 @@ "offer_expires_in": "で有効期限が切れます: ", "offline": "オフライン", "ok": "OK", + "old_fee": "古い料金", "onion_link": "オニオンリンク", "online": "オンライン", "onramper_option_description": "多くの支払い方法で暗号をすばやく購入してください。ほとんどの国で利用可能です。スプレッドと料金は異なります。", @@ -398,6 +405,7 @@ "outdated_electrum_wallet_description": "Cakeで作成された新しいビットコインウォレットには、24ワードのシードがあります。 新しいビットコインウォレットを作成し、すべての資金を新しい24ワードのウォレットに転送し、12ワードのシードを持つウォレットの使用を停止することが必須です。 あなたの資金を確保するためにこれをすぐに行ってください。", "outdated_electrum_wallet_receive_warning": "このウォレットに 12 ワードのシードがあり、Cake で作成された場合、このウォレットにビットコインを入金しないでください。 このウォレットに転送された BTC は失われる可能性があります。 新しい 24 ワードのウォレットを作成し (右上のメニューをタップし、[ウォレット]、[新しいウォレットの作成]、[ビットコイン] の順に選択)、すぐに BTC をそこに移動します。 Cake の新しい (24 ワード) BTC ウォレットは安全です", "outgoing": "発信", + "outputs": "出力", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "ペアリング無効イベント", "password": "パスワード", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index d2b48913b..7cc49e315 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "비트코인 결제는 1번의 확인이 필요하며 20분 이상이 소요될 수 있습니다. 기다려 주셔서 감사합니다! 결제가 확인되면 이메일이 전송됩니다.", "Blocks_remaining": "${status} 남은 블록", "bright_theme": "선명한", + "bump_fee": "범프 요금", "buy": "구입", "buy_alert_content": "현재 Bitcoin, Ethereum, Litecoin 및 Monero 구매만 지원합니다. Bitcoin, Ethereum, Litecoin 또는 Monero 지갑을 생성하거나 전환하십시오.", "buy_bitcoin": "비트 코인 구매", @@ -133,6 +134,8 @@ "confirm": "확인", "confirm_delete_template": "이 작업은이 템플릿을 삭제합니다. 계속 하시겠습니까?", "confirm_delete_wallet": "이 작업은이 지갑을 삭제합니다. 계속 하시겠습니까?", + "confirm_fee_deduction": "수수료 공제를 확인하십시오", + "confirm_fee_deduction_content": "출력에서 수수료를 공제하는 데 동의하십니까?", "confirm_sending": "전송 확인", "confirmations": "확인", "confirmed": "확인된 잔액", @@ -212,6 +215,7 @@ "edit_token": "토큰 편집", "electrum_address_disclaimer": "사용할 때마다 새 주소가 생성되지만 이전 주소는 계속 작동합니다.", "email_address": "이메일 주소", + "enable_replace_by_fee": "대체별로 활성화하십시오", "enabled": "사용", "enter_amount": "금액 입력", "enter_backup_password": "여기에 백업 비밀번호를 입력하세요.", @@ -248,6 +252,7 @@ "errorGettingCredentials": "실패: 자격 증명을 가져오는 중 오류가 발생했습니다.", "errorSigningTransaction": "거래에 서명하는 동안 오류가 발생했습니다.", "estimated": "예상", + "estimated_new_fee": "예상 새로운 수수료", "etherscan_history": "이더스캔 역사", "event": "이벤트", "events": "이벤트", @@ -314,6 +319,7 @@ "in_store": "매장 내", "incoming": "들어오는", "incorrect_seed": "입력하신 텍스트가 유효하지 않습니다.", + "inputs": "입력", "introducing_cake_pay": "소개 Cake Pay!", "invalid_input": "잘못된 입력", "invoice_details": "인보이스 세부정보", @@ -381,6 +387,7 @@ "offer_expires_in": "쿠폰 만료일: ", "offline": "오프라인", "ok": "승인", + "old_fee": "옛 수수료", "onion_link": "양파 링크", "online": "온라인", "onramper_option_description": "많은 결제 방법으로 암호화를 신속하게 구입하십시오. 대부분의 국가에서 사용할 수 있습니다. 스프레드와 수수료는 다양합니다.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Cake에서 생성 된 새로운 비트 코인 지갑에는 이제 24 단어 시드가 있습니다. 새로운 비트 코인 지갑을 생성하고 모든 자금을 새로운 24 단어 지갑으로 이체하고 12 단어 시드가있는 지갑 사용을 중지해야합니다. 자금을 확보하려면 즉시이 작업을 수행하십시오.", "outdated_electrum_wallet_receive_warning": "이 지갑에 12 단어 시드가 있고 Cake에서 생성 된 경우이 지갑에 비트 코인을 입금하지 마십시오. 이 지갑으로 전송 된 모든 BTC는 손실 될 수 있습니다. 새로운 24 단어 지갑을 생성하고 (오른쪽 상단의 메뉴를 탭하고 지갑을 선택한 다음 새 지갑 생성을 선택한 다음 비트 코인을 선택하십시오) 즉시 BTC를 그곳으로 이동하십시오. Cake의 새로운 (24 단어) BTC 지갑은 안전합니다", "outgoing": "나가는", + "outputs": "출력", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "잘못된 이벤트 페어링", "password": "암호", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index c7312b290..9c88dc817 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Bitcoin ငွေပေးချေမှုများသည် မိနစ် 20 သို့မဟုတ် ထို့ထက်ပိုကြာနိုင်သည် 1 အတည်ပြုချက် လိုအပ်သည်။ မင်းရဲ့စိတ်ရှည်မှုအတွက် ကျေးဇူးတင်ပါတယ်။ ငွေပေးချေမှုကို အတည်ပြုပြီးသောအခါ သင့်ထံ အီးမေးလ်ပို့ပါမည်။", "Blocks_remaining": "${status} ဘလောက်များ ကျန်နေပါသည်။", "bright_theme": "တောက်ပ", + "bump_fee": "ဝင်ငွေ", "buy": "ဝယ်ပါ။", "buy_alert_content": "လက်ရှိတွင် ကျွန်ုပ်တို့သည် Bitcoin၊ Ethereum၊ Litecoin နှင့် Monero တို့ကိုသာ ဝယ်ယူမှုကို ပံ့ပိုးပေးပါသည်။ သင်၏ Bitcoin၊ Ethereum၊ Litecoin သို့မဟုတ် Monero ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။", "buy_bitcoin": "Bitcoin ကိုဝယ်ပါ။", @@ -133,6 +134,8 @@ "confirm": "အတည်ပြုပါ။", "confirm_delete_template": "ဤလုပ်ဆောင်ချက်သည် ဤပုံစံပြားကို ဖျက်လိုက်ပါမည်။ ဆက်လုပ်လိုပါသလား။", "confirm_delete_wallet": "ဤလုပ်ဆောင်ချက်သည် ဤပိုက်ဆံအိတ်ကို ဖျက်လိုက်ပါမည်။ ဆက်လုပ်လိုပါသလား။", + "confirm_fee_deduction": "အခကြေးငွေကိုနှုတ်ယူခြင်း", + "confirm_fee_deduction_content": "output မှအခကြေးငွေကိုယူရန်သဘောတူပါသလား။", "confirm_sending": "ပေးပို့အတည်ပြုပါ။", "confirmations": "အတည်ပြုချက်များ", "confirmed": "အတည်ပြုထားသော လက်ကျန်ငွေ", @@ -212,6 +215,7 @@ "edit_token": "တိုကင်ကို တည်းဖြတ်ပါ။", "electrum_address_disclaimer": "သင်အသုံးပြုသည့်အချိန်တိုင်းတွင် ကျွန်ုပ်တို့သည် လိပ်စာအသစ်များကို ထုတ်ပေးသော်လည်း ယခင်လိပ်စာများသည် ဆက်လက်အလုပ်လုပ်နေပါသည်။", "email_address": "အီးမေးလ်လိပ်စာ", + "enable_replace_by_fee": "အစားထိုး - by- အခကြေးငွေ enable", "enabled": "ဖွင့်ထားသည်။", "enter_amount": "ပမာဏကို ထည့်ပါ။", "enter_backup_password": "အရန်စကားဝှက်ကို ဤနေရာတွင် ထည့်ပါ။", @@ -248,6 +252,7 @@ "errorGettingCredentials": "မအောင်မြင်ပါ- အထောက်အထားများ ရယူနေစဉ် အမှားအယွင်း", "errorSigningTransaction": "ငွေပေးငွေယူ လက်မှတ်ထိုးစဉ် အမှားအယွင်းတစ်ခု ဖြစ်ပေါ်ခဲ့သည်။", "estimated": "ခန့်မှန်း", + "estimated_new_fee": "ခန့်မှန်းသစ်ခန့်မှန်း", "etherscan_history": "Etherscan သမိုင်း", "event": "ပွဲ", "events": "အဲ့ဒါနဲ့", @@ -314,6 +319,7 @@ "in_store": "စတိုးတွင်", "incoming": "ဝင်လာ", "incorrect_seed": "ထည့်သွင်းထားသော စာသားသည် မမှန်ကန်ပါ။", + "inputs": "သွင်းငေှ", "introducing_cake_pay": "Cake Pay ကို မိတ်ဆက်ခြင်း။", "invalid_input": "ထည့်သွင်းမှု မမှန်ကန်ပါ။", "invoice_details": "ပြေစာအသေးစိတ်", @@ -381,6 +387,7 @@ "offer_expires_in": "ကမ်းလှမ်းချက် သက်တမ်းကုန်သည်:", "offline": "အော့ဖ်လိုင်း", "ok": "ရလား", + "old_fee": "ကြေးဟောင်း", "onion_link": "ကြက်သွန်လင့်", "online": "အွန်လိုင်း", "onramper_option_description": "ငွေပေးချေမှုနည်းလမ်းများစွာဖြင့် Crypto ကိုလျင်မြန်စွာ 0 ယ်ပါ။ နိုင်ငံအများစုတွင်ရရှိနိုင်ပါသည်။ ဖြန့်ဖြူးနှင့်အခကြေးငွေကွဲပြားခြားနားသည်။", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "ယခု Cake တွင်ဖန်တီးထားသော Bitcoin ပိုက်ဆံအိတ်အသစ်တွင် စကားလုံး 24 မျိုးရှိသည်။ Bitcoin ပိုက်ဆံအိတ်အသစ်တစ်ခုကို ဖန်တီးပြီး သင့်ငွေအားလုံးကို 24 စကားလုံးပိုက်ဆံအိတ်အသစ်သို့ လွှဲပြောင်းပြီး 12 စကားလုံးမျိုးစေ့ဖြင့် ပိုက်ဆံအိတ်များကို အသုံးပြုခြင်းကို ရပ်တန့်ရန် မဖြစ်မနေလိုအပ်ပါသည်။ သင့်ရန်ပုံငွေများကို လုံခြုံစေရန်အတွက် ၎င်းကိုချက်ချင်းလုပ်ဆောင်ပါ။", "outdated_electrum_wallet_receive_warning": "ဤပိုက်ဆံအိတ်တွင် စာလုံး 12 လုံးပါပြီး ကိတ်မုန့်တွင် ဖန်တီးပါက၊ Bitcoin ကို ဤပိုက်ဆံအိတ်ထဲသို့ မထည့်ပါနှင့်။ ဤပိုက်ဆံအိတ်သို့ လွှဲပြောင်းပေးသည့် မည်သည့် BTC မဆို ဆုံးရှုံးနိုင်သည်။ 24 စကားလုံးပိုက်ဆံအိတ်အသစ်တစ်ခုဖန်တီးပါ (ညာဘက်အပေါ်ထောင့်ရှိမီနူးကိုနှိပ်ပါ၊ Wallets ကိုရွေးချယ်ပါ၊ ပိုက်ဆံအိတ်အသစ်ဖန်တီးရန်ကိုရွေးချယ်ပါ၊ ထို့နောက် Bitcoin ကိုရွေးချယ်ပါ) နှင့်သင်၏ BTC ကိုထိုနေရာသို့ချက်ချင်းရွှေ့ပါ။ Cake မှ (24 စာလုံး) BTC ပိုက်ဆံအိတ်အသစ်များသည် လုံခြုံပါသည်။", "outgoing": "အထွက်", + "outputs": "ထုတ်လုပ်မှု", "overwrite_amount": "ပမာဏကို ထပ်ရေးပါ။", "pairingInvalidEvent": "မမှန်ကန်သောဖြစ်ရပ်ကို တွဲချိတ်ခြင်း။", "password": "စကားဝှက်", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 86881452e..74b111dcb 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Bitcoin-betalingen vereisen 1 bevestiging, wat 20 minuten of langer kan duren. Dank voor uw geduld! U ontvangt een e-mail wanneer de betaling is bevestigd.", "Blocks_remaining": "${status} Resterende blokken", "bright_theme": "Helder", + "bump_fee": "Bult fee", "buy": "Kopen", "buy_alert_content": "Momenteel ondersteunen we alleen de aankoop van Bitcoin, Ethereum, Litecoin en Monero. Maak of schakel over naar uw Bitcoin-, Ethereum-, Litecoin- of Monero-portemonnee.", "buy_bitcoin": "Koop Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Bevestigen", "confirm_delete_template": "Met deze actie wordt deze sjabloon verwijderd. Wilt u doorgaan?", "confirm_delete_wallet": "Met deze actie wordt deze portemonnee verwijderd. Wilt u doorgaan?", + "confirm_fee_deduction": "Bevestig de aftrek van de kosten", + "confirm_fee_deduction_content": "Stemt u ermee in om de vergoeding af te trekken van de output?", "confirm_sending": "Bevestig verzending", "confirmations": "Bevestigingen", "confirmed": "Bevestigd saldo", @@ -212,6 +215,7 @@ "edit_token": "Token bewerken", "electrum_address_disclaimer": "We genereren nieuwe adressen elke keer dat u er een gebruikt, maar eerdere adressen blijven werken", "email_address": "E-mailadres", + "enable_replace_by_fee": "Schakel vervangen door een fee", "enabled": "Ingeschakeld", "enter_amount": "Voer Bedrag in", "enter_backup_password": "Voer hier een back-upwachtwoord in", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Mislukt: fout bij het ophalen van inloggegevens", "errorSigningTransaction": "Er is een fout opgetreden tijdens het ondertekenen van de transactie", "estimated": "Geschatte", + "estimated_new_fee": "Geschatte nieuwe vergoeding", "etherscan_history": "Etherscan-geschiedenis", "event": "Evenement", "events": "Evenementen", @@ -314,6 +319,7 @@ "in_store": "In winkel", "incoming": "inkomend", "incorrect_seed": "De ingevoerde tekst is niet geldig.", + "inputs": "Invoer", "introducing_cake_pay": "Introductie van Cake Pay!", "invalid_input": "Ongeldige invoer", "invoice_details": "Factuurgegevens", @@ -381,6 +387,7 @@ "offer_expires_in": "Aanbieding verloopt over: ", "offline": "Offline", "ok": "OK", + "old_fee": "Oude vergoeding", "onion_link": "Ui koppeling", "online": "online", "onramper_option_description": "Koop snel crypto met veel betaalmethoden. Beschikbaar in de meeste landen. Spreads en vergoedingen variëren.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Nieuwe Bitcoin-portefeuilles die in Cake zijn gemaakt, hebben nu een zaadje van 24 woorden. Het is verplicht dat u een nieuwe Bitcoin-portemonnee maakt en al uw geld overmaakt naar de nieuwe portemonnee van 24 woorden, en stopt met het gebruik van wallets met een seed van 12 woorden. Doe dit onmiddellijk om uw geld veilig te stellen.", "outdated_electrum_wallet_receive_warning": "Als deze portemonnee een seed van 12 woorden heeft en is gemaakt in Cake, stort dan GEEN Bitcoin in deze portemonnee. Elke BTC die naar deze portemonnee is overgebracht, kan verloren gaan. Maak een nieuwe portemonnee van 24 woorden (tik op het menu rechtsboven, selecteer Portefeuilles, kies Nieuwe portemonnee maken en selecteer vervolgens Bitcoin) en verplaats je BTC ONMIDDELLIJK daar. Nieuwe (24-woorden) BTC-portefeuilles van Cake zijn veilig", "outgoing": "Uitgaande", + "outputs": "Uitgangen", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Koppelen Ongeldige gebeurtenis", "password": "Wachtwoord", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 994820123..2ac1b9fb5 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Płatności Bitcoin wymagają 1 potwierdzenia, co może zająć 20 minut lub dłużej. Dziękuję za cierpliwość! Otrzymasz wiadomość e-mail, gdy płatność zostanie potwierdzona.", "Blocks_remaining": "Pozostało ${status} bloków", "bright_theme": "Biały", + "bump_fee": "Opłata za nierówność", "buy": "Kup", "buy_alert_content": "Obecnie obsługujemy tylko zakup Bitcoin, Ethereum, Litecoin i Monero. Utwórz lub przełącz się na swój portfel Bitcoin, Ethereum, Litecoin lub Monero.", "buy_bitcoin": "Kup Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Potwierdzać", "confirm_delete_template": "Ta czynność usunie ten szablon. Czy chcesz kontynuować?", "confirm_delete_wallet": "Ta czynność usunie ten portfel. Czy chcesz kontynuować?", + "confirm_fee_deduction": "Potwierdź odliczenie opłaty", + "confirm_fee_deduction_content": "Czy zgadzasz się odliczyć opłatę od wyników?", "confirm_sending": "Potwierdź wysłanie", "confirmations": "Potwierdzenia", "confirmed": "Potwierdzone saldo", @@ -212,6 +215,7 @@ "edit_token": "Edytuj token", "electrum_address_disclaimer": "Za każdym razem, gdy wykorzystasz adres, dla wiekszej prywatności generujemy nowy, ale poprzednie adresy nadal działają, i moga odbierać środki", "email_address": "Adres e-mail", + "enable_replace_by_fee": "Włącz wymianę po lewej", "enabled": "Włączone", "enter_amount": "Wprowadź kwotę", "enter_backup_password": "Wprowadź tutaj hasło kopii zapasowej", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Niepowodzenie: Błąd podczas uzyskiwania poświadczeń", "errorSigningTransaction": "Wystąpił błąd podczas podpisywania transakcji", "estimated": "Oszacowano", + "estimated_new_fee": "Szacowana nowa opłata", "etherscan_history": "Historia Etherscanu", "event": "Wydarzenie", "events": "Wydarzenia", @@ -314,6 +319,7 @@ "in_store": "W Sklepie", "incoming": "Przychodzące", "incorrect_seed": "Wprowadzony seed jest nieprawidłowy.", + "inputs": "Wejścia", "introducing_cake_pay": "Przedstawiamy Cake Pay!", "invalid_input": "Nieprawidłowe dane wejściowe", "invoice_details": "Dane do faktury", @@ -381,6 +387,7 @@ "offer_expires_in": "Oferta wygasa za ", "offline": "Offline", "ok": "Ok", + "old_fee": "Stara opłata", "onion_link": "Łącznik cebulowy", "online": "online", "onramper_option_description": "Szybko kup kryptowaluty z wieloma metodami płatności. Dostępne w większości krajów. Spready i opłaty różnią się.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Nowe portfele Bitcoin utworzone w Cake mają teraz fraze seed składające się z 24 słów. Konieczne jest utworzenie nowego portfela Bitcoin i przeniesienie wszystkich środków do nowego portfela na 24 słowa oraz zaprzestanie korzystania z portfeli z frazą seed na 12 słów. Zrób to natychmiast, aby zabezpieczyć swoje fundusze.", "outdated_electrum_wallet_receive_warning": "Jeśli ten portfel ma 12-wyrazowy seed i został utworzony w Cake, NIE Wpłacaj Bitcoina do tego portfela. Wszelkie BTC przeniesione do tego portfela mogą zostać utracone. Utwórz nowy portfel z 24 słowami (dotknij menu w prawym górnym rogu, wybierz Portfele, wybierz Utwórz nowy portfel, a następnie Bitcoin) i NATYCHMIAST przenieś tam swoje BTC. Nowe (24 słowa) portfele BTC Cake Wallet są bezpieczne", "outgoing": "Wychodzące", + "outputs": "Wyjścia", "overwrite_amount": "Nadpisz ilość", "pairingInvalidEvent": "Nieprawidłowe zdarzenie parowania", "password": "Hasło", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index cec7b8c11..bf0b0082d 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Os pagamentos em Bitcoin exigem 1 confirmação, o que pode levar 20 minutos ou mais. Obrigado pela sua paciência! Você receberá um e-mail quando o pagamento for confirmado.", "Blocks_remaining": "${status} blocos restantes", "bright_theme": "Brilhante", + "bump_fee": "Taxa de aumento", "buy": "Comprar", "buy_alert_content": "Atualmente, oferecemos suporte apenas à compra de Bitcoin, Ethereum, Litecoin e Monero. Crie ou troque para sua carteira Bitcoin, Ethereum, Litecoin ou Monero.", "buy_bitcoin": "Compre Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Confirmar", "confirm_delete_template": "Esta ação excluirá este modelo. Você deseja continuar?", "confirm_delete_wallet": "Esta ação excluirá esta carteira. Você deseja continuar?", + "confirm_fee_deduction": "Confirme dedução da taxa", + "confirm_fee_deduction_content": "Você concorda em deduzir a taxa da saída?", "confirm_sending": "Confirmar o envio", "confirmations": "Confirmações", "confirmed": "Saldo Confirmado", @@ -212,6 +215,7 @@ "edit_token": "Editar símbolo", "electrum_address_disclaimer": "Geramos novos endereços cada vez que você usa um, mas os endereços anteriores continuam funcionando", "email_address": "Endereço de e-mail", + "enable_replace_by_fee": "Habilite substituir por taxa", "enabled": "Habilitado", "enter_amount": "Digite o valor", "enter_backup_password": "Digite a senha de backup aqui", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Falha: Erro ao obter credenciais", "errorSigningTransaction": "Ocorreu um erro ao assinar a transação", "estimated": "Estimado", + "estimated_new_fee": "Nova taxa estimada", "etherscan_history": "história Etherscan", "event": "Evento", "events": "Eventos", @@ -314,6 +319,7 @@ "in_store": "Na loja", "incoming": "Recebidas", "incorrect_seed": "O texto digitado não é válido.", + "inputs": "Entradas", "introducing_cake_pay": "Apresentando o Cake Pay!", "invalid_input": "Entrada inválida", "invoice_details": "Detalhes da fatura", @@ -382,6 +388,7 @@ "offer_expires_in": "A oferta expira em: ", "offline": "offline", "ok": "Ok", + "old_fee": "Taxa antiga", "onion_link": "ligação de cebola", "online": "Online", "onramper_option_description": "Compre rapidamente criptografia com muitos métodos de pagamento. Disponível na maioria dos países. Os spreads e taxas variam.", @@ -399,6 +406,7 @@ "outdated_electrum_wallet_description": "As novas carteiras Bitcoin criadas no Cake agora têm uma semente de 24 palavras. É obrigatório que você crie uma nova carteira Bitcoin e transfira todos os seus fundos para a nova carteira de 24 palavras, e pare de usar carteiras com semente de 12 palavras. Faça isso imediatamente para garantir seus fundos.", "outdated_electrum_wallet_receive_warning": "Se esta carteira tiver uma semente de 12 palavras e foi criada no Cake, NÃO deposite Bitcoin nesta carteira. Qualquer BTC transferido para esta carteira pode ser perdido. Crie uma nova carteira de 24 palavras (toque no menu no canto superior direito, selecione Carteiras, escolha Criar Nova Carteira e selecione Bitcoin) e mova IMEDIATAMENTE seu BTC para lá. As novas carteiras BTC (24 palavras) da Cake são seguras", "outgoing": "Enviadas", + "outputs": "Saídas", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Emparelhamento de evento inválido", "password": "Senha", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 4ae5bb129..999728faf 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -75,10 +75,11 @@ "billing_address_info": "Если вас попросят указать платежный адрес, укажите адрес доставки", "biometric_auth_reason": "Отсканируйте свой отпечаток пальца для аутентификации", "bitcoin_dark_theme": "Биткойн Темная тема", - "bitcoin_light_theme": "Легкая биткойн-тема", + "bitcoin_light_theme": "Светлая биткойн-тема", "bitcoin_payments_require_1_confirmation": "Биткойн-платежи требуют 1 подтверждения, что может занять 20 минут или дольше. Спасибо тебе за твое терпение! Вы получите электронное письмо, когда платеж будет подтвержден.", "Blocks_remaining": "${status} Осталось блоков", "bright_theme": "Яркая", + "bump_fee": "Повысить комиссию", "buy": "Купить", "buy_alert_content": "В настоящее время мы поддерживаем только покупку биткойнов, Ethereum, Litecoin и Monero. Пожалуйста, создайте или переключитесь на свой кошелек Bitcoin, Ethereum, Litecoin или Monero.", "buy_bitcoin": "Купить Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Подтвердить", "confirm_delete_template": "Это действие удалит шаблон. Вы хотите продолжить?", "confirm_delete_wallet": "Это действие удалит кошелек. Вы хотите продолжить?", + "confirm_fee_deduction": "Подтвердите вычет платы", + "confirm_fee_deduction_content": "Согласны ли вы вычесть плату из вывода?", "confirm_sending": "Подтвердить отправку", "confirmations": "Подтверждения", "confirmed": "Подтвержденный баланс", @@ -212,6 +215,7 @@ "edit_token": "Изменить токен", "electrum_address_disclaimer": "Мы генерируем новые адреса каждый раз, когда вы их используете, но предыдущие адреса продолжают работать.", "email_address": "Адрес электронной почты", + "enable_replace_by_fee": "Включить замену за пикой", "enabled": "Включено", "enter_amount": "Введите сумму", "enter_backup_password": "Введите пароль резервной копии", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Не удалось: ошибка при получении учетных данных.", "errorSigningTransaction": "Произошла ошибка при подписании транзакции", "estimated": "Примерно", + "estimated_new_fee": "Расчетная новая плата", "etherscan_history": "История Эфириума", "event": "Событие", "events": "События", @@ -314,6 +319,7 @@ "in_store": "В магазине", "incoming": "Входящие", "incorrect_seed": "Введённый текст некорректный.", + "inputs": "Входы", "introducing_cake_pay": "Представляем Cake Pay!", "invalid_input": "Неверный Ввод", "invoice_details": "Детали счета", @@ -381,6 +387,7 @@ "offer_expires_in": "Предложение истекает через: ", "offline": "Не в сети", "ok": "OK", + "old_fee": "Старая плата", "onion_link": "Луковая ссылка", "online": "Онлайн", "onramper_option_description": "Быстро купите крипто со многими способами оплаты. Доступно в большинстве стран. Спреды и сборы различаются.", @@ -398,6 +405,7 @@ "outdated_electrum_wallet_description": "Новые биткойн-кошельки, созданные в Cake, теперь содержат мнемоническую фразу из 24 слов. Вы обязательно должны создать новый биткойн-кошелек и перевести все свои средства в новый кошелек из 24 слов, а также прекратить использование кошельков с мнемонической фразой из 12 слов. Пожалуйста, сделайте это немедленно, чтобы обезопасить свои средства.", "outdated_electrum_wallet_receive_warning": "Если этот кошелек имеет мнемоническую фразу из 12 слов и был создан в Cake, НЕ переводите биткойны на этот кошелек. Любые BTC, переведенные на этот кошелек, могут быть потеряны. Создайте новый кошелек с мнемоническои фразы из 24 слов (коснитесь меню в правом верхнем углу, выберите «Кошельки», выберите «Создать новый кошелек», затем выберите «Bitcoin») и НЕМЕДЛЕННО переведите туда свои BTC. Новые (24 слова) кошельки BTC от Cake безопасны", "outgoing": "Исходящие", + "outputs": "Выходы", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Недействительное событие сопряжения", "password": "Пароль", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 6c8634e83..a71bc6b36 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "การชำระเงินด้วย Bitcoin ต้องการการยืนยัน 1 ครั้ง ซึ่งอาจใช้เวลา 20 นาทีหรือนานกว่านั้น ขอบคุณสำหรับความอดทนของคุณ! คุณจะได้รับอีเมลเมื่อการชำระเงินได้รับการยืนยัน", "Blocks_remaining": "${status} บล็อกที่เหลืออยู่", "bright_theme": "สดใส", + "bump_fee": "ค่าธรรมเนียมชน", "buy": "ซื้อ", "buy_alert_content": "ขณะนี้เรารองรับการซื้อ Bitcoin, Ethereum, Litecoin และ Monero เท่านั้น โปรดสร้างหรือเปลี่ยนเป็นกระเป๋าเงิน Bitcoin, Ethereum, Litecoin หรือ Monero", "buy_bitcoin": "ซื้อ Bitcoin", @@ -133,6 +134,8 @@ "confirm": "ยืนยัน", "confirm_delete_template": "การดำเนินการนี้จะลบแบบฟอร์มนี้ คุณต้องการดำเนินการต่อหรือไม่?", "confirm_delete_wallet": "การดำเนินการนี้จะลบกระเป๋านี้ คุณต้องการดำเนินการต่อหรือไม่?", + "confirm_fee_deduction": "ยืนยันการหักค่าธรรมเนียม", + "confirm_fee_deduction_content": "คุณตกลงที่จะหักค่าธรรมเนียมจากผลลัพธ์หรือไม่?", "confirm_sending": "ยืนยันการส่ง", "confirmations": "การยืนยัน", "confirmed": "ยอดคงเหลือที่ยืนยันแล้ว", @@ -212,6 +215,7 @@ "edit_token": "แก้ไขโทเค็น", "electrum_address_disclaimer": "เราสร้างที่อยู่ใหม่ทุกครั้งที่คุณใช้หนึ่งอย่าง แต่ที่อยู่เก่ายังสามารถใช้ได้ต่อไป", "email_address": "ที่อยู่อีเมล", + "enable_replace_by_fee": "เปิดใช้งานการเปลี่ยนโดยค่าธรรมเนียม", "enabled": "เปิดใช้งาน", "enter_amount": "กรอกจำนวน", "enter_backup_password": "ป้อนรหัสผ่านสำรองที่นี่", @@ -248,6 +252,7 @@ "errorGettingCredentials": "ล้มเหลว: เกิดข้อผิดพลาดขณะรับข้อมูลรับรอง", "errorSigningTransaction": "เกิดข้อผิดพลาดขณะลงนามธุรกรรม", "estimated": "ประมาณการ", + "estimated_new_fee": "ค่าธรรมเนียมใหม่โดยประมาณ", "etherscan_history": "ประวัติอีเธอร์สแกน", "event": "เหตุการณ์", "events": "กิจกรรม", @@ -314,6 +319,7 @@ "in_store": "ในร้าน", "incoming": "ขาเข้า", "incorrect_seed": "ข้อความที่ป้อนไม่ถูกต้อง", + "inputs": "อินพุต", "introducing_cake_pay": "ยินดีต้อนรับสู่ Cake Pay!", "invalid_input": "อินพุตไม่ถูกต้อง", "invoice_details": "รายละเอียดใบแจ้งหนี้", @@ -381,6 +387,7 @@ "offer_expires_in": "ข้อเสนอจะหมดอายุใน: ", "offline": "ออฟไลน์", "ok": "ตกลง", + "old_fee": "ค่าธรรมเนียมเก่า", "onion_link": "ลิงค์หัวหอม", "online": "ออนไลน์", "onramper_option_description": "ซื้อ crypto อย่างรวดเร็วด้วยวิธีการชำระเงินจำนวนมาก มีให้บริการในประเทศส่วนใหญ่ สเปรดและค่าธรรมเนียมแตกต่างกันไป", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "กระเป๋า Bitcoin ใหม่ที่สร้างใน Cake มี seed ขนาด 24 คำ ซึ่งจำเป็นต้องสร้างกระเป๋า Bitcoin ใหม่และโอนทุกเงินของคุณไปยังกระเป๋าใหม่ขนาด 24 คำ และหยุดใช้กระเป๋าที่มี seed ขนาด 12 คำ กรุณาทำด่วนเพื่อรักษาเงินของคุณ", "outdated_electrum_wallet_receive_warning": "หากกระเป๋านี้มีซีดีที่มี 12 คำและถูกสร้างขึ้นใน Cake อย่าโอน Bitcoin เข้ากระเป๋านี้ ทุกจำนวน BTC ที่โอนเข้ากระเป๋านี้อาจสูญหาย สร้างกระเป๋าใหม่ที่มีซีดีที่มี 24 คำ (กดที่เมนูที่มุมขวาบนแล้วเลือก Wallets และเลือก Create New Wallet จากนั้นเลือก Bitcoin) และย้าย BTC ไปที่นั้นทันที กระเป๋า BTC ที่มีซีดีที่มี 24 คำของ Cake ปลอดภัย", "outgoing": "ขาออก", + "outputs": "เอาต์พุต", "overwrite_amount": "เขียนทับจำนวน", "pairingInvalidEvent": "การจับคู่เหตุการณ์ที่ไม่ถูกต้อง", "password": "รหัสผ่าน", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 4d88fe640..73cd8a1f7 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Ang mga pagbabayad sa Bitcoin ay nangangailangan ng 1 kumpirmasyon, na maaaring tumagal ng 20 minuto o mas mahaba. Salamat sa iyong pasensya! Mag -email ka kapag nakumpirma ang pagbabayad.", "Blocks_remaining": "Ang natitirang ${status} ay natitira", "bright_theme": "Maliwanag", + "bump_fee": "Bayad sa paga", "buy": "Bilhin", "buy_alert_content": "Sa kasalukuyan ay sinusuportahan lamang namin ang pagbili ng Bitcoin, Ethereum, Litecoin, at Monero. Mangyaring lumikha o lumipat sa iyong Bitcoin, Ethereum, Litecoin, o Monero Wallet.", "buy_bitcoin": "Bumili ng bitcoin", @@ -133,6 +134,8 @@ "confirm": "Kumpirmahin", "confirm_delete_template": "Ang pagkilos na ito ay tatanggalin ang template na ito. Nais mo bang magpatuloy?", "confirm_delete_wallet": "Ang pagkilos na ito ay tatanggalin ang pitaka na ito. Nais mo bang magpatuloy?", + "confirm_fee_deduction": "Kumpirmahin ang pagbabawas ng bayad", + "confirm_fee_deduction_content": "Sumasang -ayon ka bang bawasan ang bayad mula sa output?", "confirm_sending": "Kumpirmahin ang pagpapadala", "confirmations": "Mga kumpirmasyon", "confirmed": "Nakumpirma na balanse", @@ -212,6 +215,7 @@ "edit_token": "I -edit ang token", "electrum_address_disclaimer": "Bumubuo kami ng mga bagong address sa tuwing gumagamit ka ng isa, ngunit ang mga nakaraang address ay patuloy na gumagana", "email_address": "Email address", + "enable_replace_by_fee": "Paganahin ang palitan-by-fee", "enabled": "Pinagana", "enter_amount": "Ipasok ang halaga", "enter_backup_password": "Ipasok ang backup password dito", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Nabigo: Error habang kumukuha ng mga kredensyal", "errorSigningTransaction": "May naganap na error habang pinipirmahan ang transaksyon", "estimated": "Tinatayang", + "estimated_new_fee": "Tinatayang bagong bayad", "etherscan_history": "Kasaysayan ng Etherscan", "event": "Kaganapan", "events": "Mga kaganapan", @@ -314,6 +319,7 @@ "in_store": "Nakatago", "incoming": "Papasok", "incorrect_seed": "Ang teksto na ipinasok ay hindi wasto.", + "inputs": "Mga input", "introducing_cake_pay": "Ipinakikilala ang cake pay!", "invalid_input": "Di -wastong input", "invoice_details": "Mga detalye ng invoice", @@ -381,6 +387,7 @@ "offer_expires_in": "Mag -expire ang alok sa:", "offline": "Offline", "ok": "Ok", + "old_fee": "Matandang bayad", "onion_link": "Link ng Onion", "online": "Online", "onramper_option_description": "Mabilis na bumili ng crypto na may maraming paraan ng pagbabayad. Available sa karamihan ng mga bansa. Iba-iba ang mga spread at bayarin.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Ang mga bagong wallets ng Bitcoin na nilikha sa cake ay mayroon na ngayong 24-salitang binhi. Ipinag-uutos na lumikha ka ng isang bagong pitaka ng Bitcoin at ilipat ang lahat ng iyong mga pondo sa bagong 24-salitang pitaka, at itigil ang paggamit ng mga pitaka na may 12-salitang binhi. Mangyaring gawin ito kaagad upang ma -secure ang iyong mga pondo.", "outdated_electrum_wallet_receive_warning": "Kung ang pitaka na ito ay may 12-salitang binhi at nilikha sa cake, huwag magdeposito sa Bitcoin sa pitaka na ito. Ang anumang BTC na inilipat sa pitaka na ito ay maaaring mawala. Lumikha ng isang bagong 24-word wallet (tapikin ang menu sa kanang tuktok, piliin ang mga pitaka, piliin ang Lumikha ng Bagong Wallet, pagkatapos ay piliin ang Bitcoin) at agad na ilipat ang iyong BTC doon. Ang mga bagong (24-salita) BTC Wallets mula sa cake ay ligtas", "outgoing": "Palabas", + "outputs": "Mga output", "overwrite_amount": "Overwrite na halaga", "pairingInvalidEvent": "Pagpares ng Di-wastong Kaganapan", "password": "Password", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 599d5bf67..de197c1b1 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Bitcoin ödemeleri, 20 dakika veya daha uzun sürebilen 1 onay gerektirir. Sabrınız için teşekkürler! Ödeme onaylandığında e-posta ile bilgilendirileceksiniz.", "Blocks_remaining": "${status} Blok Kaldı", "bright_theme": "Parlak", + "bump_fee": "Çarpma ücreti", "buy": "Alış", "buy_alert_content": "Şu anda yalnızca Bitcoin, Ethereum, Litecoin ve Monero satın alımını destekliyoruz. Lütfen Bitcoin, Ethereum, Litecoin veya Monero cüzdanınızı oluşturun veya cüzdanınıza geçin.", "buy_bitcoin": "Bitcoin Satın Al", @@ -133,6 +134,8 @@ "confirm": "Onayla", "confirm_delete_template": "Bu eylem, bu şablonu silecek. Devam etmek istiyor musun?", "confirm_delete_wallet": "Bu eylem, bu cüzdanı silecek. Devam etmek istiyor musun?", + "confirm_fee_deduction": "Ücret kesintisini onaylayın", + "confirm_fee_deduction_content": "Ücreti çıktıdan düşürmeyi kabul ediyor musunuz?", "confirm_sending": "Göndermeyi onayla", "confirmations": "Onay", "confirmed": "Onaylanmış Bakiye", @@ -212,6 +215,7 @@ "edit_token": "Belirteci düzenle", "electrum_address_disclaimer": "Adresini her kullandığında yeni adres oluşturuyoruz, ancak önceki adresler de çalışmaya devam eder", "email_address": "E-posta Adresi", + "enable_replace_by_fee": "Farklı Değiştir'i Etkinleştir", "enabled": "Etkin", "enter_amount": "Miktar Girin", "enter_backup_password": "Yedekleme parolasını buraya gir", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Başarısız: Kimlik bilgileri alınırken hata oluştu", "errorSigningTransaction": "İşlem imzalanırken bir hata oluştu", "estimated": "Tahmini", + "estimated_new_fee": "Tahmini yeni ücret", "etherscan_history": "Etherscan geçmişi", "event": "Etkinlik", "events": "Olaylar", @@ -314,6 +319,7 @@ "in_store": "Mağazada", "incoming": "Gelen", "incorrect_seed": "Girilen metin geçerli değil.", + "inputs": "Girişler", "introducing_cake_pay": "Cake Pay ile tanışın!", "invalid_input": "Geçersiz Giriş", "invoice_details": "fatura detayları", @@ -381,6 +387,7 @@ "offer_expires_in": "Teklifin bitmesine kalan: ", "offline": "Çevrimdışı", "ok": "Tamam", + "old_fee": "Eski ücret", "onion_link": "soğan bağlantısı", "online": "Çevrimiçi", "onramper_option_description": "Birçok ödeme yöntemi ile hızlı bir şekilde kripto satın alın. Çoğu ülkede mevcuttur. Forma ve ücretler değişir.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Cake'te oluşturulan yeni Bitcoin cüzdanları artık 24 kelimelik bir tohuma sahip. Yeni bir Bitcoin cüzdanı oluşturmanız ve tüm paranızı 24 kelimelik yeni cüzdana aktarmanız ve 12 kelimelik tohuma sahip cüzdanları kullanmayı bırakmanız zorunludur. Lütfen paranızı güvence altına almak için bunu hemen yapın.", "outdated_electrum_wallet_receive_warning": "Bu cüzdanın 12 kelimelik bir tohumu varsa ve Cake'te oluşturulduysa, bu cüzdana Bitcoin YATIRMAYIN. Bu cüzdana aktarılan tüm BTC'ler kaybolabilir. 24 kelimelik yeni bir cüzdan oluşturun (sağ üstteki menüye dokunun, Cüzdanlar'ı seçin, Yeni Cüzdan Oluştur'u seçin, ardından Bitcoin'i seçin) ve BTC'nizi HEMEN oraya taşıyın. Cake'in yeni (24 kelimelik) BTC cüzdanları güvenlidir", "outgoing": "Giden", + "outputs": "çıktılar", "overwrite_amount": "Miktarın üzerine yaz", "pairingInvalidEvent": "Geçersiz Etkinliği Eşleştirme", "password": "Parola", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index b0902aada..86e60214b 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Платежі Bitcoin потребують 1 підтвердження, яке може зайняти 20 хвилин або більше. Дякую за Ваше терпіння! Ви отримаєте електронний лист, коли платіж буде підтверджено.", "Blocks_remaining": "${status} Залишилось блоків", "bright_theme": "Яскрава", + "bump_fee": "Підвищити комісію", "buy": "Купити", "buy_alert_content": "Наразі ми підтримуємо купівлю лише Bitcoin, Ethereum, Litecoin і Monero. Створіть або перейдіть на свій гаманець Bitcoin, Ethereum, Litecoin або Monero.", "buy_bitcoin": "Купити Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Підтвердити", "confirm_delete_template": "Ця дія видалить шаблон. Ви хочете продовжити?", "confirm_delete_wallet": "Ця дія видалить гаманець. Ви хочете продовжити?", + "confirm_fee_deduction": "Підтвердьте відрахування комісії", + "confirm_fee_deduction_content": "Чи погоджуєтесь ви вирахувати комісію з сумми одержувача?", "confirm_sending": "Підтвердити відправлення", "confirmations": "Підтвердження", "confirmed": "Підтверджений баланс", @@ -212,6 +215,7 @@ "edit_token": "Редагувати маркер", "electrum_address_disclaimer": "Ми створюємо нові адреси щоразу, коли ви використовуєте їх, але попередні адреси продовжують працювати", "email_address": "Адреса електронної пошти", + "enable_replace_by_fee": "Увімкнути заміну з комісією", "enabled": "Увімкнено", "enter_amount": "Введіть суму", "enter_backup_password": "Введіть пароль резервної копії", @@ -248,6 +252,7 @@ "errorGettingCredentials": "Помилка: помилка під час отримання облікових даних", "errorSigningTransaction": "Під час підписання транзакції сталася помилка", "estimated": "Приблизно ", + "estimated_new_fee": "Орієнтовна нова комісія", "etherscan_history": "Історія Etherscan", "event": "Подія", "events": "Події", @@ -314,6 +319,7 @@ "in_store": "У магазині", "incoming": "Вхідні", "incorrect_seed": "Введений текст невірний.", + "inputs": "Вхoди", "introducing_cake_pay": "Представляємо Cake Pay!", "invalid_input": "Неправильні дані", "invoice_details": "Реквізити рахунку-фактури", @@ -381,6 +387,7 @@ "offer_expires_in": "Пропозиція закінчиться через: ", "offline": "Офлайн", "ok": "OK", + "old_fee": "Стара комісія", "onion_link": "Посилання на цибулю", "online": "Онлайн", "onramper_option_description": "Швидко купуйте криптовалюту з багатьма методами оплати. Доступний у більшості країн. Поширення та збори різняться.", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "Нові біткойн-гаманці, створені в Cake, тепер містять мнемонічну фразу з 24 слів. Обов’язково стовріть новий біткойн-гаманець, переведіть всі кошти на новий гаманець із 24 слів і припиніть використання гаманців із мнемонічною фразою з 12 слів. Зробіть це негайно, щоб убезпечити свої кошти.", "outdated_electrum_wallet_receive_warning": "Якщо цей гаманець має мнемонічну фразу з 12 слів і був створений у Cake, НЕ переводьте біткойни на цей гаманець. Будь-які BTC, переведений на цей гаманець, можуть бути втраченими. Створіть новий гаманець з мнемонічною фразою з 24 слів (торкніться меню у верхньому правому куті, виберіть Гаманці, виберіть Створити новий гаманець, потім виберіть Bitcoin) і НЕГАЙНО переведіть туди свії BTC. Нові (з мнемонічною фразою з 24 слів) гаманці BTC від Cake надійно захищені", "outgoing": "Вихідні", + "outputs": "Виходи", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Недійсна подія сполучення", "password": "Пароль", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 1d4d98f45..725a1d895 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "بٹ کوائن کی ادائیگی میں 1 تصدیق کی ضرورت ہوتی ہے ، جس میں 20 منٹ یا اس سے زیادہ وقت لگ سکتا ہے۔ آپ کے صبر کا شکریہ! ادائیگی کی تصدیق ہونے پر آپ کو ای میل کیا جائے گا۔", "Blocks_remaining": "${status} بلاکس باقی ہیں۔", "bright_theme": "روشن", + "bump_fee": "بمپ فیس", "buy": "خریدنے", "buy_alert_content": "۔ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﺱﺍ ﺎﯾ ﮟﯿﺋﺎﻨﺑ ﭧﯿﻟﺍﻭ Monero ﺎﯾ ،Bitcoin، Ethereum، Litecoin ﺎﻨﭘﺍ ﻡ", "buy_bitcoin": "Bitcoin خریدیں۔", @@ -133,6 +134,8 @@ "confirm": "تصدیق کریں۔", "confirm_delete_template": "یہ عمل اس ٹیمپلیٹ کو حذف کر دے گا۔ کیا آپ جاری رکھنا چاہتے ہیں؟", "confirm_delete_wallet": "اس کارروائی سے یہ پرس حذف ہو جائے گا۔ کیا آپ جاری رکھنا چاہتے ہیں؟", + "confirm_fee_deduction": "فیس میں کٹوتی کی تصدیق کریں", + "confirm_fee_deduction_content": "کیا آپ آؤٹ پٹ سے فیس کم کرنے پر راضی ہیں؟", "confirm_sending": "بھیجنے کی تصدیق کریں۔", "confirmations": "تصدیقات", "confirmed": "تصدیق شدہ بیلنس", @@ -212,6 +215,7 @@ "edit_token": "ٹوکن میں ترمیم کریں۔", "electrum_address_disclaimer": "جب بھی آپ ایک کا استعمال کرتے ہیں تو ہم نئے پتے تیار کرتے ہیں، لیکن پچھلے پتے کام کرتے رہتے ہیں۔", "email_address": "ای میل اڈریس", + "enable_replace_by_fee": "فی فیس کو تبدیل کریں", "enabled": "فعال", "enter_amount": "رقم درج کریں۔", "enter_backup_password": "یہاں بیک اپ پاس ورڈ درج کریں۔", @@ -248,6 +252,7 @@ "errorGettingCredentials": "۔ﯽﺑﺍﺮﺧ ﮟﯿﻣ ﮯﻧﺮﮐ ﻞﺻﺎﺣ ﺩﺎﻨﺳﺍ :ﻡﺎﮐﺎﻧ", "errorSigningTransaction": "۔ﮯﮨ ﯽﺌﮔﺁ ﺶﯿﭘ ﯽﺑﺍﺮﺧ ﮏﯾﺍ ﺖﻗﻭ ﮯﺗﺮﮐ ﻂﺨﺘﺳﺩ ﺮﭘ ﻦﯾﺩ ﻦﯿﻟ", "estimated": "تخمینہ لگایا", + "estimated_new_fee": "تخمینہ شدہ نئی فیس", "etherscan_history": "ﺦﯾﺭﺎﺗ ﯽﮐ ﻦﯿﮑﺳﺍ ﺮﮭﺘﯾﺍ", "event": "ﺐﯾﺮﻘﺗ", "events": "ﺕﺎﺒﯾﺮﻘﺗ", @@ -314,6 +319,7 @@ "in_store": "اسٹور میں", "incoming": "آنے والا", "incorrect_seed": "درج کردہ متن درست نہیں ہے۔", + "inputs": "آدانوں", "introducing_cake_pay": "Cake پے کا تعارف!", "invalid_input": "غلط ان پٹ", "invoice_details": "رسید کی تفصیلات", @@ -381,6 +387,7 @@ "offer_expires_in": "پیشکش کی میعاد اس وقت ختم ہو جاتی ہے:", "offline": "آف لائن", "ok": "ٹھیک ہے", + "old_fee": "پرانی فیس", "onion_link": "پیاز کا لنک", "online": "آن لائن", "onramper_option_description": "ادائیگی کے بہت سے طریقوں سے جلدی سے کرپٹو خریدیں۔ زیادہ تر ممالک میں دستیاب ہے۔ پھیلاؤ اور فیس مختلف ہوتی ہے۔", @@ -399,6 +406,7 @@ "outdated_electrum_wallet_description": "Cake میں بنائے گئے نئے Bitcoin بٹوے میں اب 24 الفاظ کا بیج ہے۔ یہ لازمی ہے کہ آپ ایک نیا Bitcoin والیٹ بنائیں اور اپنے تمام فنڈز کو نئے 24 الفاظ والے والیٹ میں منتقل کریں، اور 12 الفاظ کے بیج والے بٹوے کا استعمال بند کریں۔ براہ کرم اپنے فنڈز کو محفوظ بنانے کے لیے فوری طور پر ایسا کریں۔", "outdated_electrum_wallet_receive_warning": "اگر اس پرس میں 12 الفاظ کا بیج ہے اور اسے Cake میں بنایا گیا ہے، تو اس بٹوے میں Bitcoin جمع نہ کریں۔ اس بٹوے میں منتقل کیا گیا کوئی بھی BTC ضائع ہو سکتا ہے۔ ایک نیا 24 الفاظ والا والیٹ بنائیں (اوپر دائیں جانب مینو کو تھپتھپائیں، Wallets کو منتخب کریں، نیا والیٹ بنائیں، پھر Bitcoin کو منتخب کریں) اور فوری طور پر اپنے BTC کو وہاں منتقل کریں۔ Cake کے نئے (24-لفظوں) BTC بٹوے محفوظ ہیں۔", "outgoing": "سبکدوش ہونے والے", + "outputs": "نتائج", "overwrite_amount": "رقم کو اوور رائٹ کریں۔", "pairingInvalidEvent": "ﭧﻧﻮﯾﺍ ﻂﻠﻏ ﺎﻧﺎﻨﺑ ﺍﮌﻮﺟ", "password": "پاس ورڈ", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 9128427e5..517757716 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "Àwọn àránṣẹ́ Bitcoin nílò ìjẹ́rìísí kan. Ó lè lo ìṣéjú ogun tàbí ìṣéjú jù. A dúpẹ́ fún sùúrù yín! Ẹ máa gba ímeèlì t'ó bá jẹ́rìísí àránṣẹ́ náà.", "Blocks_remaining": "Àkójọpọ̀ ${status} kikù", "bright_theme": "Funfun", + "bump_fee": "Ọya ija", "buy": "Rà", "buy_alert_content": "Lọwọlọwọ a ṣe atilẹyin rira Bitcoin, Ethereum, Litecoin, ati Monero. Jọwọ ṣẹda tabi yipada si Bitcoin, Ethereum, Litecoin, tabi apamọwọ Monero.", "buy_bitcoin": "Ra Bitcoin", @@ -133,6 +134,8 @@ "confirm": "Jẹ́rìísí", "confirm_delete_template": "Ìṣe yìí máa yọ àwòṣe yìí kúrò. Ṣé ẹ fẹ́ tẹ̀síwájú?", "confirm_delete_wallet": "Ìṣe yìí máa yọ àpamọ́wọ́ yìí kúrò. Ṣé ẹ fẹ́ tẹ̀síwájú?", + "confirm_fee_deduction": "Jẹrisi iyọkuro owo", + "confirm_fee_deduction_content": "Ṣe o gba lati yọkuro idiyele naa kuro ni iṣejade?", "confirm_sending": "Jẹ́rìí sí ránṣẹ́", "confirmations": "Àwọn ẹ̀rí", "confirmed": "A ti jẹ́rìí ẹ̀", @@ -213,6 +216,7 @@ "edit_token": "Ṣatunkọ àmi", "electrum_address_disclaimer": "A dá àwọn àdírẹ́sì títun ní gbogbo àwọn ìgbà t'ẹ́ lo ó kan ṣùgbọ́n ẹ lè tẹ̀síwájú lo àwọn àdírẹ́sì tẹ́lẹ̀tẹ́lẹ̀.", "email_address": "Àdírẹ́sì ímeèlì", + "enable_replace_by_fee": "Mu ki o rọpo", "enabled": "Wọ́n tíwọn ti tan", "enter_amount": "Tẹ̀ iye", "enter_backup_password": "Tẹ̀ ọ̀rọ̀ aṣínà ti ẹ̀dà ḿbí", @@ -249,6 +253,7 @@ "errorGettingCredentials": "Kuna: Aṣiṣe lakoko gbigba awọn iwe-ẹri", "errorSigningTransaction": "Aṣiṣe kan ti waye lakoko ti o fowo si iṣowo", "estimated": "Ó tó a fojú díwọ̀n", + "estimated_new_fee": "Ifoju tuntun owo tuntun", "etherscan_history": "Etherscan itan", "event": "Iṣẹlẹ", "events": "Awọn iṣẹlẹ", @@ -315,6 +320,7 @@ "in_store": "A níyí", "incoming": "Wọ́n tó ń bọ̀", "incorrect_seed": "Ọ̀rọ̀ tí a tẹ̀ kì í ṣe èyí.", + "inputs": "Igbewọle", "introducing_cake_pay": "Ẹ bá Cake Pay!", "invalid_input": "Iṣawọle ti ko tọ", "invoice_details": "Iru awọn ẹya ọrọ", @@ -382,6 +388,7 @@ "offer_expires_in": "Ìrònúdábàá máa gbẹ́mìí mì ní: ", "offline": "kò wà lórí ayélujára", "ok": "Ó dáa", + "old_fee": "Oya atijọ", "onion_link": "Kọja ilọ alubosa", "online": "Lórí ayélujára", "onramper_option_description": "Ni kiakia Ra Crypto pẹlu ọpọlọpọ awọn ọna isanwo. Wa ni ọpọlọpọ awọn orilẹ-ede. Itankale ati awọn idiyele yatọ.", @@ -398,6 +405,7 @@ "outdated_electrum_wallet_description": "Àwọn àpamọ́wọ́ títun Bitcoin ti a ti dá nínú Cake Wallet lọ́wọ́lọ́wọ́. Àwọn àpamọ́wọ́ títun t'á dá nínú Cake Wallet ni hóró tó ní ọ̀rọ̀ mẹ́rinlélógún. Ẹ gbọ́dọ̀ dá àpamọ́wọ́. Ẹ sì sún gbogbo owó yín sí àpamọ́wọ́ títun náà tó dá lórí ọ̀rọ̀ mẹ́rinlélógún. Ẹ sì gbọ́dọ̀ yé lo àwọn àpamọ́wọ́ tó dá lórí hóró tó ní ọ̀rọ̀ méjìlá. Ẹ jọ̀wọ́ ṣe èyí láìpẹ́ kí ẹ ba owó yín.", "outdated_electrum_wallet_receive_warning": "Ẹ KÒ FI BITCOIN SÍ ÀPAMỌ́WỌ́ YÌÍ t'á ti dá a nínú Cake Wallet àti àpamọ́wọ́ yìí ni hóró ti ọ̀rọ̀ méjìlá. A lè pàdánù BTC t'á ránṣẹ́ sí àpamọ́wọ́ yìí. Ẹ dá àpamọ́wọ́ títun tó ni hóró tó ni ọ̀rọ̀ mẹ́rinlélógún (Ẹ tẹ àkọsílẹ̀ tó wa l’ókè l'ọ́tún nígbàna, ẹ sì yan àwọn àpamọ́wọ́ nígbàna, ẹ sì yan Dá Àpamọ́wọ́ Títun nígbàna, ẹ sì yan Bitcoin) àti sún Bitcoin yín síbẹ̀ ní sinsìn yẹn. Àwọn àpamọ́wọ́ títun (hóró ni ọ̀rọ̀ mẹ́rinlélógún) láti Cake Wallet wa láìléwu.", "outgoing": "Wọ́n tó ń jáde", + "outputs": "Awọn iṣan", "overwrite_amount": "Pààrọ̀ iye owó", "pairingInvalidEvent": "Pipọpọ Iṣẹlẹ Ti ko tọ", "password": "Ọ̀rọ̀ aṣínà", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index d9ac86b34..104848996 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -79,6 +79,7 @@ "bitcoin_payments_require_1_confirmation": "比特币支付需要 1 次确认,这可能需要 20 分钟或更长时间。谢谢你的耐心!确认付款后,您将收到电子邮件。", "Blocks_remaining": "${status} 剩余的块", "bright_theme": "明亮", + "bump_fee": "撞费", "buy": "购买", "buy_alert_content": "目前我们仅支持购买比特币、以太坊、莱特币和门罗币。请创建或切换到您的比特币、以太坊、莱特币或门罗币钱包。", "buy_bitcoin": "购买比特币", @@ -133,6 +134,8 @@ "confirm": "确认", "confirm_delete_template": "此操作将刪除此模板。确定吗?", "confirm_delete_wallet": "此操作将刪除此钱包。确定吗?", + "confirm_fee_deduction": "确认费用扣除", + "confirm_fee_deduction_content": "您是否同意从产出中扣除费用?", "confirm_sending": "确认发送", "confirmations": "确认", "confirmed": "确认余额", @@ -212,6 +215,7 @@ "edit_token": "编辑令牌", "electrum_address_disclaimer": "每次您使用一个地址时,我们都会生成新地址,但之前的地址仍然有效", "email_address": "电子邮件地址", + "enable_replace_by_fee": "启用by-Fee替换", "enabled": "启用", "enter_amount": "输入金额", "enter_backup_password": "在此处输入備用密码", @@ -248,6 +252,7 @@ "errorGettingCredentials": "失败:获取凭据时出错", "errorSigningTransaction": "签署交易时发生错误", "estimated": "估计值", + "estimated_new_fee": "估计新费用", "etherscan_history": "以太扫描历史", "event": "事件", "events": "活动", @@ -314,6 +319,7 @@ "in_store": "店内", "incoming": "收到", "incorrect_seed": "输入的文字无效。", + "inputs": "输入", "introducing_cake_pay": "介绍 Cake Pay!", "invalid_input": "输入无效", "invoice_details": "发票明细", @@ -381,6 +387,7 @@ "offer_expires_in": "优惠有效期至 ", "offline": "离线", "ok": "确认", + "old_fee": "旧费用", "onion_link": "洋葱链接", "online": "在线", "onramper_option_description": "快速使用许多付款方式购买加密货币。在大多数国家 /地区可用。利差和费用各不相同。", @@ -397,6 +404,7 @@ "outdated_electrum_wallet_description": "在Cake创建的新比特币钱包现在有一个24字的种子。你必须创建一个新的比特币钱包,并将你所有的资金转移到新的24字钱包,并停止使用12字种子的钱包。请立即这样做以保证你的资金安全。", "outdated_electrum_wallet_receive_warning": "如果这个钱包有一个 12 字的种子并且是在 Cake 中创建的,不要将比特币存入这个钱包。 任何转移到此钱包的 BTC 都可能丢失。 创建一个新的 24 字钱包(点击右上角的菜单,选择钱包,选择创建新钱包,然后选择比特币)并立即将您的 BTC 移到那里。 Cake 的新(24 字)BTC 钱包是安全的", "outgoing": "发送", + "outputs": "输出", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "配对无效事件", "password": "密码", diff --git a/scripts/append_translation.sh b/scripts/append_translation.sh deleted file mode 100755 index 0cc33fc0f..000000000 --- a/scripts/append_translation.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# to use on Mac first install the translation shell `brew install translate-shell` -# then install the jq `brew install jq` -# then run this file with the English key and value that you want to be translated -# `./append_translation.sh "greetings" "Hello World!"` -# if you get an error `command not found` -# give the correct permissions to this file using `chmod 777 append_translation.sh` - -langs=("ar" "bg" "cs" "de" "en" "es" "fr" "ha" "hi" "hr" "id" "it" "ja" "ko" "my" "nl" "pl" "pt" "ru" "th" "tl" "tr" "uk" "ur" "yo" "zh") - -name=$1 -text=$2 - -for lang in "${langs[@]}"; do - translation="$(trans en:$lang --brief "$text")" - - # Use jq to add the new key-value pair to the JSON object - jq_result=$(jq '. += { "'"$name"'": "'"$translation"'" }' ../res/values/strings_$lang.arb) - - echo "$jq_result" > ../res/values/strings_$lang.arb - echo 'Added { "'"$name"'": "'"$translation"'" } to '"strings_$lang.arb"'' -done diff --git a/tool/configure.dart b/tool/configure.dart index b3aa44feb..06243e8ab 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -87,6 +87,7 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/litecoin_wallet_service.dart'; +import 'package:cw_bitcoin/pending_bitcoin_transaction.dart'; import 'package:mobx/mobx.dart'; """; const bitcoinCwPart = "part 'cw_bitcoin.dart';"; @@ -135,13 +136,14 @@ abstract class Bitcoin { String formatterBitcoinAmountToString({required int amount}); double formatterBitcoinAmountToDouble({required int amount}); int formatterStringDoubleToBitcoinAmount(String amount); - String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate); + String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate, {int? customRate}); List getUnspents(Object wallet); Future updateUnspents(Object wallet); WalletService createBitcoinWalletService(Box walletInfoSource, Box unspentCoinSource); WalletService createLitecoinWalletService(Box walletInfoSource, Box unspentCoinSource); TransactionPriority getBitcoinTransactionPriorityMedium(); + TransactionPriority getBitcoinTransactionPriorityCustom(); TransactionPriority getLitecoinTransactionPriorityMedium(); TransactionPriority getBitcoinTransactionPrioritySlow(); TransactionPriority getLitecoinTransactionPrioritySlow(); @@ -151,6 +153,12 @@ abstract class Bitcoin { List getBitcoinReceivePageOptions(); BitcoinAddressType getBitcoinAddressType(ReceivePageOption option); bool hasTaprootInput(PendingTransaction pendingTransaction); + + Future replaceByFee(Object wallet, String transactionHash, String fee); + Future canReplaceByFee(Object wallet, String transactionHash); + Future isChangeSufficientForFee(Object wallet, String txId, String newFee); + int getFeeAmountForPriority(Object wallet, TransactionPriority priority, int inputsCount, int outputsCount, {int? size}); + int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount, {int? size}); } """;