CAKE-345 | added monero_output.dart to the app; fixed transaction_history.dart; renamed SendItem on Output; calculated formattedCryptoAmount in the output.dart; used outputs list instead sendItemList; fixed bitcoin_transaction_credentials.dart, electrum_wallet.dart, monero_transaction_creation_credentials.dart, monero_wallet.dart, exchange and send pages, view models

This commit is contained in:
OleksandrSobol 2021-08-10 17:52:35 +03:00
parent 1dd3f69b1c
commit 1e3ec8da1c
15 changed files with 191 additions and 188 deletions

View file

@ -0,0 +1,8 @@
import 'package:flutter/foundation.dart';
class MoneroOutput {
MoneroOutput({@required this.address, @required this.amount});
final String address;
final String amount;
}

View file

@ -1,5 +1,6 @@
import 'dart:ffi';
import 'package:cw_monero/convert_utf8_to_string.dart';
import 'package:cw_monero/monero_output.dart';
import 'package:cw_monero/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
@ -107,21 +108,21 @@ PendingTransactionDescription createTransactionSync(
}
PendingTransactionDescription createTransactionMultDestSync(
{List<String> addresses,
{List<MoneroOutput> outputs,
String paymentId,
List<String> amounts,
int size,
int priorityRaw,
int accountIndex = 0}) {
final List<Pointer<Utf8>> addressesPointers = addresses.map(Utf8.toUtf8).toList();
final int size = outputs.length;
final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
Utf8.toUtf8(output.address)).toList();
final Pointer<Pointer<Utf8>> addressesPointerPointer = allocate(count: size);
final List<Pointer<Utf8>> amountsPointers = amounts.map(Utf8.toUtf8).toList();
final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
Utf8.toUtf8(output.amount)).toList();
final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
for (int i = 0; i < size; i++) {
addressesPointerPointer[ i ] = addressesPointers[ i ];
amountsPointerPointer[ i ] = amountsPointers[ i ];
addressesPointerPointer[i] = addressesPointers[i];
amountsPointerPointer[i] = amountsPointers[i];
}
final paymentIdPointer = Utf8.toUtf8(paymentId);
@ -190,18 +191,14 @@ PendingTransactionDescription _createTransactionSync(Map args) {
}
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
final addresses = args['addresses'] as List<String>;
final outputs = args['outputs'] as List<MoneroOutput>;
final paymentId = args['paymentId'] as String;
final amounts = args['amounts'] as List<String>;
final size = args['size'] as int;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;
return createTransactionMultDestSync(
addresses: addresses,
outputs: outputs,
paymentId: paymentId,
amounts: amounts,
size: size,
priorityRaw: priorityRaw,
accountIndex: accountIndex);
}
@ -221,17 +218,13 @@ Future<PendingTransactionDescription> createTransaction(
});
Future<PendingTransactionDescription> createTransactionMultDest(
{List<String> addresses,
{List<MoneroOutput> outputs,
String paymentId,
List<String> amounts,
int size,
int priorityRaw,
int accountIndex = 0}) =>
compute(_createTransactionMultDestSync, {
'addresses': addresses,
'outputs': outputs,
'paymentId': paymentId,
'amounts': amounts,
'size': size,
'priorityRaw': priorityRaw,
'accountIndex': accountIndex
});

View file

@ -1,9 +1,9 @@
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
import 'package:cake_wallet/view_model/send/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
class BitcoinTransactionCredentials {
BitcoinTransactionCredentials(this.sendItemList, this.priority);
BitcoinTransactionCredentials(this.outputs, this.priority);
final List<SendItem> sendItemList;
final List<Output> outputs;
BitcoinTransactionPriority priority;
}

View file

@ -158,7 +158,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
const minAmount = 546;
final transactionCredentials = credentials as BitcoinTransactionCredentials;
final inputs = <BitcoinUnspent>[];
final sendItemList = transactionCredentials.sendItemList;
final outputs = transactionCredentials.outputs;
final hasMultiDestination = outputs.length > 1;
var allInputsAmount = 0;
if (unspentCoins.isEmpty) {
@ -177,61 +178,54 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
}
final allAmountFee = feeAmountForPriority(
transactionCredentials.priority, inputs.length, sendItemList.length);
transactionCredentials.priority, inputs.length, outputs.length);
final allAmount = allInputsAmount - allAmountFee;
var credentialsAmount = 0;
var amount = 0;
var fee = 0;
if (sendItemList.length > 1) {
final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
if (hasMultiDestination) {
final sendAllItems = outputs.where((item) => item.sendAll).toList();
if (sendAllItems?.isNotEmpty ?? false) {
throw BitcoinTransactionWrongBalanceException(currency);
}
final nullAmountItems = sendItemList.where((item) =>
stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.')) <= 0)
.toList();
final nullAmountItems = outputs.where((item) =>
item.formattedCryptoAmount <= 0).toList();
if (nullAmountItems?.isNotEmpty ?? false) {
throw BitcoinTransactionWrongBalanceException(currency);
}
credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
previousValue + stringDoubleToBitcoinAmount(
element.cryptoAmount.replaceAll(',', '.')));
credentialsAmount = outputs.fold(0, (acc, value) =>
acc + value.formattedCryptoAmount);
if (credentialsAmount > allAmount) {
if (allAmount - credentialsAmount < minAmount) {
throw BitcoinTransactionWrongBalanceException(currency);
}
amount = allAmount - credentialsAmount < minAmount
? allAmount
: credentialsAmount;
amount = credentialsAmount;
fee = amount == allAmount
? allAmountFee
: calculateEstimatedFee(transactionCredentials.priority, amount,
outputsCount: sendItemList.length + 1);
fee = calculateEstimatedFee(transactionCredentials.priority, amount,
outputsCount: outputs.length + 1);
} else {
final sendItem = sendItemList.first;
final output = outputs.first;
credentialsAmount = !sendItem.sendAll
? stringDoubleToBitcoinAmount(
sendItem.cryptoAmount.replaceAll(',', '.'))
credentialsAmount = !output.sendAll
? output.formattedCryptoAmount
: 0;
if (credentialsAmount > allAmount) {
throw BitcoinTransactionWrongBalanceException(currency);
}
amount = sendItem.sendAll || allAmount - credentialsAmount < minAmount
amount = output.sendAll || allAmount - credentialsAmount < minAmount
? allAmount
: credentialsAmount;
fee = sendItem.sendAll || amount == allAmount
fee = output.sendAll || amount == allAmount
? allAmountFee
: calculateEstimatedFee(transactionCredentials.priority, amount);
}
@ -289,18 +283,18 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
}
});
sendItemList.forEach((item) {
final _amount = item.sendAll
? amount
: stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.'));
outputs.forEach((item) {
final outputAmount = hasMultiDestination
? item.formattedCryptoAmount
: amount;
txb.addOutput(
addressToOutputScript(item.address, networkType),
_amount);
outputAmount);
});
final estimatedSize =
estimatedTransactionSize(inputs.length, sendItemList.length + 1);
estimatedTransactionSize(inputs.length, outputs.length + 1);
final feeAmount = feeRate(transactionCredentials.priority) * estimatedSize;
final changeValue = totalInputAmount - amount - feeAmount;

View file

@ -1,11 +1,11 @@
import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
import 'package:cake_wallet/entities/monero_transaction_priority.dart';
import 'package:cake_wallet/view_model/send/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
class MoneroTransactionCreationCredentials
extends TransactionCreationCredentials {
MoneroTransactionCreationCredentials({this.sendItemList, this.priority});
MoneroTransactionCreationCredentials({this.outputs, this.priority});
final List<SendItem> sendItemList;
final List<Output> outputs;
final MoneroTransactionPriority priority;
}

View file

@ -13,6 +13,7 @@ import 'package:cw_monero/transaction_history.dart'
import 'package:cw_monero/wallet.dart';
import 'package:cw_monero/wallet.dart' as monero_wallet;
import 'package:cw_monero/transaction_history.dart' as transaction_history;
import 'package:cw_monero/monero_output.dart';
import 'package:cake_wallet/monero/monero_transaction_creation_credentials.dart';
import 'package:cake_wallet/monero/pending_monero_transaction.dart';
import 'package:cake_wallet/monero/monero_wallet_keys.dart';
@ -150,8 +151,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
final _credentials = credentials as MoneroTransactionCreationCredentials;
final sendItemList = _credentials.sendItemList;
final listSize = sendItemList.length;
final outputs = _credentials.outputs;
final hasMultiDestination = outputs.length > 1;
final unlockedBalance =
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
@ -161,16 +162,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
throw MoneroTransactionCreationException('The wallet is not synced.');
}
if (listSize > 1) {
final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
if (hasMultiDestination) {
final sendAllItems = outputs.where((item) => item.sendAll).toList();
if (sendAllItems?.isNotEmpty ?? false) {
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
}
final nullAmountItems = sendItemList.where((item) =>
moneroParseAmount(amount: item.cryptoAmount.replaceAll(',', '.')) <= 0)
.toList();
final nullAmountItems = outputs.where((item) =>
item.formattedCryptoAmount <= 0).toList();
if (nullAmountItems?.isNotEmpty ?? false) {
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
@ -178,42 +178,41 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
var credentialsAmount = 0;
credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
previousValue + moneroParseAmount(
amount: element.cryptoAmount.replaceAll(',', '.')));
credentialsAmount = outputs.fold(0, (acc, value) =>
acc + value.formattedCryptoAmount);
if (unlockedBalance < credentialsAmount) {
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
}
final addresses = sendItemList.map((e) => e.address).toList();
final amounts = sendItemList.map((e) =>
e.cryptoAmount.replaceAll(',', '.')).toList();
final moneroOutputs = outputs.map((output) =>
MoneroOutput(
address: output.address,
amount: output.cryptoAmount.replaceAll(',', '.')))
.toList();
pendingTransactionDescription =
await transaction_history.createTransactionMultDest(
addresses: addresses,
outputs: moneroOutputs,
paymentId: '',
amounts: amounts,
size: listSize,
priorityRaw: _credentials.priority.serialize(),
accountIndex: walletAddresses.account.id);
} else {
final item = sendItemList.first;
final address = item.address;
final amount = item.sendAll
final output = outputs.first;
final address = output.address;
final amount = output.sendAll
? null
: item.cryptoAmount.replaceAll(',', '.');
final formattedAmount = item.sendAll
: output.cryptoAmount.replaceAll(',', '.');
final formattedAmount = output.sendAll
? null
: moneroParseAmount(amount: amount);
: output.formattedCryptoAmount;
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
(formattedAmount == null && unlockedBalance <= 0)) {
final formattedBalance = moneroAmountToString(amount: unlockedBalance);
throw MoneroTransactionCreationException(
'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${item.cryptoAmount}.');
'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
}
pendingTransactionDescription =

View file

@ -385,8 +385,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
.pendingTransactionFiatAmount +
' ' +
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
sendItemList: widget.exchangeTradeViewModel.sendViewModel
.sendItemList);
outputs: widget.exchangeTradeViewModel.sendViewModel
.outputs);
});
});
}

