diff --git a/cw_lightning/lib/lightning_transaction_history.dart b/cw_lightning/lib/lightning_transaction_history.dart new file mode 100644 index 000000000..6625f8702 --- /dev/null +++ b/cw_lightning/lib/lightning_transaction_history.dart @@ -0,0 +1,90 @@ +import 'dart:convert'; + +import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/transaction_history.dart'; +import 'package:cw_core/utils/file.dart'; +import 'package:cw_core/wallet_info.dart'; +import 'package:cw_lightning/lightning_transaction_info.dart'; +import 'package:mobx/mobx.dart'; + +part 'lightning_transaction_history.g.dart'; + +const transactionsHistoryFileName = 'transactions.json'; + +class LightningTransactionHistory = LightningTransactionHistoryBase + with _$LightningTransactionHistory; + +abstract class LightningTransactionHistoryBase + extends TransactionHistoryBase with Store { + LightningTransactionHistoryBase( + {required this.walletInfo, required String password}) + : _password = password, + _height = 0 { + transactions = ObservableMap(); + } + + final WalletInfo walletInfo; + String _password; + int _height; + + Future init() async => await _load(); + + @override + void addOne(LightningTransactionInfo transaction) => + transactions[transaction.id] = transaction; + + @override + void addMany(Map transactions) => + transactions.forEach((_, tx) => _update(tx)); + + @override + Future save() async { + try { + final dirPath = + await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); + final path = '$dirPath/$transactionsHistoryFileName'; + final data = + json.encode({'height': _height, 'transactions': transactions}); + await writeData(path: path, password: _password, data: data); + } catch (e) { + print('Error while save bitcoin transaction history: ${e.toString()}'); + } + } + + Future changePassword(String password) async { + _password = password; + await save(); + } + + Future> _read() async { + final dirPath = + await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); + final path = '$dirPath/$transactionsHistoryFileName'; + final content = await read(path: path, password: _password); + return json.decode(content) as Map; + } + + Future _load() async { + try { + final content = await _read(); + final txs = content['transactions'] as Map? ?? {}; + + txs.entries.forEach((entry) { + final val = entry.value; + + if (val is Map) { + final tx = LightningTransactionInfo.fromJson(val, walletInfo.type); + _update(tx); + } + }); + + _height = content['height'] as int; + } catch (e) { + print(e); + } + } + + void _update(LightningTransactionInfo transaction) => + transactions[transaction.id] = transaction; + +} diff --git a/cw_lightning/lib/lightning_transaction_info.dart b/cw_lightning/lib/lightning_transaction_info.dart new file mode 100644 index 000000000..78bd016ea --- /dev/null +++ b/cw_lightning/lib/lightning_transaction_info.dart @@ -0,0 +1,122 @@ +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; +import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData; +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_core/transaction_direction.dart'; +import 'package:cw_core/transaction_info.dart'; +import 'package:cw_core/format_amount.dart'; +import 'package:cw_core/wallet_type.dart'; + +class LightningTransactionInfo extends TransactionInfo { + LightningTransactionInfo(this.type, + {required String id, + required int height, + required int amount, + int? fee, + required TransactionDirection direction, + required bool isPending, + required DateTime date, + required int confirmations}) { + this.id = id; + this.height = height; + this.amount = amount; + this.fee = fee; + this.direction = direction; + this.date = date; + this.isPending = isPending; + this.confirmations = confirmations; + } + + factory LightningTransactionInfo.fromHexAndHeader(WalletType type, String hex, + {List? addresses, required int height, int? timestamp, required int confirmations}) { + final tx = bitcoin.Transaction.fromHex(hex); + var exist = false; + var amount = 0; + + if (addresses != null) { + tx.outs.forEach((out) { + try { + final p2pkh = bitcoin.P2PKH( + data: PaymentData(output: out.script), network: bitcoin.bitcoin); + exist = addresses.contains(p2pkh.data.address); + + if (exist) { + amount += out.value!; + } + } catch (_) {} + }); + } + + final date = timestamp != null + ? DateTime.fromMillisecondsSinceEpoch(timestamp * 1000) + : DateTime.now(); + + return LightningTransactionInfo(type, + id: tx.getId(), + height: height, + isPending: false, + fee: null, + direction: TransactionDirection.incoming, + amount: amount, + date: date, + confirmations: confirmations); + } + + factory LightningTransactionInfo.fromJson( + Map data, WalletType type) { + return LightningTransactionInfo(type, + id: data['id'] as String, + height: data['height'] as int, + amount: data['amount'] as int, + fee: data['fee'] as int, + direction: parseTransactionDirectionFromInt(data['direction'] as int), + date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), + isPending: data['isPending'] as bool, + confirmations: data['confirmations'] as int); + } + + final WalletType type; + + String? _fiatAmount; + + @override + String amountFormatted() => + '${formatAmount(bitcoinAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(type).title}'; + + @override + String? feeFormatted() => fee != null + ? '${formatAmount(bitcoinAmountToString(amount: fee!))} ${walletTypeToCryptoCurrency(type).title}' + : ''; + + @override + String fiatAmount() => _fiatAmount ?? ''; + + @override + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount); + + LightningTransactionInfo updated(LightningTransactionInfo info) { + return LightningTransactionInfo(info.type, + id: id, + height: info.height, + amount: info.amount, + fee: info.fee, + direction: direction, + date: date, + isPending: isPending, + confirmations: info.confirmations); + } + + Map toJson() { + final m = {}; + m['id'] = id; + m['height'] = height; + m['amount'] = amount; + m['direction'] = direction.index; + m['date'] = date.millisecondsSinceEpoch; + m['isPending'] = isPending; + m['confirmations'] = confirmations; + m['fee'] = fee; + return m; + } +} diff --git a/cw_lightning/lib/lightning_wallet.dart b/cw_lightning/lib/lightning_wallet.dart index 666d00a6b..6047adcea 100644 --- a/cw_lightning/lib/lightning_wallet.dart +++ b/cw_lightning/lib/lightning_wallet.dart @@ -6,19 +6,20 @@ import 'package:breez_sdk/bridge_generated.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_wallet_keys.dart'; import 'package:cw_bitcoin/electrum.dart'; -import 'package:cw_bitcoin/electrum_balance.dart'; -import 'package:cw_bitcoin/electrum_transaction_history.dart'; -import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/sync_status.dart'; +import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/utils/file.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:cw_lightning/lightning_balance.dart'; +import 'package:cw_lightning/lightning_transaction_history.dart'; +import 'package:cw_lightning/lightning_transaction_info.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:flutter/foundation.dart'; @@ -36,13 +37,13 @@ part 'lightning_wallet.g.dart'; class LightningWallet = LightningWalletBase with _$LightningWallet; -// abstract class LightningWalletBase extends ElectrumWallet with Store { -class LightningWalletBase - extends WalletBase +abstract class LightningWalletBase + extends WalletBase with Store { final bitcoin.HDWallet hd; final String mnemonic; String _password; + bool _isTransactionUpdating; late ElectrumClient electrumClient; @override @@ -77,12 +78,13 @@ class LightningWalletBase syncStatus = NotConnectedSyncStatus(), mnemonic = mnemonic, _password = password, + _isTransactionUpdating = false, balance = ObservableMap.of({ CryptoCurrency.btc: initialBalance ?? const LightningBalance(confirmed: 0, unconfirmed: 0, frozen: 0) }), super(walletInfo) { - transactionHistory = ElectrumTransactionHistory(walletInfo: walletInfo, password: password); + transactionHistory = LightningTransactionHistory(walletInfo: walletInfo, password: password); walletAddresses = BitcoinWalletAddresses(walletInfo, electrumClient: electrumClient ?? ElectrumClient(), initialAddresses: initialAddresses, @@ -182,10 +184,7 @@ class LightningWalletBase } sdk.nodeStateStream.listen((event) { - print("Node state: $event"); if (event == null) return; - int balanceSat = event.maxPayableMsat ~/ 1000; - print("sats: $balanceSat"); balance[CryptoCurrency.btc] = LightningBalance( confirmed: event.maxPayableMsat ~/ 1000, unconfirmed: event.maxReceivableMsat ~/ 1000, @@ -193,6 +192,9 @@ class LightningWalletBase ); }); + // final payments = await sdk.listPayments(req: ListPaymentsRequest()); + // print("payments: $payments"); + print("initialized breez: ${(await sdk.isInitialized())}"); } @@ -206,9 +208,7 @@ class LightningWalletBase Future startSync() async { try { syncStatus = AttemptingSyncStatus(); - - // TODO: CW-563 Implement sync - + await updateTransactions(); syncStatus = SyncedSyncStatus(); } catch (e) { print(e); @@ -230,6 +230,7 @@ class LightningWalletBase Future connectToNode({required Node node}) async { try { syncStatus = ConnectingSyncStatus(); + await updateTransactions(); syncStatus = ConnectedSyncStatus(); } catch (e) { print(e); @@ -242,35 +243,61 @@ class LightningWalletBase throw UnimplementedError("createTransaction"); } - @override - Future> fetchTransactions() async { - // String address = _publicAddress!; + Future updateTransactions() async { + try { + if (_isTransactionUpdating) { + return false; + } - // final transactions = await _client.fetchTransactions(address); - - // final Map result = {}; - - // for (var transactionModel in transactions) { - // final bool isSend = transactionModel.type == "send"; - // result[transactionModel.hash] = NanoTransactionInfo( - // id: transactionModel.hash, - // amountRaw: transactionModel.amount, - // height: transactionModel.height, - // direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming, - // confirmed: transactionModel.confirmed, - // date: transactionModel.date ?? DateTime.now(), - // confirmations: transactionModel.confirmed ? 1 : 0, - // to: isSend ? transactionModel.account : address, - // from: isSend ? address : transactionModel.account, - // ); - // } - - // return result; - return {}; + _isTransactionUpdating = true; + final transactions = await fetchTransactions(); + transactionHistory.addMany(transactions); + await transactionHistory.save(); + _isTransactionUpdating = false; + return true; + } catch (_) { + _isTransactionUpdating = false; + return false; + } } @override - Future rescan({required int height}) async => throw UnimplementedError(); + Future> fetchTransactions() async { + final sdk = await BreezSDK(); + + final payments = await sdk.listPayments(req: ListPaymentsRequest()); + final Map result = {}; + + for (var tx in payments) { + print(tx.details.data); + var details = tx.details.data as LnPaymentDetails; + bool isSend = false; + if (details.lnAddress?.isNotEmpty ?? false) { + isSend = true; + } + if (details.lnurlMetadata?.isNotEmpty ?? false) { + isSend = true; + } + result[tx.id] = LightningTransactionInfo( + WalletType.lightning, + isPending: false, + id: tx.id, + amount: tx.amountMsat ~/ 1000, + fee: tx.feeMsat, + date: DateTime.fromMillisecondsSinceEpoch(tx.paymentTime * 1000), + height: tx.paymentTime, + direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming, + confirmations: 1, + ); + } + + return result; + } + + @override + Future rescan({required int height}) async { + updateTransactions(); + } Future init() async { await walletAddresses.init(); diff --git a/lib/src/screens/receive/lightning_invoice_page.dart b/lib/src/screens/receive/lightning_invoice_page.dart index f4be9bca4..a961646b2 100644 --- a/lib/src/screens/receive/lightning_invoice_page.dart +++ b/lib/src/screens/receive/lightning_invoice_page.dart @@ -247,8 +247,7 @@ class LightningInvoicePage extends BasePage { context: context, builder: (BuildContext context) { return AlertWithTwoActions( - // alertTitle: S.of(context).invoice_created, - alertTitle: "Invoice created TODO: CW-563", + alertTitle: S.of(context).invoice_created, alertContent: state.payload as String, rightButtonText: S.of(context).ok, actionRightButton: () => Navigator.of(context).pop(), diff --git a/lib/src/screens/send/lightning_send_confirm_page.dart b/lib/src/screens/send/lightning_send_confirm_page.dart index 819378a99..bd3c4b19e 100644 --- a/lib/src/screens/send/lightning_send_confirm_page.dart +++ b/lib/src/screens/send/lightning_send_confirm_page.dart @@ -1,50 +1,29 @@ import 'package:breez_sdk/breez_sdk.dart'; import 'package:breez_sdk/bridge_generated.dart'; -import 'package:cake_wallet/core/auth_service.dart'; -import 'package:cake_wallet/entities/fiat_currency.dart'; -import 'package:cake_wallet/entities/template.dart'; -import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart'; -import 'package:cake_wallet/src/screens/send/widgets/send_card.dart'; -import 'package:cake_wallet/src/widgets/add_template_button.dart'; -import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; -import 'package:cake_wallet/src/widgets/picker.dart'; -import 'package:cake_wallet/src/widgets/template_tile.dart'; import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; -import 'package:cake_wallet/themes/extensions/seed_widget_theme.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/themes/theme_base.dart'; -import 'package:cake_wallet/utils/payment_request.dart'; -import 'package:cake_wallet/utils/request_review_handler.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; -import 'package:cake_wallet/view_model/send/output.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cw_bitcoin/bitcoin_amount_format.dart'; +import 'package:cw_core/crypto_currency.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:keyboard_actions/keyboard_actions.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/view_model/send/send_view_model.dart'; -import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/src/widgets/trail_button.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/generated/i18n.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; -import 'package:smooth_page_indicator/smooth_page_indicator.dart'; -import 'package:cw_core/crypto_currency.dart'; class LightningSendConfirmPage extends BasePage { - LightningSendConfirmPage({this.invoice}) : _formKey = GlobalKey(); + LightningSendConfirmPage({required this.invoice}) : _formKey = GlobalKey(); final GlobalKey _formKey; final controller = PageController(initialPage: 0); - LNInvoice? invoice; + LNInvoice invoice; final bolt11Controller = TextEditingController(); final _bolt11FocusNode = FocusNode(); @@ -114,23 +93,6 @@ class LightningSendConfirmPage extends BasePage { Navigator.of(context).pop(); } - // @override - // Widget? middle(BuildContext context) { - // final supMiddle = super.middle(context); - // return Row( - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // Padding( - // padding: const EdgeInsets.only(right: 8.0), - // child: Observer( - // builder: (_) => SyncIndicatorIcon(isSynced: sendViewModel.isReadyForSend), - // ), - // ), - // if (supMiddle != null) supMiddle - // ], - // ); - // } - @override Widget body(BuildContext context) { _setEffects(context); @@ -176,23 +138,81 @@ class LightningSendConfirmPage extends BasePage { child: Observer(builder: (_) { return Padding( padding: EdgeInsets.fromLTRB(24, 120, 24, 0), - child: BaseTextFormField( - controller: bolt11Controller, - focusNode: _bolt11FocusNode, - textInputAction: TextInputAction.next, - borderColor: Theme.of(context) - .extension()! - .textFieldBorderTopPanelColor, - suffixIcon: SizedBox(width: 36), - hintText: S.of(context).invoice_details, - placeholderTextStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.hintTextColor, - ), - textStyle: - TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), - validator: null, + child: Column( + children: [ + BaseTextFormField( + enabled: false, + borderColor: Theme.of(context) + .extension()! + .textFieldBorderTopPanelColor, + suffixIcon: SizedBox(width: 36), + initialValue: "${S.of(context).invoice}: ${invoice.bolt11}", + placeholderTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.hintTextColor, + ), + textStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + validator: null, + ), + SizedBox(height: 24), + BaseTextFormField( + enabled: false, + borderColor: Theme.of(context) + .extension()! + .textFieldBorderTopPanelColor, + suffixIcon: SizedBox(width: 36), + initialValue: + "sats: ${bitcoinAmountToLightningString(amount: (invoice.amountMsat ?? 0) ~/ 1000)}", + placeholderTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.hintTextColor, + ), + textStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + validator: null, + ), + SizedBox(height: 24), + BaseTextFormField( + enabled: false, + initialValue: "USD: ${invoice.amountMsat}", + borderColor: Theme.of(context) + .extension()! + .textFieldBorderTopPanelColor, + suffixIcon: SizedBox(width: 36), + placeholderTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.hintTextColor, + ), + textStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + validator: null, + ), + SizedBox(height: 24), + if (invoice.description?.isNotEmpty ?? false) ...[ + BaseTextFormField( + enabled: false, + initialValue: "${S.of(context).description}: ${invoice.description}", + textInputAction: TextInputAction.next, + borderColor: Theme.of(context) + .extension()! + .textFieldBorderTopPanelColor, + suffixIcon: SizedBox(width: 36), + placeholderTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.hintTextColor, + ), + textStyle: TextStyle( + fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + validator: null, + ), + SizedBox(height: 24), + ], + ], ), ); }), @@ -201,27 +221,36 @@ class LightningSendConfirmPage extends BasePage { bottomSection: Observer(builder: (_) { return Column( children: [ - // Padding( - // padding: EdgeInsets.only(bottom: 15), - // child: Center( - // child: Text( - // S.of(context).anonpay_description("an invoice", "pay"), - // textAlign: TextAlign.center, - // style: TextStyle( - // color: Theme.of(context) - // .extension()! - // .receiveAmountColor, - // fontWeight: FontWeight.w500, - // fontSize: 12), - // ), - // ), - // ), LoadingPrimaryButton( text: S.of(context).send, onPressed: () async { - FocusScope.of(context).unfocus(); - // sendViewModel.send(bolt11Controller.text); - final sdk = await BreezSDK(); + try { + final sdk = await BreezSDK(); + await sdk.sendPayment(req: SendPaymentRequest(bolt11: invoice.bolt11)); + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: '', + alertContent: S + .of(context) + .send_success(CryptoCurrency.btc.toString()), + buttonText: S.of(context).ok, + buttonAction: () { + Navigator.of(context).pop(); + }); + }); + } catch (e) { + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: e.toString(), + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); + } }, color: Theme.of(context).primaryColor, textColor: Colors.white, @@ -246,80 +275,6 @@ class LightningSendConfirmPage extends BasePage { return; } - // reaction((_) => sendViewModel.state, (ExecutionState state) { - // if (state is FailureState) { - // WidgetsBinding.instance.addPostFrameCallback((_) { - // showPopUp( - // context: context, - // builder: (BuildContext context) { - // return AlertWithOneAction( - // alertTitle: S.of(context).error, - // alertContent: state.error, - // buttonText: S.of(context).ok, - // buttonAction: () => Navigator.of(context).pop()); - // }); - // }); - // } - - // if (state is ExecutedSuccessfullyState) { - // WidgetsBinding.instance.addPostFrameCallback((_) { - // if (context.mounted) { - // showPopUp( - // context: context, - // builder: (BuildContext _dialogContext) { - // return ConfirmSendingAlert( - // alertTitle: S.of(_dialogContext).confirm_sending, - // amount: S.of(_dialogContext).send_amount, - // amountValue: sendViewModel.pendingTransaction!.amountFormatted, - // fiatAmountValue: sendViewModel.pendingTransactionFiatAmountFormatted, - // fee: S.of(_dialogContext).send_fee, - // feeValue: sendViewModel.pendingTransaction!.feeFormatted, - // feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmountFormatted, - // outputs: sendViewModel.outputs, - // rightButtonText: S.of(_dialogContext).send, - // leftButtonText: S.of(_dialogContext).cancel, - // actionRightButton: () { - // Navigator.of(_dialogContext).pop(); - // sendViewModel.commitTransaction(); - // showPopUp( - // context: context, - // builder: (BuildContext _dialogContext) { - // return Observer(builder: (_) { - // final state = sendViewModel.state; - - // if (state is FailureState) { - // Navigator.of(_dialogContext).pop(); - // } - - // if (state is TransactionCommitted) { - // return AlertWithOneAction( - // alertTitle: '', - // alertContent: S.of(_dialogContext).send_success( - // sendViewModel.selectedCryptoCurrency.toString()), - // buttonText: S.of(_dialogContext).ok, - // buttonAction: () { - // Navigator.of(_dialogContext).pop(); - // RequestReviewHandler.requestReview(); - // }); - // } - - // return Offstage(); - // }); - // }); - // }, - // actionLeftButton: () => Navigator.of(_dialogContext).pop()); - // }); - // } - // }); - // } - - // if (state is TransactionCommitted) { - // WidgetsBinding.instance.addPostFrameCallback((_) { - // sendViewModel.clearOutputs(); - // }); - // } - // }); - _effectsInstalled = true; } } diff --git a/lib/src/screens/send/lightning_send_page.dart b/lib/src/screens/send/lightning_send_page.dart index 95ef34b4b..d3e6be268 100644 --- a/lib/src/screens/send/lightning_send_page.dart +++ b/lib/src/screens/send/lightning_send_page.dart @@ -160,71 +160,57 @@ class LightningSendPage extends BasePage { ), ) : null, - child: Observer(builder: (_) { - return Padding( - padding: EdgeInsets.fromLTRB(24, 120, 24, 0), - child: BaseTextFormField( - controller: bolt11Controller, - focusNode: _bolt11FocusNode, - textInputAction: TextInputAction.next, - borderColor: Theme.of(context) - .extension()! - .textFieldBorderTopPanelColor, - suffixIcon: SizedBox(width: 36), - hintText: S.of(context).invoice_details, - placeholderTextStyle: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.hintTextColor, + child: Padding( + padding: EdgeInsets.fromLTRB(24, 120, 24, 0), + child: Column( + children: [ + BaseTextFormField( + controller: bolt11Controller, + focusNode: _bolt11FocusNode, + textInputAction: TextInputAction.next, + borderColor: Theme.of(context) + .extension()! + .textFieldBorderTopPanelColor, + suffixIcon: SizedBox(width: 36), + hintText: S.of(context).invoice_details, + placeholderTextStyle: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.hintTextColor, + ), + textStyle: + TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), + validator: null, ), - textStyle: - TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white), - validator: null, - ), - ); - }), + SizedBox(height: 24), + ], + ), + ), ), bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24), - bottomSection: Observer(builder: (_) { - return Column( - children: [ - // Padding( - // padding: EdgeInsets.only(bottom: 15), - // child: Center( - // child: Text( - // S.of(context).anonpay_description("an invoice", "pay"), - // textAlign: TextAlign.center, - // style: TextStyle( - // color: Theme.of(context) - // .extension()! - // .receiveAmountColor, - // fontWeight: FontWeight.w500, - // fontSize: 12), - // ), - // ), - // ), - LoadingPrimaryButton( - text: S.of(context).paste, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - isLoading: false, - onPressed: () async { - processInput(context); - }, - ), - const SizedBox(height: 16), - LoadingPrimaryButton( - text: S.of(context).scan_qr_code, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - isLoading: false, - onPressed: () async { - processInput(context); - }, - ), - ], - ); - }), + bottomSection: Column( + children: [ + LoadingPrimaryButton( + text: S.of(context).paste, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + isLoading: false, + onPressed: () async { + processInput(context); + }, + ), + const SizedBox(height: 16), + LoadingPrimaryButton( + text: S.of(context).scan_qr_code, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + isLoading: false, + onPressed: () async { + processInput(context); + }, + ), + ], + ), ), ), ), diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart index 6c7a6ee51..aaaabed0c 100644 --- a/lib/view_model/dashboard/balance_view_model.dart +++ b/lib/view_model/dashboard/balance_view_model.dart @@ -142,7 +142,7 @@ abstract class BalanceViewModelBase with Store { case WalletType.banano: return S.current.receivable_balance; case WalletType.lightning: - return "CW-563 Max Receivable"; + return S.current.max_receivable; default: return S.current.unconfirmed; } diff --git a/lib/view_model/lightning_view_model.dart b/lib/view_model/lightning_view_model.dart index aa6aedbc2..fd926be19 100644 --- a/lib/view_model/lightning_view_model.dart +++ b/lib/view_model/lightning_view_model.dart @@ -92,10 +92,9 @@ abstract class LightningViewModelBase with Store { amountMsat: 1000, description: 'limits', ); - // final res = await sdk.receivePayment(req: req); - // print(res.lnInvoice.); - // return res.lnInvoice.bolt11; + final res = await sdk.receivePayment(req: req); + // sdk. // TODO: CW-563 figure out how to get the limits - return ['0', '20000']; + return [(res.openingFeeMsat).toString(), '20000']; } } diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 254e52c0d..885e2efe0 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -377,8 +377,6 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor case WalletType.polygon: return polygon!.createPolygonTransactionCredentials(outputs, priority: priority!, currency: selectedCryptoCurrency); - case WalletType.lightning: - throw Exception("TODO: CW-563 Implement lightning tx send!"); default: throw Exception('Unexpected wallet type: ${wallet.type}'); } diff --git a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart index 377e4173b..ffeeebb22 100644 --- a/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart +++ b/lib/view_model/wallet_address_list/wallet_address_list_view_model.dart @@ -80,6 +80,16 @@ class BitcoinURI extends PaymentURI { } } +class LightningURI extends PaymentURI { + LightningURI({required String amount, required String address}) + : super(amount: amount, address: address); + + @override + String toString() { + throw Exception('TODO: Not implemented'); + } +} + class LitecoinURI extends PaymentURI { LitecoinURI({required String amount, required String address}) : super(amount: amount, address: address); @@ -238,8 +248,7 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo } if (wallet.type == WalletType.lightning) { - // TODO: CW-563 - return BitcoinURI(amount: amount, address: address.address); + return LightningURI(amount: amount, address: address.address); } if (wallet.type == WalletType.litecoin) { diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 553262f79..01c6a4783 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -312,6 +312,8 @@ "incorrect_seed": "النص الذي تم إدخاله غير صالح.", "introducing_cake_pay": "نقدم لكم Cake Pay!", "invalid_input": "مدخل غير صالح", + "invoice": "فاتورة", + "invoice_created": "الفاتورة التي تم إنشاؤها", "invoice_details": "تفاصيل الفاتورة", "is_percentage": "يكون", "last_30_days": "آخر 30 يومًا", @@ -329,6 +331,7 @@ "market_place": "منصة التجارة", "matrix_green_dark_theme": "موضوع ماتريكس الأخضر الداكن", "max_amount": "الحد الأقصى: ${value}", + "max_receivable": "ماكس القبض", "max_value": "الحد الأقصى: ${value} ${currency}", "memo": "مذكرة:", "message": "ﺔﻟﺎﺳﺭ", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 8d89f463b..cbf4ff851 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Въведеният текст е невалиден.", "introducing_cake_pay": "Запознайте се с Cake Pay!", "invalid_input": "Невалиден вход", + "invoice": "Фактура", + "invoice_created": "Създадена фактура", "invoice_details": "IДанни за фактура", "is_percentage": "е", "last_30_days": "Последните 30 дни", @@ -329,6 +331,7 @@ "market_place": "Магазин", "matrix_green_dark_theme": "Зелена тъмна тема Matrix", "max_amount": "Макс: ${value}", + "max_receivable": "Макс вземания", "max_value": "Макс: ${value} ${currency}", "memo": "Мемо:", "message": "Съобщение", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index e81eab570..492d2a4df 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Zadaný text není správný.", "introducing_cake_pay": "Představujeme Cake Pay!", "invalid_input": "Neplatný vstup", + "invoice": "Faktura", + "invoice_created": "Faktura vytvořená", "invoice_details": "detaily faktury", "is_percentage": "je", "last_30_days": "Posledních 30 dnů", @@ -329,6 +331,7 @@ "market_place": "Obchod", "matrix_green_dark_theme": "Tmavé téma Matrix Green", "max_amount": "Max: ${value}", + "max_receivable": "Max pohledávka", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Zpráva", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 3ca972af4..70bfbad2d 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Der eingegebene Text ist ungültig.", "introducing_cake_pay": "Einführung von Cake Pay!", "invalid_input": "Ungültige Eingabe", + "invoice": "Rechnung", + "invoice_created": "Rechnung erstellt", "invoice_details": "Rechnungs-Details", "is_percentage": "ist", "last_30_days": "Letzte 30 Tage", @@ -329,6 +331,7 @@ "market_place": "Marktplatz", "matrix_green_dark_theme": "Matrix Green Dark Theme", "max_amount": "Max: ${value}", + "max_receivable": "Max. Forderung", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Nachricht", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 2db7602c1..68a348337 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -312,6 +312,8 @@ "incorrect_seed": "The text entered is not valid.", "introducing_cake_pay": "Introducing Cake Pay!", "invalid_input": "Invalid input", + "invoice": "Invoice", + "invoice_created": "Invoice created", "invoice_details": "Invoice details", "is_percentage": "is", "last_30_days": "Last 30 days", @@ -329,6 +331,7 @@ "market_place": "Marketplace", "matrix_green_dark_theme": "Matrix Green Dark Theme", "max_amount": "Max: ${value}", + "max_receivable": "Max Receivable", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Message", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 5ca5ff4d3..d9b222d01 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -312,6 +312,8 @@ "incorrect_seed": "El texto ingresado no es válido.", "introducing_cake_pay": "¡Presentamos Cake Pay!", "invalid_input": "Entrada inválida", + "invoice": "Factura", + "invoice_created": "Factura creada", "invoice_details": "Detalles de la factura", "is_percentage": "es", "last_30_days": "Últimos 30 días", @@ -329,6 +331,7 @@ "market_place": "Mercado", "matrix_green_dark_theme": "Matrix verde oscuro tema", "max_amount": "Máx: ${value}", + "max_receivable": "Max por cobrar", "max_value": "Max: ${value} ${currency}", "memo": "Memorándum:", "message": "Mensaje", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index aee967d21..87d6be4cf 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Le texte entré est invalide.", "introducing_cake_pay": "Présentation de Cake Pay !", "invalid_input": "Entrée invalide", + "invoice": "Facture", + "invoice_created": "Facture créée", "invoice_details": "Détails de la facture", "is_percentage": "est", "last_30_days": "30 derniers jours", @@ -329,6 +331,7 @@ "market_place": "Place de marché", "matrix_green_dark_theme": "Thème Matrix Green Dark", "max_amount": "Max : ${value}", + "max_receivable": "Max à recevoir", "max_value": "Max: ${value} ${currency}", "memo": "Mémo :", "message": "Message", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index dfffa8a8b..9f2226a3c 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -312,6 +312,8 @@ "incorrect_seed": "rubutun da aka shigar ba shi da inganci.", "introducing_cake_pay": "Gabatar da Cake Pay!", "invalid_input": "Shigar da ba daidai ba", + "invoice": "Daftari", + "invoice_created": "Invoice ya kirkira", "invoice_details": "Bayanin wadannan", "is_percentage": "shine", "last_30_days": "Kwanaki 30 na ƙarshe", @@ -329,6 +331,7 @@ "market_place": "Kasuwa", "matrix_green_dark_theme": "Matrix Green Dark Jigo", "max_amount": "Max: ${value}", + "max_receivable": "Max mai karba", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Sako", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index e67b00726..c838ad785 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -312,6 +312,8 @@ "incorrect_seed": "दर्ज किया गया पाठ मान्य नहीं है।", "introducing_cake_pay": "परिचय Cake Pay!", "invalid_input": "अमान्य निवेश", + "invoice": "चालान", + "invoice_created": "चालान बनाया गया", "invoice_details": "चालान विवरण", "is_percentage": "है", "last_30_days": "पिछले 30 दिन", @@ -329,6 +331,7 @@ "market_place": "मार्केटप्लेस", "matrix_green_dark_theme": "मैट्रिक्स ग्रीन डार्क थीम", "max_amount": "अधिकतम: ${value}", + "max_receivable": "अधिकतम प्राप्य", "max_value": "मैक्स: ${value} ${currency}", "memo": "ज्ञापन:", "message": "संदेश", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index c2fee8420..b942ffa02 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Uneseni tekst nije valjan.", "introducing_cake_pay": "Predstavljamo Cake Pay!", "invalid_input": "Pogrešan unos", + "invoice": "Dostavnica", + "invoice_created": "Račun stvoren", "invoice_details": "Podaci o fakturi", "is_percentage": "je", "last_30_days": "Zadnjih 30 dana", @@ -329,6 +331,7 @@ "market_place": "Tržnica", "matrix_green_dark_theme": "Matrix Green Dark Theme", "max_amount": "Maksimum: ${value}", + "max_receivable": "Maksimalno potraživanje", "max_value": "Maks.: ${value} ${currency}", "memo": "Memo:", "message": "Poruka", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 28a7df3c9..f3cf552cf 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Teks yang dimasukkan tidak valid.", "introducing_cake_pay": "Perkenalkan Cake Pay!", "invalid_input": "Masukan tidak valid", + "invoice": "Faktur", + "invoice_created": "Faktur dibuat", "invoice_details": "Detail faktur", "is_percentage": "adalah", "last_30_days": "30 hari terakhir", @@ -329,6 +331,7 @@ "market_place": "Pasar", "matrix_green_dark_theme": "Tema Matrix Green Dark", "max_amount": "Max: ${value}", + "max_receivable": "Piutang maksimum", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Pesan", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 42f0b8d86..effd62c89 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -313,6 +313,8 @@ "incorrect_seed": "Il testo inserito non è valido.", "introducing_cake_pay": "Presentazione di Cake Pay!", "invalid_input": "Inserimento non valido", + "invoice": "Fattura", + "invoice_created": "Fattura creata", "invoice_details": "Dettagli della fattura", "is_percentage": "è", "last_30_days": "Ultimi 30 giorni", @@ -330,6 +332,7 @@ "market_place": "Mercato", "matrix_green_dark_theme": "Tema Matrix verde scuro", "max_amount": "Max: ${value}", + "max_receivable": "Ricevibile massimo", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Messaggio", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index f4b014909..922037b1a 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -313,6 +313,8 @@ "incorrect_seed": "入力されたテキストは無効です。", "introducing_cake_pay": "序章Cake Pay!", "invalid_input": "無効入力", + "invoice": "請求書", + "invoice_created": "作成された請求書", "invoice_details": "請求の詳細", "is_percentage": "is", "last_30_days": "過去30日", @@ -330,6 +332,7 @@ "market_place": "Marketplace", "matrix_green_dark_theme": "マトリックスグリーンダークテーマ", "max_amount": "最大: ${value}", + "max_receivable": "最大売掛金", "max_value": "マックス: ${value} ${currency}", "memo": "メモ:", "message": "メッセージ", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 7af7376ce..bb520a54f 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -312,6 +312,8 @@ "incorrect_seed": "입력하신 텍스트가 유효하지 않습니다.", "introducing_cake_pay": "소개 Cake Pay!", "invalid_input": "잘못된 입력", + "invoice": "송장", + "invoice_created": "송장 생성", "invoice_details": "인보이스 세부정보", "is_percentage": "이다", "last_30_days": "지난 30일", @@ -329,6 +331,7 @@ "market_place": "마켓플레이스", "matrix_green_dark_theme": "매트릭스 그린 다크 테마", "max_amount": "최대: ${value}", + "max_receivable": "MAX 미수금", "max_value": "맥스: ${value} ${currency}", "memo": "메모:", "message": "메시지", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 6cba70ab2..5bfeaf273 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -312,6 +312,8 @@ "incorrect_seed": "ထည့်သွင်းထားသော စာသားသည် မမှန်ကန်ပါ။", "introducing_cake_pay": "Cake Pay ကို မိတ်ဆက်ခြင်း။", "invalid_input": "ထည့်သွင်းမှု မမှန်ကန်ပါ။", + "invoice": "ဝယ်ကုန်စာရင်း", + "invoice_created": "ငွေတောင်းခံလွှာကိုဖန်တီးခဲ့သည်", "invoice_details": "ပြေစာအသေးစိတ်", "is_percentage": "သည်", "last_30_days": "လွန်ခဲ့သော ရက် 30", @@ -329,6 +331,7 @@ "market_place": "ဈေး", "matrix_green_dark_theme": "Matrix Green Dark အပြင်အဆင်", "max_amount": "အများဆုံး- ${value}", + "max_receivable": "max ကိုလက်ခံရရှိ", "max_value": "အများဆုံး- ${value} ${currency}", "memo": "မှတ်စုတို:", "message": "မက်ဆေ့ချ်", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 19451da27..c418e53ca 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -312,6 +312,8 @@ "incorrect_seed": "De ingevoerde tekst is niet geldig.", "introducing_cake_pay": "Introductie van Cake Pay!", "invalid_input": "Ongeldige invoer", + "invoice": "Factuur", + "invoice_created": "Factuur gemaakt", "invoice_details": "Factuurgegevens", "is_percentage": "is", "last_30_days": "Laatste 30 dagen", @@ -329,6 +331,7 @@ "market_place": "Marktplaats", "matrix_green_dark_theme": "Matrix groen donker thema", "max_amount": "Max: ${value}", + "max_receivable": "Max -vordering", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Bericht", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 74aafd014..71cb2b6c6 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Wprowadzony seed jest nieprawidłowy.", "introducing_cake_pay": "Przedstawiamy Cake Pay!", "invalid_input": "Nieprawidłowe dane wejściowe", + "invoice": "Faktura", + "invoice_created": "Utworzona faktura", "invoice_details": "Dane do faktury", "is_percentage": "jest", "last_30_days": "Ostatnie 30 dni", @@ -329,6 +331,7 @@ "market_place": "Rynek", "matrix_green_dark_theme": "Matrix Zielony ciemny motyw", "max_amount": "Max: ${value}", + "max_receivable": "MAX NECTIVET", "max_value": "Max: ${value} ${currency}", "memo": "Notatka:", "message": "Wiadomość", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 53d93fe75..334b26e2f 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -312,6 +312,8 @@ "incorrect_seed": "O texto digitado não é válido.", "introducing_cake_pay": "Apresentando o Cake Pay!", "invalid_input": "Entrada inválida", + "invoice": "Fatura", + "invoice_created": "Fatura criada", "invoice_details": "Detalhes da fatura", "is_percentage": "é", "last_30_days": "Últimos 30 dias", @@ -330,6 +332,7 @@ "market_place": "Mercado", "matrix_green_dark_theme": "Tema escuro verde matrix", "max_amount": "Máx.: ${valor}", + "max_receivable": "Max a receber", "max_value": "Máx: ${value} ${currency}", "memo": "Memorando:", "message": "Mensagem", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 89a25db06..e6de959ac 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Введённый текст некорректный.", "introducing_cake_pay": "Представляем Cake Pay!", "invalid_input": "Неверный Ввод", + "invoice": "Счет", + "invoice_created": "Счет -фактор создан", "invoice_details": "Детали счета", "is_percentage": "есть", "last_30_days": "Последние 30 дней", @@ -329,6 +331,7 @@ "market_place": "Торговая площадка", "matrix_green_dark_theme": "Матрица Зеленая Темная Тема", "max_amount": "Макс.: ${value}", + "max_receivable": "Максимальная дебиторская задолженность", "max_value": "Макс: ${value} ${currency}", "memo": "Памятка:", "message": "Сообщение", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index ef8992329..c64721a00 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -312,6 +312,8 @@ "incorrect_seed": "ข้อความที่ป้อนไม่ถูกต้อง", "introducing_cake_pay": "ยินดีต้อนรับสู่ Cake Pay!", "invalid_input": "อินพุตไม่ถูกต้อง", + "invoice": "ใบแจ้งหนี้", + "invoice_created": "สร้างใบแจ้งหนี้", "invoice_details": "รายละเอียดใบแจ้งหนี้", "is_percentage": "เป็น", "last_30_days": "30 วันล่าสุด", @@ -329,6 +331,7 @@ "market_place": "ตลาดพื้นที่", "matrix_green_dark_theme": "ธีมเมทริกซ์สีเขียวเข้ม", "max_amount": "จำนวนสูงสุด: ${value}", + "max_receivable": "ลูกหนี้สูงสุด", "max_value": "ขั้นสูง: ${value} ${currency}", "memo": "หมายเหตุ:", "message": "ข้อความ", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 55b6adb51..7e47d07ef 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Ang teksto na ipinasok ay hindi wasto.", "introducing_cake_pay": "Ipinakikilala ang cake pay!", "invalid_input": "Di -wastong input", + "invoice": "Invoice", + "invoice_created": "Nilikha ang Invoice", "invoice_details": "Mga detalye ng invoice", "is_percentage": "ay", "last_30_days": "Huling 30 araw", @@ -329,6 +331,7 @@ "market_place": "Marketplace", "matrix_green_dark_theme": "Matrix Green Madilim na Tema", "max_amount": "Max: ${value}", + "max_receivable": "MAX RECEIVABLE", "max_value": "Max: ${value} ${currency}", "memo": "Memo:", "message": "Mensahe", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index e6cab5027..86ab454e2 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Girilen metin geçerli değil.", "introducing_cake_pay": "Cake Pay ile tanışın!", "invalid_input": "Geçersiz Giriş", + "invoice": "Fatura", + "invoice_created": "Fatura Oluşturuldu", "invoice_details": "fatura detayları", "is_percentage": "is", "last_30_days": "Son 30 gün", @@ -329,6 +331,7 @@ "market_place": "Pazar Alanı", "matrix_green_dark_theme": "Matrix Yeşil Koyu Tema", "max_amount": "Maks: ${value}", + "max_receivable": "Maksimum alacak", "max_value": "En fazla: ${value} ${currency}", "memo": "Memo:", "message": "İleti", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index e81d97021..90102dc1f 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -312,6 +312,8 @@ "incorrect_seed": "Введений текст невірний.", "introducing_cake_pay": "Представляємо Cake Pay!", "invalid_input": "Неправильні дані", + "invoice": "Рахунок -фактура", + "invoice_created": "Створений рахунок -фактури", "invoice_details": "Реквізити рахунку-фактури", "is_percentage": "є", "last_30_days": "Останні 30 днів", @@ -329,6 +331,7 @@ "market_place": "Ринок", "matrix_green_dark_theme": "Зелена темна тема Matrix", "max_amount": "Макс: ${value}", + "max_receivable": "Максимальна дебіторська заборгованість", "max_value": "Макс: ${value} ${currency}", "memo": "Пам’ятка:", "message": "повідомлення", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 465fac003..387db7354 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -312,6 +312,8 @@ "incorrect_seed": "درج کردہ متن درست نہیں ہے۔", "introducing_cake_pay": "Cake پے کا تعارف!", "invalid_input": "غلط ان پٹ", + "invoice": "انوائس", + "invoice_created": "انوائس تخلیق کیا گیا", "invoice_details": "رسید کی تفصیلات", "is_percentage": "ہے", "last_30_days": "آخری 30 دن", @@ -329,6 +331,7 @@ "market_place": "بازار", "matrix_green_dark_theme": "میٹرکس گرین ڈارک تھیم", "max_amount": "زیادہ سے زیادہ: ${value}", + "max_receivable": "زیادہ سے زیادہ قابل وصول", "max_value": "زیادہ سے زیادہ: ${value} ${currency}", "memo": "میمو:", "message": "ﻡﺎﻐﯿﭘ", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index c88f488cd..22e4a181b 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -313,6 +313,8 @@ "incorrect_seed": "Ọ̀rọ̀ tí a tẹ̀ kì í ṣe èyí.", "introducing_cake_pay": "Ẹ bá Cake Pay!", "invalid_input": "Iṣawọle ti ko tọ", + "invoice": "Iye-owo ọja", + "invoice_created": "Risiti da", "invoice_details": "Iru awọn ẹya ọrọ", "is_percentage": "jẹ́", "last_30_days": "Ọ̀jọ̀ mọ́gbọ̀n tó kọjà", @@ -330,6 +332,7 @@ "market_place": "Ọjà", "matrix_green_dark_theme": "Matrix Green Dark Akori", "max_amount": "kò tóbi ju: ${value}", + "max_receivable": "Max gba", "max_value": "kò gbọ́dọ̀ tóbi ju ${value} ${currency}", "memo": "Àkọsílẹ̀:", "message": "Ifiranṣẹ", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index 7e05d4471..0ca23c9a6 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -312,6 +312,8 @@ "incorrect_seed": "输入的文字无效。", "introducing_cake_pay": "介绍 Cake Pay!", "invalid_input": "输入无效", + "invoice": "发票", + "invoice_created": "创建了发票", "invoice_details": "发票明细", "is_percentage": "是", "last_30_days": "过去 30 天", @@ -329,6 +331,7 @@ "market_place": "市场", "matrix_green_dark_theme": "矩阵绿暗主题", "max_amount": "最大值: ${value}", + "max_receivable": "最大应收", "max_value": "最大: ${value} ${currency}", "memo": "备忘录:", "message": "信息",