mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-05-06 05:52:13 +00:00
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:
parent
1dd3f69b1c
commit
1e3ec8da1c
15 changed files with 191 additions and 188 deletions
cw_monero/lib
lib
bitcoin
monero
src/screens
exchange_trade
send
view_model
8
cw_monero/lib/monero_output.dart
Normal file
8
cw_monero/lib/monero_output.dart
Normal 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;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:cw_monero/convert_utf8_to_string.dart';
|
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:cw_monero/structs/ut8_box.dart';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
@ -107,21 +108,21 @@ PendingTransactionDescription createTransactionSync(
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingTransactionDescription createTransactionMultDestSync(
|
PendingTransactionDescription createTransactionMultDestSync(
|
||||||
{List<String> addresses,
|
{List<MoneroOutput> outputs,
|
||||||
String paymentId,
|
String paymentId,
|
||||||
List<String> amounts,
|
|
||||||
int size,
|
|
||||||
int priorityRaw,
|
int priorityRaw,
|
||||||
int accountIndex = 0}) {
|
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 Pointer<Pointer<Utf8>> addressesPointerPointer = allocate(count: size);
|
||||||
|
final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
|
||||||
final List<Pointer<Utf8>> amountsPointers = amounts.map(Utf8.toUtf8).toList();
|
Utf8.toUtf8(output.amount)).toList();
|
||||||
final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
|
final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
addressesPointerPointer[ i ] = addressesPointers[ i ];
|
addressesPointerPointer[i] = addressesPointers[i];
|
||||||
amountsPointerPointer[ i ] = amountsPointers[ i ];
|
amountsPointerPointer[i] = amountsPointers[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
final paymentIdPointer = Utf8.toUtf8(paymentId);
|
final paymentIdPointer = Utf8.toUtf8(paymentId);
|
||||||
|
@ -190,18 +191,14 @@ PendingTransactionDescription _createTransactionSync(Map args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingTransactionDescription _createTransactionMultDestSync(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 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 priorityRaw = args['priorityRaw'] as int;
|
||||||
final accountIndex = args['accountIndex'] as int;
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
return createTransactionMultDestSync(
|
return createTransactionMultDestSync(
|
||||||
addresses: addresses,
|
outputs: outputs,
|
||||||
paymentId: paymentId,
|
paymentId: paymentId,
|
||||||
amounts: amounts,
|
|
||||||
size: size,
|
|
||||||
priorityRaw: priorityRaw,
|
priorityRaw: priorityRaw,
|
||||||
accountIndex: accountIndex);
|
accountIndex: accountIndex);
|
||||||
}
|
}
|
||||||
|
@ -221,17 +218,13 @@ Future<PendingTransactionDescription> createTransaction(
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<PendingTransactionDescription> createTransactionMultDest(
|
Future<PendingTransactionDescription> createTransactionMultDest(
|
||||||
{List<String> addresses,
|
{List<MoneroOutput> outputs,
|
||||||
String paymentId,
|
String paymentId,
|
||||||
List<String> amounts,
|
|
||||||
int size,
|
|
||||||
int priorityRaw,
|
int priorityRaw,
|
||||||
int accountIndex = 0}) =>
|
int accountIndex = 0}) =>
|
||||||
compute(_createTransactionMultDestSync, {
|
compute(_createTransactionMultDestSync, {
|
||||||
'addresses': addresses,
|
'outputs': outputs,
|
||||||
'paymentId': paymentId,
|
'paymentId': paymentId,
|
||||||
'amounts': amounts,
|
|
||||||
'size': size,
|
|
||||||
'priorityRaw': priorityRaw,
|
'priorityRaw': priorityRaw,
|
||||||
'accountIndex': accountIndex
|
'accountIndex': accountIndex
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
|
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 {
|
class BitcoinTransactionCredentials {
|
||||||
BitcoinTransactionCredentials(this.sendItemList, this.priority);
|
BitcoinTransactionCredentials(this.outputs, this.priority);
|
||||||
|
|
||||||
final List<SendItem> sendItemList;
|
final List<Output> outputs;
|
||||||
BitcoinTransactionPriority priority;
|
BitcoinTransactionPriority priority;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
const minAmount = 546;
|
const minAmount = 546;
|
||||||
final transactionCredentials = credentials as BitcoinTransactionCredentials;
|
final transactionCredentials = credentials as BitcoinTransactionCredentials;
|
||||||
final inputs = <BitcoinUnspent>[];
|
final inputs = <BitcoinUnspent>[];
|
||||||
final sendItemList = transactionCredentials.sendItemList;
|
final outputs = transactionCredentials.outputs;
|
||||||
|
final hasMultiDestination = outputs.length > 1;
|
||||||
var allInputsAmount = 0;
|
var allInputsAmount = 0;
|
||||||
|
|
||||||
if (unspentCoins.isEmpty) {
|
if (unspentCoins.isEmpty) {
|
||||||
|
@ -177,61 +178,54 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
|
|
||||||
final allAmountFee = feeAmountForPriority(
|
final allAmountFee = feeAmountForPriority(
|
||||||
transactionCredentials.priority, inputs.length, sendItemList.length);
|
transactionCredentials.priority, inputs.length, outputs.length);
|
||||||
final allAmount = allInputsAmount - allAmountFee;
|
final allAmount = allInputsAmount - allAmountFee;
|
||||||
|
|
||||||
var credentialsAmount = 0;
|
var credentialsAmount = 0;
|
||||||
var amount = 0;
|
var amount = 0;
|
||||||
var fee = 0;
|
var fee = 0;
|
||||||
|
|
||||||
if (sendItemList.length > 1) {
|
if (hasMultiDestination) {
|
||||||
final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
|
final sendAllItems = outputs.where((item) => item.sendAll).toList();
|
||||||
|
|
||||||
if (sendAllItems?.isNotEmpty ?? false) {
|
if (sendAllItems?.isNotEmpty ?? false) {
|
||||||
throw BitcoinTransactionWrongBalanceException(currency);
|
throw BitcoinTransactionWrongBalanceException(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
final nullAmountItems = sendItemList.where((item) =>
|
final nullAmountItems = outputs.where((item) =>
|
||||||
stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.')) <= 0)
|
item.formattedCryptoAmount <= 0).toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (nullAmountItems?.isNotEmpty ?? false) {
|
if (nullAmountItems?.isNotEmpty ?? false) {
|
||||||
throw BitcoinTransactionWrongBalanceException(currency);
|
throw BitcoinTransactionWrongBalanceException(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
|
credentialsAmount = outputs.fold(0, (acc, value) =>
|
||||||
previousValue + stringDoubleToBitcoinAmount(
|
acc + value.formattedCryptoAmount);
|
||||||
element.cryptoAmount.replaceAll(',', '.')));
|
|
||||||
|
|
||||||
if (credentialsAmount > allAmount) {
|
if (allAmount - credentialsAmount < minAmount) {
|
||||||
throw BitcoinTransactionWrongBalanceException(currency);
|
throw BitcoinTransactionWrongBalanceException(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = allAmount - credentialsAmount < minAmount
|
amount = credentialsAmount;
|
||||||
? allAmount
|
|
||||||
: credentialsAmount;
|
|
||||||
|
|
||||||
fee = amount == allAmount
|
fee = calculateEstimatedFee(transactionCredentials.priority, amount,
|
||||||
? allAmountFee
|
outputsCount: outputs.length + 1);
|
||||||
: calculateEstimatedFee(transactionCredentials.priority, amount,
|
|
||||||
outputsCount: sendItemList.length + 1);
|
|
||||||
} else {
|
} else {
|
||||||
final sendItem = sendItemList.first;
|
final output = outputs.first;
|
||||||
|
|
||||||
credentialsAmount = !sendItem.sendAll
|
credentialsAmount = !output.sendAll
|
||||||
? stringDoubleToBitcoinAmount(
|
? output.formattedCryptoAmount
|
||||||
sendItem.cryptoAmount.replaceAll(',', '.'))
|
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
if (credentialsAmount > allAmount) {
|
if (credentialsAmount > allAmount) {
|
||||||
throw BitcoinTransactionWrongBalanceException(currency);
|
throw BitcoinTransactionWrongBalanceException(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = sendItem.sendAll || allAmount - credentialsAmount < minAmount
|
amount = output.sendAll || allAmount - credentialsAmount < minAmount
|
||||||
? allAmount
|
? allAmount
|
||||||
: credentialsAmount;
|
: credentialsAmount;
|
||||||
|
|
||||||
fee = sendItem.sendAll || amount == allAmount
|
fee = output.sendAll || amount == allAmount
|
||||||
? allAmountFee
|
? allAmountFee
|
||||||
: calculateEstimatedFee(transactionCredentials.priority, amount);
|
: calculateEstimatedFee(transactionCredentials.priority, amount);
|
||||||
}
|
}
|
||||||
|
@ -289,18 +283,18 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sendItemList.forEach((item) {
|
outputs.forEach((item) {
|
||||||
final _amount = item.sendAll
|
final outputAmount = hasMultiDestination
|
||||||
? amount
|
? item.formattedCryptoAmount
|
||||||
: stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.'));
|
: amount;
|
||||||
|
|
||||||
txb.addOutput(
|
txb.addOutput(
|
||||||
addressToOutputScript(item.address, networkType),
|
addressToOutputScript(item.address, networkType),
|
||||||
_amount);
|
outputAmount);
|
||||||
});
|
});
|
||||||
|
|
||||||
final estimatedSize =
|
final estimatedSize =
|
||||||
estimatedTransactionSize(inputs.length, sendItemList.length + 1);
|
estimatedTransactionSize(inputs.length, outputs.length + 1);
|
||||||
final feeAmount = feeRate(transactionCredentials.priority) * estimatedSize;
|
final feeAmount = feeRate(transactionCredentials.priority) * estimatedSize;
|
||||||
final changeValue = totalInputAmount - amount - feeAmount;
|
final changeValue = totalInputAmount - amount - feeAmount;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
|
import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
|
||||||
import 'package:cake_wallet/entities/monero_transaction_priority.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
|
class MoneroTransactionCreationCredentials
|
||||||
extends TransactionCreationCredentials {
|
extends TransactionCreationCredentials {
|
||||||
MoneroTransactionCreationCredentials({this.sendItemList, this.priority});
|
MoneroTransactionCreationCredentials({this.outputs, this.priority});
|
||||||
|
|
||||||
final List<SendItem> sendItemList;
|
final List<Output> outputs;
|
||||||
final MoneroTransactionPriority priority;
|
final MoneroTransactionPriority priority;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import 'package:cw_monero/transaction_history.dart'
|
||||||
import 'package:cw_monero/wallet.dart';
|
import 'package:cw_monero/wallet.dart';
|
||||||
import 'package:cw_monero/wallet.dart' as monero_wallet;
|
import 'package:cw_monero/wallet.dart' as monero_wallet;
|
||||||
import 'package:cw_monero/transaction_history.dart' as transaction_history;
|
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/monero_transaction_creation_credentials.dart';
|
||||||
import 'package:cake_wallet/monero/pending_monero_transaction.dart';
|
import 'package:cake_wallet/monero/pending_monero_transaction.dart';
|
||||||
import 'package:cake_wallet/monero/monero_wallet_keys.dart';
|
import 'package:cake_wallet/monero/monero_wallet_keys.dart';
|
||||||
|
@ -150,8 +151,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||||
final sendItemList = _credentials.sendItemList;
|
final outputs = _credentials.outputs;
|
||||||
final listSize = sendItemList.length;
|
final hasMultiDestination = outputs.length > 1;
|
||||||
final unlockedBalance =
|
final unlockedBalance =
|
||||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
|
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
|
||||||
|
|
||||||
|
@ -161,16 +162,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
throw MoneroTransactionCreationException('The wallet is not synced.');
|
throw MoneroTransactionCreationException('The wallet is not synced.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (listSize > 1) {
|
if (hasMultiDestination) {
|
||||||
final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
|
final sendAllItems = outputs.where((item) => item.sendAll).toList();
|
||||||
|
|
||||||
if (sendAllItems?.isNotEmpty ?? false) {
|
if (sendAllItems?.isNotEmpty ?? false) {
|
||||||
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final nullAmountItems = sendItemList.where((item) =>
|
final nullAmountItems = outputs.where((item) =>
|
||||||
moneroParseAmount(amount: item.cryptoAmount.replaceAll(',', '.')) <= 0)
|
item.formattedCryptoAmount <= 0).toList();
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (nullAmountItems?.isNotEmpty ?? false) {
|
if (nullAmountItems?.isNotEmpty ?? false) {
|
||||||
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
||||||
|
@ -178,42 +178,41 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
var credentialsAmount = 0;
|
var credentialsAmount = 0;
|
||||||
|
|
||||||
credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
|
credentialsAmount = outputs.fold(0, (acc, value) =>
|
||||||
previousValue + moneroParseAmount(
|
acc + value.formattedCryptoAmount);
|
||||||
amount: element.cryptoAmount.replaceAll(',', '.')));
|
|
||||||
|
|
||||||
if (unlockedBalance < credentialsAmount) {
|
if (unlockedBalance < credentialsAmount) {
|
||||||
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
|
||||||
}
|
}
|
||||||
|
|
||||||
final addresses = sendItemList.map((e) => e.address).toList();
|
final moneroOutputs = outputs.map((output) =>
|
||||||
final amounts = sendItemList.map((e) =>
|
MoneroOutput(
|
||||||
e.cryptoAmount.replaceAll(',', '.')).toList();
|
address: output.address,
|
||||||
|
amount: output.cryptoAmount.replaceAll(',', '.')))
|
||||||
|
.toList();
|
||||||
|
|
||||||
pendingTransactionDescription =
|
pendingTransactionDescription =
|
||||||
await transaction_history.createTransactionMultDest(
|
await transaction_history.createTransactionMultDest(
|
||||||
addresses: addresses,
|
outputs: moneroOutputs,
|
||||||
paymentId: '',
|
paymentId: '',
|
||||||
amounts: amounts,
|
|
||||||
size: listSize,
|
|
||||||
priorityRaw: _credentials.priority.serialize(),
|
priorityRaw: _credentials.priority.serialize(),
|
||||||
accountIndex: walletAddresses.account.id);
|
accountIndex: walletAddresses.account.id);
|
||||||
} else {
|
} else {
|
||||||
final item = sendItemList.first;
|
final output = outputs.first;
|
||||||
final address = item.address;
|
final address = output.address;
|
||||||
final amount = item.sendAll
|
final amount = output.sendAll
|
||||||
? null
|
? null
|
||||||
: item.cryptoAmount.replaceAll(',', '.');
|
: output.cryptoAmount.replaceAll(',', '.');
|
||||||
final formattedAmount = item.sendAll
|
final formattedAmount = output.sendAll
|
||||||
? null
|
? null
|
||||||
: moneroParseAmount(amount: amount);
|
: output.formattedCryptoAmount;
|
||||||
|
|
||||||
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
|
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
|
||||||
(formattedAmount == null && unlockedBalance <= 0)) {
|
(formattedAmount == null && unlockedBalance <= 0)) {
|
||||||
final formattedBalance = moneroAmountToString(amount: unlockedBalance);
|
final formattedBalance = moneroAmountToString(amount: unlockedBalance);
|
||||||
|
|
||||||
throw MoneroTransactionCreationException(
|
throw MoneroTransactionCreationException(
|
||||||
'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${item.cryptoAmount}.');
|
'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingTransactionDescription =
|
pendingTransactionDescription =
|
||||||
|
|
|
@ -385,8 +385,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
.pendingTransactionFiatAmount +
|
.pendingTransactionFiatAmount +
|
||||||
' ' +
|
' ' +
|
||||||
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
|
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
|
||||||
sendItemList: widget.exchangeTradeViewModel.sendViewModel
|
outputs: widget.exchangeTradeViewModel.sendViewModel
|
||||||
.sendItemList);
|
.outputs);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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/screens/send/widgets/send_card.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.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/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/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
@ -55,16 +55,16 @@ class SendPage extends BasePage {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
var pageToJump = controller.page.round() - 1;
|
var pageToJump = controller.page.round() - 1;
|
||||||
pageToJump = pageToJump > 0 ? pageToJump : 0;
|
pageToJump = pageToJump > 0 ? pageToJump : 0;
|
||||||
final item = _defineCurrentSendItem();
|
final output = _defineCurrentOutput();
|
||||||
sendViewModel.removeSendItem(item);
|
sendViewModel.removeOutput(output);
|
||||||
controller.jumpToPage(pageToJump);
|
controller.jumpToPage(pageToJump);
|
||||||
})
|
})
|
||||||
: TrailButton(
|
: TrailButton(
|
||||||
caption: S.of(context).clear,
|
caption: S.of(context).clear,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final item = _defineCurrentSendItem();
|
final output = _defineCurrentOutput();
|
||||||
_formKey.currentState.reset();
|
_formKey.currentState.reset();
|
||||||
item.reset();
|
output.reset();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -85,13 +85,13 @@ class SendPage extends BasePage {
|
||||||
return PageView.builder(
|
return PageView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
itemCount: sendViewModel.sendItemList.length,
|
itemCount: sendViewModel.outputs.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = sendViewModel.sendItemList[index];
|
final output = sendViewModel.outputs[index];
|
||||||
|
|
||||||
return SendCard(
|
return SendCard(
|
||||||
key: item.key,
|
key: output.key,
|
||||||
item: item,
|
output: output,
|
||||||
sendViewModel: sendViewModel,
|
sendViewModel: sendViewModel,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ class SendPage extends BasePage {
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 10,
|
height: 10,
|
||||||
child: Observer(builder: (_) {
|
child: Observer(builder: (_) {
|
||||||
final count = sendViewModel.sendItemList.length;
|
final count = sendViewModel.outputs.length;
|
||||||
|
|
||||||
return count > 1
|
return count > 1
|
||||||
? SmoothPageIndicator(
|
? SmoothPageIndicator(
|
||||||
|
@ -211,11 +211,11 @@ class SendPage extends BasePage {
|
||||||
amount: template.amount,
|
amount: template.amount,
|
||||||
from: template.cryptoCurrency,
|
from: template.cryptoCurrency,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final item = _defineCurrentSendItem();
|
final output = _defineCurrentOutput();
|
||||||
item.address =
|
output.address =
|
||||||
template.address;
|
template.address;
|
||||||
item.setCryptoAmount(template.amount);
|
output.setCryptoAmount(template.amount);
|
||||||
final parsedAddress = await item
|
final parsedAddress = await output
|
||||||
.applyOpenaliasOrUnstoppableDomains();
|
.applyOpenaliasOrUnstoppableDomains();
|
||||||
showAddressAlert(context, parsedAddress);
|
showAddressAlert(context, parsedAddress);
|
||||||
},
|
},
|
||||||
|
@ -263,7 +263,7 @@ class SendPage extends BasePage {
|
||||||
padding: EdgeInsets.only(bottom: 12),
|
padding: EdgeInsets.only(bottom: 12),
|
||||||
child: PrimaryButton(
|
child: PrimaryButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
sendViewModel.addSendItem();
|
sendViewModel.addOutput();
|
||||||
},
|
},
|
||||||
text: S.of(context).add_receiver,
|
text: S.of(context).add_receiver,
|
||||||
color: Colors.green,
|
color: Colors.green,
|
||||||
|
@ -274,16 +274,16 @@ class SendPage extends BasePage {
|
||||||
return LoadingPrimaryButton(
|
return LoadingPrimaryButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (!_formKey.currentState.validate()) {
|
if (!_formKey.currentState.validate()) {
|
||||||
if (sendViewModel.sendItemList.length > 1) {
|
if (sendViewModel.outputs.length > 1) {
|
||||||
showErrorValidationAlert(context);
|
showErrorValidationAlert(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final notValidItems = sendViewModel.sendItemList
|
final notValidItems = sendViewModel.outputs
|
||||||
.where((item) =>
|
.where((item) =>
|
||||||
item.address.isEmpty || item.cryptoAmount.isEmpty)
|
item.address.isEmpty || item.cryptoAmount.isEmpty)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (notValidItems?.isNotEmpty ?? false) {
|
if (notValidItems?.isNotEmpty ?? false) {
|
||||||
|
@ -343,7 +343,7 @@ class SendPage extends BasePage {
|
||||||
feeValue: sendViewModel.pendingTransaction.feeFormatted,
|
feeValue: sendViewModel.pendingTransaction.feeFormatted,
|
||||||
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmount
|
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmount
|
||||||
+ ' ' + sendViewModel.fiat.title,
|
+ ' ' + sendViewModel.fiat.title,
|
||||||
sendItemList: sendViewModel.sendItemList,
|
outputs: sendViewModel.outputs,
|
||||||
rightButtonText: S.of(context).ok,
|
rightButtonText: S.of(context).ok,
|
||||||
leftButtonText: S.of(context).cancel,
|
leftButtonText: S.of(context).cancel,
|
||||||
actionRightButton: () {
|
actionRightButton: () {
|
||||||
|
@ -381,7 +381,7 @@ class SendPage extends BasePage {
|
||||||
|
|
||||||
if (state is TransactionCommitted) {
|
if (state is TransactionCommitted) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
sendViewModel.clearSendItemList();
|
sendViewModel.clearOutputs();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -389,9 +389,9 @@ class SendPage extends BasePage {
|
||||||
_effectsInstalled = true;
|
_effectsInstalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SendItem _defineCurrentSendItem() {
|
Output _defineCurrentOutput() {
|
||||||
final itemCount = controller.page.round();
|
final itemCount = controller.page.round();
|
||||||
return sendViewModel.sendItemList[itemCount];
|
return sendViewModel.outputs[itemCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
void showErrorValidationAlert(BuildContext context) async {
|
void showErrorValidationAlert(BuildContext context) async {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
|
||||||
class SendTemplatePage extends BasePage {
|
class SendTemplatePage extends BasePage {
|
||||||
SendTemplatePage({@required this.sendTemplateViewModel}) {
|
SendTemplatePage({@required this.sendTemplateViewModel}) {
|
||||||
sendTemplateViewModel.sendItem.reset();
|
sendTemplateViewModel.output.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
final SendTemplateViewModel sendTemplateViewModel;
|
final SendTemplateViewModel sendTemplateViewModel;
|
||||||
|
@ -258,21 +258,21 @@ class SendTemplatePage extends BasePage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final item = sendTemplateViewModel.sendItem;
|
final output = sendTemplateViewModel.output;
|
||||||
|
|
||||||
reaction((_) => item.fiatAmount, (String amount) {
|
reaction((_) => output.fiatAmount, (String amount) {
|
||||||
if (amount != _fiatAmountController.text) {
|
if (amount != _fiatAmountController.text) {
|
||||||
_fiatAmountController.text = amount;
|
_fiatAmountController.text = amount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => item.cryptoAmount, (String amount) {
|
reaction((_) => output.cryptoAmount, (String amount) {
|
||||||
if (amount != _cryptoAmountController.text) {
|
if (amount != _cryptoAmountController.text) {
|
||||||
_cryptoAmountController.text = amount;
|
_cryptoAmountController.text = amount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => item.address, (String address) {
|
reaction((_) => output.address, (String address) {
|
||||||
if (address != _addressController.text) {
|
if (address != _addressController.text) {
|
||||||
_addressController.text = address;
|
_addressController.text = address;
|
||||||
}
|
}
|
||||||
|
@ -281,24 +281,24 @@ class SendTemplatePage extends BasePage {
|
||||||
_cryptoAmountController.addListener(() {
|
_cryptoAmountController.addListener(() {
|
||||||
final amount = _cryptoAmountController.text;
|
final amount = _cryptoAmountController.text;
|
||||||
|
|
||||||
if (amount != item.cryptoAmount) {
|
if (amount != output.cryptoAmount) {
|
||||||
item.setCryptoAmount(amount);
|
output.setCryptoAmount(amount);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_fiatAmountController.addListener(() {
|
_fiatAmountController.addListener(() {
|
||||||
final amount = _fiatAmountController.text;
|
final amount = _fiatAmountController.text;
|
||||||
|
|
||||||
if (amount != item.fiatAmount) {
|
if (amount != output.fiatAmount) {
|
||||||
item.setFiatAmount(amount);
|
output.setFiatAmount(amount);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_addressController.addListener(() {
|
_addressController.addListener(() {
|
||||||
final address = _addressController.text;
|
final address = _addressController.text;
|
||||||
|
|
||||||
if (item.address != address) {
|
if (output.address != address) {
|
||||||
item.address = address;
|
output.address = address;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:cake_wallet/palette.dart';
|
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:flutter/material.dart';
|
||||||
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
|
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
@ -13,14 +13,14 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
||||||
@required this.fee,
|
@required this.fee,
|
||||||
@required this.feeValue,
|
@required this.feeValue,
|
||||||
@required this.feeFiatAmount,
|
@required this.feeFiatAmount,
|
||||||
@required this.sendItemList,
|
@required this.outputs,
|
||||||
@required this.leftButtonText,
|
@required this.leftButtonText,
|
||||||
@required this.rightButtonText,
|
@required this.rightButtonText,
|
||||||
@required this.actionLeftButton,
|
@required this.actionLeftButton,
|
||||||
@required this.actionRightButton,
|
@required this.actionRightButton,
|
||||||
this.alertBarrierDismissible = true
|
this.alertBarrierDismissible = true
|
||||||
}) {
|
}) {
|
||||||
itemCount = sendItemList.length;
|
itemCount = outputs.length;
|
||||||
recipientTitle = itemCount > 1
|
recipientTitle = itemCount > 1
|
||||||
? S.current.transaction_details_recipient_address
|
? S.current.transaction_details_recipient_address
|
||||||
: S.current.recipient_address;
|
: S.current.recipient_address;
|
||||||
|
@ -33,7 +33,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
||||||
final String fee;
|
final String fee;
|
||||||
final String feeValue;
|
final String feeValue;
|
||||||
final String feeFiatAmount;
|
final String feeFiatAmount;
|
||||||
final List<SendItem> sendItemList;
|
final List<Output> outputs;
|
||||||
final String leftButtonText;
|
final String leftButtonText;
|
||||||
final String rightButtonText;
|
final String rightButtonText;
|
||||||
final VoidCallback actionLeftButton;
|
final VoidCallback actionLeftButton;
|
||||||
|
@ -179,10 +179,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
||||||
physics: NeverScrollableScrollPhysics(),
|
physics: NeverScrollableScrollPhysics(),
|
||||||
itemCount: itemCount,
|
itemCount: itemCount,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final item = sendItemList[index];
|
final item = outputs[index];
|
||||||
final _address = item.address;
|
final _address = item.address;
|
||||||
final _amount =
|
final _amount =
|
||||||
item.cryptoAmount.replaceAll(',', '.');
|
item.cryptoAmount.replaceAll(',', '.');
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -225,7 +225,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: EdgeInsets.only(top: 8),
|
padding: EdgeInsets.only(top: 8),
|
||||||
child: Text(
|
child: Text(
|
||||||
sendItemList.first.address,
|
outputs.first.address,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
|
@ -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/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/keyboard_done_button.dart';
|
||||||
import 'package:cake_wallet/src/widgets/picker.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:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.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';
|
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||||
|
|
||||||
class SendCard extends StatefulWidget {
|
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;
|
final SendViewModel sendViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SendCardState createState() => SendCardState(
|
SendCardState createState() => SendCardState(
|
||||||
item: item,
|
output: output,
|
||||||
sendViewModel: sendViewModel
|
sendViewModel: sendViewModel
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class SendCardState extends State<SendCard>
|
class SendCardState extends State<SendCard>
|
||||||
with AutomaticKeepAliveClientMixin<SendCard> {
|
with AutomaticKeepAliveClientMixin<SendCard> {
|
||||||
SendCardState({@required this.item, @required this.sendViewModel})
|
SendCardState({@required this.output, @required this.sendViewModel})
|
||||||
: addressController = TextEditingController(),
|
: addressController = TextEditingController(),
|
||||||
cryptoAmountController = TextEditingController(),
|
cryptoAmountController = TextEditingController(),
|
||||||
fiatAmountController = TextEditingController(),
|
fiatAmountController = TextEditingController(),
|
||||||
|
@ -45,7 +45,7 @@ class SendCardState extends State<SendCard>
|
||||||
static const prefixIconWidth = 34.0;
|
static const prefixIconWidth = 34.0;
|
||||||
static const prefixIconHeight = 34.0;
|
static const prefixIconHeight = 34.0;
|
||||||
|
|
||||||
final SendItem item;
|
final Output output;
|
||||||
final SendViewModel sendViewModel;
|
final SendViewModel sendViewModel;
|
||||||
|
|
||||||
final TextEditingController addressController;
|
final TextEditingController addressController;
|
||||||
|
@ -143,7 +143,7 @@ class SendCardState extends State<SendCard>
|
||||||
.decorationColor),
|
.decorationColor),
|
||||||
onPushPasteButton: (context) async {
|
onPushPasteButton: (context) async {
|
||||||
final parsedAddress =
|
final parsedAddress =
|
||||||
await item.applyOpenaliasOrUnstoppableDomains();
|
await output.applyOpenaliasOrUnstoppableDomains();
|
||||||
showAddressAlert(context, parsedAddress);
|
showAddressAlert(context, parsedAddress);
|
||||||
},
|
},
|
||||||
validator: sendViewModel.addressValidator,
|
validator: sendViewModel.addressValidator,
|
||||||
|
@ -189,7 +189,7 @@ class SendCardState extends State<SendCard>
|
||||||
.decorationColor,
|
.decorationColor,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
fontSize: 14),
|
fontSize: 14),
|
||||||
validator: item.sendAll
|
validator: output.sendAll
|
||||||
? sendViewModel.allAmountValidator
|
? sendViewModel.allAmountValidator
|
||||||
: sendViewModel
|
: sendViewModel
|
||||||
.amountValidator),
|
.amountValidator),
|
||||||
|
@ -201,7 +201,7 @@ class SendCardState extends State<SendCard>
|
||||||
height: prefixIconHeight,
|
height: prefixIconHeight,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async =>
|
onTap: () async =>
|
||||||
item.setSendAll(),
|
output.setSendAll(),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
|
@ -349,7 +349,7 @@ class SendCardState extends State<SendCard>
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
item
|
output
|
||||||
.estimatedFee
|
.estimatedFee
|
||||||
.toString() +
|
.toString() +
|
||||||
' ' +
|
' ' +
|
||||||
|
@ -366,7 +366,7 @@ class SendCardState extends State<SendCard>
|
||||||
padding:
|
padding:
|
||||||
EdgeInsets.only(top: 5),
|
EdgeInsets.only(top: 5),
|
||||||
child: Text(
|
child: Text(
|
||||||
item
|
output
|
||||||
.estimatedFeeFiatAmount
|
.estimatedFeeFiatAmount
|
||||||
+ ' ' +
|
+ ' ' +
|
||||||
sendViewModel
|
sendViewModel
|
||||||
|
@ -435,10 +435,10 @@ class SendCardState extends State<SendCard>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setEffects(BuildContext context) {
|
void _setEffects(BuildContext context) {
|
||||||
addressController.text = item.address;
|
addressController.text = output.address;
|
||||||
cryptoAmountController.text = item.cryptoAmount;
|
cryptoAmountController.text = output.cryptoAmount;
|
||||||
fiatAmountController.text = item.fiatAmount;
|
fiatAmountController.text = output.fiatAmount;
|
||||||
noteController.text = item.note;
|
noteController.text = output.note;
|
||||||
|
|
||||||
if (_effectsInstalled) {
|
if (_effectsInstalled) {
|
||||||
return;
|
return;
|
||||||
|
@ -447,48 +447,48 @@ class SendCardState extends State<SendCard>
|
||||||
cryptoAmountController.addListener(() {
|
cryptoAmountController.addListener(() {
|
||||||
final amount = cryptoAmountController.text;
|
final amount = cryptoAmountController.text;
|
||||||
|
|
||||||
if (item.sendAll && amount != S.current.all) {
|
if (output.sendAll && amount != S.current.all) {
|
||||||
item.sendAll = false;
|
output.sendAll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount != item.cryptoAmount) {
|
if (amount != output.cryptoAmount) {
|
||||||
item.setCryptoAmount(amount);
|
output.setCryptoAmount(amount);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
fiatAmountController.addListener(() {
|
fiatAmountController.addListener(() {
|
||||||
final amount = fiatAmountController.text;
|
final amount = fiatAmountController.text;
|
||||||
|
|
||||||
if (amount != item.fiatAmount) {
|
if (amount != output.fiatAmount) {
|
||||||
item.sendAll = false;
|
output.sendAll = false;
|
||||||
item.setFiatAmount(amount);
|
output.setFiatAmount(amount);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
noteController.addListener(() {
|
noteController.addListener(() {
|
||||||
final note = noteController.text ?? '';
|
final note = noteController.text ?? '';
|
||||||
|
|
||||||
if (note != item.note) {
|
if (note != output.note) {
|
||||||
item.note = note;
|
output.note = note;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => item.sendAll, (bool all) {
|
reaction((_) => output.sendAll, (bool all) {
|
||||||
if (all) {
|
if (all) {
|
||||||
cryptoAmountController.text = S.current.all;
|
cryptoAmountController.text = S.current.all;
|
||||||
fiatAmountController.text = null;
|
fiatAmountController.text = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => item.fiatAmount, (String amount) {
|
reaction((_) => output.fiatAmount, (String amount) {
|
||||||
if (amount != fiatAmountController.text) {
|
if (amount != fiatAmountController.text) {
|
||||||
fiatAmountController.text = amount;
|
fiatAmountController.text = amount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => item.cryptoAmount, (String amount) {
|
reaction((_) => output.cryptoAmount, (String amount) {
|
||||||
if (item.sendAll && amount != S.current.all) {
|
if (output.sendAll && amount != S.current.all) {
|
||||||
item.sendAll = false;
|
output.sendAll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (amount != cryptoAmountController.text) {
|
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) {
|
if (address != addressController.text) {
|
||||||
addressController.text = address;
|
addressController.text = address;
|
||||||
}
|
}
|
||||||
|
@ -505,12 +505,12 @@ class SendCardState extends State<SendCard>
|
||||||
addressController.addListener(() {
|
addressController.addListener(() {
|
||||||
final address = addressController.text;
|
final address = addressController.text;
|
||||||
|
|
||||||
if (item.address != address) {
|
if (output.address != address) {
|
||||||
item.address = address;
|
output.address = address;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => item.note, (String note) {
|
reaction((_) => output.note, (String note) {
|
||||||
if (note != noteController.text) {
|
if (note != noteController.text) {
|
||||||
noteController.text = note;
|
noteController.text = note;
|
||||||
}
|
}
|
||||||
|
@ -518,7 +518,7 @@ class SendCardState extends State<SendCard>
|
||||||
|
|
||||||
addressFocusNode.addListener(() async {
|
addressFocusNode.addListener(() async {
|
||||||
if (!addressFocusNode.hasFocus && addressController.text.isNotEmpty) {
|
if (!addressFocusNode.hasFocus && addressController.text.isNotEmpty) {
|
||||||
final parsedAddress = await item.applyOpenaliasOrUnstoppableDomains();
|
final parsedAddress = await output.applyOpenaliasOrUnstoppableDomains();
|
||||||
showAddressAlert(context, parsedAddress);
|
showAddressAlert(context, parsedAddress);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,11 +79,11 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendViewModel.clearSendItemList();
|
sendViewModel.clearOutputs();
|
||||||
final item = sendViewModel.sendItemList.first;
|
final output = sendViewModel.outputs.first;
|
||||||
|
|
||||||
item.address = trade.inputAddress;
|
output.address = trade.inputAddress;
|
||||||
item.setCryptoAmount(trade.amount);
|
output.setCryptoAmount(trade.amount);
|
||||||
await sendViewModel.createTransaction();
|
await sendViewModel.createTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
part 'send_item.g.dart';
|
part 'output.g.dart';
|
||||||
|
|
||||||
const String cryptoNumberPattern = '0.0';
|
const String cryptoNumberPattern = '0.0';
|
||||||
|
|
||||||
class SendItem = SendItemBase with _$SendItem;
|
class Output = OutputBase with _$Output;
|
||||||
|
|
||||||
abstract class SendItemBase with Store {
|
abstract class OutputBase with Store {
|
||||||
SendItemBase(this._wallet, this._settingsStore, this._fiatConversationStore)
|
OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore)
|
||||||
:_cryptoNumberFormat = NumberFormat(cryptoNumberPattern) {
|
:_cryptoNumberFormat = NumberFormat(cryptoNumberPattern) {
|
||||||
reset();
|
reset();
|
||||||
_setCryptoNumMaximumFractionDigits();
|
_setCryptoNumMaximumFractionDigits();
|
||||||
|
@ -47,8 +47,8 @@ abstract class SendItemBase with Store {
|
||||||
bool sendAll;
|
bool sendAll;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
double get estimatedFee {
|
int get formattedCryptoAmount {
|
||||||
int amount;
|
int amount = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (cryptoAmount?.isNotEmpty ?? false) {
|
if (cryptoAmount?.isNotEmpty ?? false) {
|
||||||
|
@ -72,9 +72,18 @@ abstract class SendItemBase with Store {
|
||||||
amount = _amount;
|
amount = _amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch(e) {
|
||||||
|
amount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed
|
||||||
|
double get estimatedFee {
|
||||||
|
try {
|
||||||
final fee = _wallet.calculateEstimatedFee(
|
final fee = _wallet.calculateEstimatedFee(
|
||||||
_settingsStore.priority[_wallet.type], amount);
|
_settingsStore.priority[_wallet.type], formattedCryptoAmount);
|
||||||
|
|
||||||
if (_wallet is ElectrumWallet) {
|
if (_wallet is ElectrumWallet) {
|
||||||
return bitcoinAmountToDouble(amount: fee);
|
return bitcoinAmountToDouble(amount: fee);
|
|
@ -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:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/entities/template.dart';
|
import 'package:cake_wallet/entities/template.dart';
|
||||||
import 'package:cake_wallet/store/templates/send_template_store.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,
|
SendTemplateViewModelBase(this._wallet, this._settingsStore,
|
||||||
this._sendTemplateStore, this._fiatConversationStore) {
|
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);
|
Validator get amountValidator => AmountValidator(type: _wallet.type);
|
||||||
|
|
||||||
|
|
|
@ -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/bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||||
import 'package:cake_wallet/entities/transaction_priority.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/send/send_template_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
@ -42,33 +42,33 @@ abstract class SendViewModelBase with Store {
|
||||||
_settingsStore.priority[_wallet.type] = priorities.first;
|
_settingsStore.priority[_wallet.type] = priorities.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendItemList = ObservableList<SendItem>()
|
outputs = ObservableList<Output>()
|
||||||
..add(SendItem(_wallet, _settingsStore, _fiatConversationStore));
|
..add(Output(_wallet, _settingsStore, _fiatConversationStore));
|
||||||
}
|
}
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
ExecutionState state;
|
ExecutionState state;
|
||||||
|
|
||||||
ObservableList<SendItem> sendItemList;
|
ObservableList<Output> outputs;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void addSendItem() {
|
void addOutput() {
|
||||||
sendItemList.add(SendItem(_wallet, _settingsStore, _fiatConversationStore));
|
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore));
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void removeSendItem(SendItem item) {
|
void removeOutput(Output output) {
|
||||||
sendItemList.remove(item);
|
outputs.remove(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void clearSendItemList() {
|
void clearOutputs() {
|
||||||
sendItemList.clear();
|
outputs.clear();
|
||||||
addSendItem();
|
addOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isBatchSending => sendItemList.length > 1;
|
bool get isBatchSending => outputs.length > 1;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
String get pendingTransactionFiatAmount {
|
String get pendingTransactionFiatAmount {
|
||||||
|
@ -150,14 +150,14 @@ abstract class SendViewModelBase with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> commitTransaction() async {
|
Future<void> commitTransaction() async {
|
||||||
String address = sendItemList.fold('', (previousValue, item) {
|
String address = outputs.fold('', (acc, value) {
|
||||||
return previousValue + item.address + '\n';
|
return acc + value.address + '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
address = address.trim();
|
address = address.trim();
|
||||||
|
|
||||||
String note = sendItemList.fold('', (previousValue, item) {
|
String note = outputs.fold('', (acc, value) {
|
||||||
return previousValue + item.note + '\n';
|
return acc + value.note + '\n';
|
||||||
});
|
});
|
||||||
|
|
||||||
note = note.trim();
|
note = note.trim();
|
||||||
|
@ -192,17 +192,17 @@ abstract class SendViewModelBase with Store {
|
||||||
final priority = _settingsStore.priority[_wallet.type];
|
final priority = _settingsStore.priority[_wallet.type];
|
||||||
|
|
||||||
return BitcoinTransactionCredentials(
|
return BitcoinTransactionCredentials(
|
||||||
sendItemList, priority as BitcoinTransactionPriority);
|
outputs, priority as BitcoinTransactionPriority);
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
final priority = _settingsStore.priority[_wallet.type];
|
final priority = _settingsStore.priority[_wallet.type];
|
||||||
|
|
||||||
return BitcoinTransactionCredentials(
|
return BitcoinTransactionCredentials(
|
||||||
sendItemList, priority as BitcoinTransactionPriority);
|
outputs, priority as BitcoinTransactionPriority);
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
final priority = _settingsStore.priority[_wallet.type];
|
final priority = _settingsStore.priority[_wallet.type];
|
||||||
|
|
||||||
return MoneroTransactionCreationCredentials(
|
return MoneroTransactionCreationCredentials(
|
||||||
sendItemList: sendItemList,
|
outputs: outputs,
|
||||||
priority: priority as MoneroTransactionPriority);
|
priority: priority as MoneroTransactionPriority);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Reference in a new issue