View file

@ -3,7 +3,7 @@ import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_a
import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/template_tile.dart';
import 'package:cake_wallet/view_model/send/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -55,16 +55,16 @@ class SendPage extends BasePage {
onPressed: () {
var pageToJump = controller.page.round() - 1;
pageToJump = pageToJump > 0 ? pageToJump : 0;
final item = _defineCurrentSendItem();
sendViewModel.removeSendItem(item);
final output = _defineCurrentOutput();
sendViewModel.removeOutput(output);
controller.jumpToPage(pageToJump);
})
: TrailButton(
caption: S.of(context).clear,
onPressed: () {
final item = _defineCurrentSendItem();
final output = _defineCurrentOutput();
_formKey.currentState.reset();
item.reset();
output.reset();
});
});
@ -85,13 +85,13 @@ class SendPage extends BasePage {
return PageView.builder(
scrollDirection: Axis.horizontal,
controller: controller,
itemCount: sendViewModel.sendItemList.length,
itemCount: sendViewModel.outputs.length,
itemBuilder: (context, index) {
final item = sendViewModel.sendItemList[index];
final output = sendViewModel.outputs[index];
return SendCard(
key: item.key,
item: item,
key: output.key,
output: output,
sendViewModel: sendViewModel,
);
}
@ -104,7 +104,7 @@ class SendPage extends BasePage {
child: Container(
height: 10,
child: Observer(builder: (_) {
final count = sendViewModel.sendItemList.length;
final count = sendViewModel.outputs.length;
return count > 1
? SmoothPageIndicator(
@ -211,11 +211,11 @@ class SendPage extends BasePage {
amount: template.amount,
from: template.cryptoCurrency,
onTap: () async {
final item = _defineCurrentSendItem();
item.address =
final output = _defineCurrentOutput();
output.address =
template.address;
item.setCryptoAmount(template.amount);
final parsedAddress = await item
output.setCryptoAmount(template.amount);
final parsedAddress = await output
.applyOpenaliasOrUnstoppableDomains();
showAddressAlert(context, parsedAddress);
},
@ -263,7 +263,7 @@ class SendPage extends BasePage {
padding: EdgeInsets.only(bottom: 12),
child: PrimaryButton(
onPressed: () {
sendViewModel.addSendItem();
sendViewModel.addOutput();
},
text: S.of(context).add_receiver,
color: Colors.green,
@ -274,16 +274,16 @@ class SendPage extends BasePage {
return LoadingPrimaryButton(
onPressed: () async {
if (!_formKey.currentState.validate()) {
if (sendViewModel.sendItemList.length > 1) {
if (sendViewModel.outputs.length > 1) {
showErrorValidationAlert(context);
}
return;
}
final notValidItems = sendViewModel.sendItemList
final notValidItems = sendViewModel.outputs
.where((item) =>
item.address.isEmpty || item.cryptoAmount.isEmpty)
item.address.isEmpty || item.cryptoAmount.isEmpty)
.toList();
if (notValidItems?.isNotEmpty ?? false) {
@ -343,7 +343,7 @@ class SendPage extends BasePage {
feeValue: sendViewModel.pendingTransaction.feeFormatted,
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmount
+ ' ' + sendViewModel.fiat.title,
sendItemList: sendViewModel.sendItemList,
outputs: sendViewModel.outputs,
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
actionRightButton: () {
@ -381,7 +381,7 @@ class SendPage extends BasePage {
if (state is TransactionCommitted) {
WidgetsBinding.instance.addPostFrameCallback((_) {
sendViewModel.clearSendItemList();
sendViewModel.clearOutputs();
});
}
});
@ -389,9 +389,9 @@ class SendPage extends BasePage {
_effectsInstalled = true;
}
SendItem _defineCurrentSendItem() {
Output _defineCurrentOutput() {
final itemCount = controller.page.round();
return sendViewModel.sendItemList[itemCount];
return sendViewModel.outputs[itemCount];
}
void showErrorValidationAlert(BuildContext context) async {

View file

@ -14,7 +14,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
class SendTemplatePage extends BasePage {
SendTemplatePage({@required this.sendTemplateViewModel}) {
sendTemplateViewModel.sendItem.reset();
sendTemplateViewModel.output.reset();
}
final SendTemplateViewModel sendTemplateViewModel;
@ -258,21 +258,21 @@ class SendTemplatePage extends BasePage {
return;
}
final item = sendTemplateViewModel.sendItem;
final output = sendTemplateViewModel.output;
reaction((_) => item.fiatAmount, (String amount) {
reaction((_) => output.fiatAmount, (String amount) {
if (amount != _fiatAmountController.text) {
_fiatAmountController.text = amount;
}
});
reaction((_) => item.cryptoAmount, (String amount) {
reaction((_) => output.cryptoAmount, (String amount) {
if (amount != _cryptoAmountController.text) {
_cryptoAmountController.text = amount;
}
});
reaction((_) => item.address, (String address) {
reaction((_) => output.address, (String address) {
if (address != _addressController.text) {
_addressController.text = address;
}
@ -281,24 +281,24 @@ class SendTemplatePage extends BasePage {
_cryptoAmountController.addListener(() {
final amount = _cryptoAmountController.text;
if (amount != item.cryptoAmount) {
item.setCryptoAmount(amount);
if (amount != output.cryptoAmount) {
output.setCryptoAmount(amount);
}
});
_fiatAmountController.addListener(() {
final amount = _fiatAmountController.text;
if (amount != item.fiatAmount) {
item.setFiatAmount(amount);
if (amount != output.fiatAmount) {
output.setFiatAmount(amount);
}
});
_addressController.addListener(() {
final address = _addressController.text;
if (item.address != address) {
item.address = address;
if (output.address != address) {
output.address = address;
}
});

View file

@ -1,5 +1,5 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/view_model/send/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -13,14 +13,14 @@ class ConfirmSendingAlert extends BaseAlertDialog {
@required this.fee,
@required this.feeValue,
@required this.feeFiatAmount,
@required this.sendItemList,
@required this.outputs,
@required this.leftButtonText,
@required this.rightButtonText,
@required this.actionLeftButton,
@required this.actionRightButton,
this.alertBarrierDismissible = true
}) {
itemCount = sendItemList.length;
itemCount = outputs.length;
recipientTitle = itemCount > 1
? S.current.transaction_details_recipient_address
: S.current.recipient_address;
@ -33,7 +33,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
final String fee;
final String feeValue;
final String feeFiatAmount;
final List<SendItem> sendItemList;
final List<Output> outputs;
final String leftButtonText;
final String rightButtonText;
final VoidCallback actionLeftButton;
@ -179,10 +179,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
physics: NeverScrollableScrollPhysics(),
itemCount: itemCount,
itemBuilder: (context, index) {
final item = sendItemList[index];
final item = outputs[index];
final _address = item.address;
final _amount =
item.cryptoAmount.replaceAll(',', '.');
item.cryptoAmount.replaceAll(',', '.');
return Column(
children: [
@ -225,7 +225,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
: Padding(
padding: EdgeInsets.only(top: 8),
child: Text(
sendItemList.first.address,
outputs.first.address,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,

View file

@ -4,7 +4,7 @@ import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_alert.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/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@ -19,21 +19,21 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
class SendCard extends StatefulWidget {
SendCard({Key key, @required this.item, @required this.sendViewModel}) : super(key: key);
SendCard({Key key, @required this.output, @required this.sendViewModel}) : super(key: key);
final SendItem item;
final Output output;
final SendViewModel sendViewModel;
@override
SendCardState createState() => SendCardState(
item: item,
output: output,
sendViewModel: sendViewModel
);
}
class SendCardState extends State<SendCard>
with AutomaticKeepAliveClientMixin<SendCard> {
SendCardState({@required this.item, @required this.sendViewModel})
SendCardState({@required this.output, @required this.sendViewModel})
: addressController = TextEditingController(),
cryptoAmountController = TextEditingController(),
fiatAmountController = TextEditingController(),
@ -45,7 +45,7 @@ class SendCardState extends State<SendCard>
static const prefixIconWidth = 34.0;
static const prefixIconHeight = 34.0;
final SendItem item;
final Output output;
final SendViewModel sendViewModel;
final TextEditingController addressController;
@ -143,7 +143,7 @@ class SendCardState extends State<SendCard>
.decorationColor),
onPushPasteButton: (context) async {
final parsedAddress =
await item.applyOpenaliasOrUnstoppableDomains();
await output.applyOpenaliasOrUnstoppableDomains();
showAddressAlert(context, parsedAddress);
},
validator: sendViewModel.addressValidator,
@ -189,7 +189,7 @@ class SendCardState extends State<SendCard>
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
validator: item.sendAll
validator: output.sendAll
? sendViewModel.allAmountValidator
: sendViewModel
.amountValidator),
@ -201,7 +201,7 @@ class SendCardState extends State<SendCard>
height: prefixIconHeight,
child: InkWell(
onTap: () async =>
item.setSendAll(),
output.setSendAll(),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
@ -349,7 +349,7 @@ class SendCardState extends State<SendCard>
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
item
output
.estimatedFee
.toString() +
' ' +
@ -366,7 +366,7 @@ class SendCardState extends State<SendCard>
padding:
EdgeInsets.only(top: 5),
child: Text(
item
output
.estimatedFeeFiatAmount
+ ' ' +
sendViewModel
@ -435,10 +435,10 @@ class SendCardState extends State<SendCard>
}
void _setEffects(BuildContext context) {
addressController.text = item.address;
cryptoAmountController.text = item.cryptoAmount;
fiatAmountController.text = item.fiatAmount;
noteController.text = item.note;
addressController.text = output.address;
cryptoAmountController.text = output.cryptoAmount;
fiatAmountController.text = output.fiatAmount;
noteController.text = output.note;
if (_effectsInstalled) {
return;
@ -447,48 +447,48 @@ class SendCardState extends State<SendCard>
cryptoAmountController.addListener(() {
final amount = cryptoAmountController.text;
if (item.sendAll && amount != S.current.all) {
item.sendAll = false;
if (output.sendAll && amount != S.current.all) {
output.sendAll = false;
}
if (amount != item.cryptoAmount) {
item.setCryptoAmount(amount);
if (amount != output.cryptoAmount) {
output.setCryptoAmount(amount);
}
});
fiatAmountController.addListener(() {
final amount = fiatAmountController.text;
if (amount != item.fiatAmount) {
item.sendAll = false;
item.setFiatAmount(amount);
if (amount != output.fiatAmount) {
output.sendAll = false;
output.setFiatAmount(amount);
}
});
noteController.addListener(() {
final note = noteController.text ?? '';
if (note != item.note) {
item.note = note;
if (note != output.note) {
output.note = note;
}
});
reaction((_) => item.sendAll, (bool all) {
reaction((_) => output.sendAll, (bool all) {
if (all) {
cryptoAmountController.text = S.current.all;
fiatAmountController.text = null;
}
});
reaction((_) => item.fiatAmount, (String amount) {
reaction((_) => output.fiatAmount, (String amount) {
if (amount != fiatAmountController.text) {
fiatAmountController.text = amount;
}
});
reaction((_) => item.cryptoAmount, (String amount) {
if (item.sendAll && amount != S.current.all) {
item.sendAll = false;
reaction((_) => output.cryptoAmount, (String amount) {
if (output.sendAll && amount != S.current.all) {
output.sendAll = false;
}
if (amount != cryptoAmountController.text) {
@ -496,7 +496,7 @@ class SendCardState extends State<SendCard>
}
});
reaction((_) => item.address, (String address) {
reaction((_) => output.address, (String address) {
if (address != addressController.text) {
addressController.text = address;
}
@ -505,12 +505,12 @@ class SendCardState extends State<SendCard>
addressController.addListener(() {
final address = addressController.text;
if (item.address != address) {
item.address = address;
if (output.address != address) {
output.address = address;
}
});
reaction((_) => item.note, (String note) {
reaction((_) => output.note, (String note) {
if (note != noteController.text) {
noteController.text = note;
}
@ -518,7 +518,7 @@ class SendCardState extends State<SendCard>
addressFocusNode.addListener(() async {
if (!addressFocusNode.hasFocus && addressController.text.isNotEmpty) {
final parsedAddress = await item.applyOpenaliasOrUnstoppableDomains();
final parsedAddress = await output.applyOpenaliasOrUnstoppableDomains();
showAddressAlert(context, parsedAddress);
}
});

View file

@ -79,11 +79,11 @@ abstract class ExchangeTradeViewModelBase with Store {
return;
}
sendViewModel.clearSendItemList();
final item = sendViewModel.sendItemList.first;
sendViewModel.clearOutputs();
final output = sendViewModel.outputs.first;
item.address = trade.inputAddress;
item.setCryptoAmount(trade.amount);
output.address = trade.inputAddress;
output.setCryptoAmount(trade.amount);
await sendViewModel.createTransaction();
}

View file

@ -15,14 +15,14 @@ import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/generated/i18n.dart';
part 'send_item.g.dart';
part 'output.g.dart';
const String cryptoNumberPattern = '0.0';
class SendItem = SendItemBase with _$SendItem;
class Output = OutputBase with _$Output;
abstract class SendItemBase with Store {
SendItemBase(this._wallet, this._settingsStore, this._fiatConversationStore)
abstract class OutputBase with Store {
OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore)
:_cryptoNumberFormat = NumberFormat(cryptoNumberPattern) {
reset();
_setCryptoNumMaximumFractionDigits();
@ -47,8 +47,8 @@ abstract class SendItemBase with Store {
bool sendAll;
@computed
double get estimatedFee {
int amount;
int get formattedCryptoAmount {
int amount = 0;
try {
if (cryptoAmount?.isNotEmpty ?? false) {
@ -72,9 +72,18 @@ abstract class SendItemBase with Store {
amount = _amount;
}
}
} catch(e) {
amount = 0;
}
return amount;
}
@computed
double get estimatedFee {
try {
final fee = _wallet.calculateEstimatedFee(
_settingsStore.priority[_wallet.type], amount);
_settingsStore.priority[_wallet.type], formattedCryptoAmount);
if (_wallet is ElectrumWallet) {
return bitcoinAmountToDouble(amount: fee);

View file

@ -1,4 +1,4 @@
import 'package:cake_wallet/view_model/send/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/template.dart';
import 'package:cake_wallet/store/templates/send_template_store.dart';
@ -21,10 +21,10 @@ abstract class SendTemplateViewModelBase with Store {
SendTemplateViewModelBase(this._wallet, this._settingsStore,
this._sendTemplateStore, this._fiatConversationStore) {
sendItem = SendItem(_wallet, _settingsStore, _fiatConversationStore);
output = Output(_wallet, _settingsStore, _fiatConversationStore);
}
SendItem sendItem;
Output output;
Validator get amountValidator => AmountValidator(type: _wallet.type);

View file

@ -2,7 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/entities/transaction_priority.dart';
import 'package:cake_wallet/view_model/send/send_item.dart';
import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
import 'package:hive/hive.dart';
@ -42,33 +42,33 @@ abstract class SendViewModelBase with Store {
_settingsStore.priority[_wallet.type] = priorities.first;
}
sendItemList = ObservableList<SendItem>()
..add(SendItem(_wallet, _settingsStore, _fiatConversationStore));
outputs = ObservableList<Output>()
..add(Output(_wallet, _settingsStore, _fiatConversationStore));
}
@observable
ExecutionState state;
ObservableList<SendItem> sendItemList;
ObservableList<Output> outputs;
@action
void addSendItem() {
sendItemList.add(SendItem(_wallet, _settingsStore, _fiatConversationStore));
void addOutput() {
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore));
}
@action
void removeSendItem(SendItem item) {
sendItemList.remove(item);
void removeOutput(Output output) {
outputs.remove(output);
}
@action
void clearSendItemList() {
sendItemList.clear();
addSendItem();
void clearOutputs() {
outputs.clear();
addOutput();
}
@computed
bool get isBatchSending => sendItemList.length > 1;
bool get isBatchSending => outputs.length > 1;
@computed
String get pendingTransactionFiatAmount {
@ -150,14 +150,14 @@ abstract class SendViewModelBase with Store {
@action
Future<void> commitTransaction() async {
String address = sendItemList.fold('', (previousValue, item) {
return previousValue + item.address + '\n';
String address = outputs.fold('', (acc, value) {
return acc + value.address + '\n';
});
address = address.trim();
String note = sendItemList.fold('', (previousValue, item) {
return previousValue + item.note + '\n';
String note = outputs.fold('', (acc, value) {
return acc + value.note + '\n';
});
note = note.trim();
@ -192,17 +192,17 @@ abstract class SendViewModelBase with Store {
final priority = _settingsStore.priority[_wallet.type];
return BitcoinTransactionCredentials(
sendItemList, priority as BitcoinTransactionPriority);
outputs, priority as BitcoinTransactionPriority);
case WalletType.litecoin:
final priority = _settingsStore.priority[_wallet.type];
return BitcoinTransactionCredentials(
sendItemList, priority as BitcoinTransactionPriority);
outputs, priority as BitcoinTransactionPriority);
case WalletType.monero:
final priority = _settingsStore.priority[_wallet.type];
return MoneroTransactionCreationCredentials(
sendItemList: sendItemList,
outputs: outputs,
priority: priority as MoneroTransactionPriority);
default:
return null;