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
OleksandrSobol committed
Aug 10, 2021 at 17:52 UTC
1e3ec8da1c40f1fdb087b55e8bb915c952fd5850
15 files changed
+191
-188
cw_monero/lib/monero_output.dart
new
+8
@@ -0,0 +1,8 @@
1
+import 'package:flutter/foundation.dart';
2
+
3
+class MoneroOutput {
4
+ MoneroOutput({@required this.address, @required this.amount});
5
+
6
+ final String address;
7
+ final String amount;
8
+}
\ No newline at end of file
cw_monero/lib/transaction_history.dart
+13
-20
@@ -1,5 +1,6 @@
1
import 'dart:ffi';
2
import 'package:cw_monero/convert_utf8_to_string.dart';
3
+import 'package:cw_monero/monero_output.dart';
4
import 'package:cw_monero/structs/ut8_box.dart';
5
import 'package:ffi/ffi.dart';
6
import 'package:flutter/foundation.dart';
@@ -107,21 +108,21 @@ PendingTransactionDescription createTransactionSync(
108
}
109
110
PendingTransactionDescription createTransactionMultDestSync(
110
- {List<String> addresses,
111
+ {List<MoneroOutput> outputs,
112
String paymentId,
112
- List<String> amounts,
113
- int size,
113
int priorityRaw,
114
int accountIndex = 0}) {
116
- final List<Pointer<Utf8>> addressesPointers = addresses.map(Utf8.toUtf8).toList();
115
+ final int size = outputs.length;
116
+ final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
117
+ Utf8.toUtf8(output.address)).toList();
118
final Pointer<Pointer<Utf8>> addressesPointerPointer = allocate(count: size);
118
-
119
- final List<Pointer<Utf8>> amountsPointers = amounts.map(Utf8.toUtf8).toList();
119
+ final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
120
+ Utf8.toUtf8(output.amount)).toList();
121
final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
122
123
for (int i = 0; i < size; i++) {
123
- addressesPointerPointer[ i ] = addressesPointers[ i ];
124
- amountsPointerPointer[ i ] = amountsPointers[ i ];
124
+ addressesPointerPointer[i] = addressesPointers[i];
125
+ amountsPointerPointer[i] = amountsPointers[i];
126
}
127
128
final paymentIdPointer = Utf8.toUtf8(paymentId);
@@ -190,18 +191,14 @@ PendingTransactionDescription _createTransactionSync(Map args) {
191
}
192
193
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
193
- final addresses = args['addresses'] as List<String>;
194
+ final outputs = args['outputs'] as List<MoneroOutput>;
195
final paymentId = args['paymentId'] as String;
195
- final amounts = args['amounts'] as List<String>;
196
- final size = args['size'] as int;
196
final priorityRaw = args['priorityRaw'] as int;
197
final accountIndex = args['accountIndex'] as int;
198
199
return createTransactionMultDestSync(
201
- addresses: addresses,
200
+ outputs: outputs,
201
paymentId: paymentId,
203
- amounts: amounts,
204
- size: size,
202
priorityRaw: priorityRaw,
203
accountIndex: accountIndex);
204
}
@@ -221,17 +218,13 @@ Future<PendingTransactionDescription> createTransaction(
218
});
219
220
Future<PendingTransactionDescription> createTransactionMultDest(
224
- {List<String> addresses,
221
+ {List<MoneroOutput> outputs,
222
String paymentId,
226
- List<String> amounts,
227
- int size,
223
int priorityRaw,
224
int accountIndex = 0}) =>
225
compute(_createTransactionMultDestSync, {
231
- 'addresses': addresses,
226
+ 'outputs': outputs,
227
'paymentId': paymentId,
233
- 'amounts': amounts,
234
- 'size': size,
228
'priorityRaw': priorityRaw,
229
'accountIndex': accountIndex
230
});
lib/bitcoin/bitcoin_transaction_credentials.dart
+3
-3
@@ -1,9 +1,9 @@
1
import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2
-import 'package:cake_wallet/view_model/send/send_item.dart';
2
+import 'package:cake_wallet/view_model/send/output.dart';
3
4
class BitcoinTransactionCredentials {
5
- BitcoinTransactionCredentials(this.sendItemList, this.priority);
5
+ BitcoinTransactionCredentials(this.outputs, this.priority);
6
7
- final List<SendItem> sendItemList;
7
+ final List<Output> outputs;
8
BitcoinTransactionPriority priority;
9
}
lib/bitcoin/electrum_wallet.dart
+24
-30
@@ -158,7 +158,8 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
158
const minAmount = 546;
159
final transactionCredentials = credentials as BitcoinTransactionCredentials;
160
final inputs = <BitcoinUnspent>[];
161
- final sendItemList = transactionCredentials.sendItemList;
161
+ final outputs = transactionCredentials.outputs;
162
+ final hasMultiDestination = outputs.length > 1;
163
var allInputsAmount = 0;
164
165
if (unspentCoins.isEmpty) {
@@ -177,61 +178,54 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
178
}
179
180
final allAmountFee = feeAmountForPriority(
180
- transactionCredentials.priority, inputs.length, sendItemList.length);
181
+ transactionCredentials.priority, inputs.length, outputs.length);
182
final allAmount = allInputsAmount - allAmountFee;
183
184
var credentialsAmount = 0;
185
var amount = 0;
186
var fee = 0;
187
187
- if (sendItemList.length > 1) {
188
- final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
188
+ if (hasMultiDestination) {
189
+ final sendAllItems = outputs.where((item) => item.sendAll).toList();
190
191
if (sendAllItems?.isNotEmpty ?? false) {
192
throw BitcoinTransactionWrongBalanceException(currency);
193
}
194
194
- final nullAmountItems = sendItemList.where((item) =>
195
- stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.')) <= 0)
196
- .toList();
195
+ final nullAmountItems = outputs.where((item) =>
196
+ item.formattedCryptoAmount <= 0).toList();
197
198
if (nullAmountItems?.isNotEmpty ?? false) {
199
throw BitcoinTransactionWrongBalanceException(currency);
200
}
201
202
- credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
203
- previousValue + stringDoubleToBitcoinAmount(
204
- element.cryptoAmount.replaceAll(',', '.')));
202
+ credentialsAmount = outputs.fold(0, (acc, value) =>
203
+ acc + value.formattedCryptoAmount);
204
206
- if (credentialsAmount > allAmount) {
205
+ if (allAmount - credentialsAmount < minAmount) {
206
throw BitcoinTransactionWrongBalanceException(currency);
207
}
208
210
- amount = allAmount - credentialsAmount < minAmount
211
- ? allAmount
212
- : credentialsAmount;
209
+ amount = credentialsAmount;
210
214
- fee = amount == allAmount
215
- ? allAmountFee
216
- : calculateEstimatedFee(transactionCredentials.priority, amount,
217
- outputsCount: sendItemList.length + 1);
211
+ fee = calculateEstimatedFee(transactionCredentials.priority, amount,
212
+ outputsCount: outputs.length + 1);
213
} else {
219
- final sendItem = sendItemList.first;
214
+ final output = outputs.first;
215
221
- credentialsAmount = !sendItem.sendAll
222
- ? stringDoubleToBitcoinAmount(
223
- sendItem.cryptoAmount.replaceAll(',', '.'))
216
+ credentialsAmount = !output.sendAll
217
+ ? output.formattedCryptoAmount
218
: 0;
219
220
if (credentialsAmount > allAmount) {
221
throw BitcoinTransactionWrongBalanceException(currency);
222
}
223
230
- amount = sendItem.sendAll || allAmount - credentialsAmount < minAmount
224
+ amount = output.sendAll || allAmount - credentialsAmount < minAmount
225
? allAmount
226
: credentialsAmount;
227
234
- fee = sendItem.sendAll || amount == allAmount
228
+ fee = output.sendAll || amount == allAmount
229
? allAmountFee
230
: calculateEstimatedFee(transactionCredentials.priority, amount);
231
}
@@ -289,18 +283,18 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
283
}
284
});
285
292
- sendItemList.forEach((item) {
293
- final _amount = item.sendAll
294
- ? amount
295
- : stringDoubleToBitcoinAmount(item.cryptoAmount.replaceAll(',', '.'));
286
+ outputs.forEach((item) {
287
+ final outputAmount = hasMultiDestination
288
+ ? item.formattedCryptoAmount
289
+ : amount;
290
291
txb.addOutput(
292
addressToOutputScript(item.address, networkType),
299
- _amount);
293
+ outputAmount);
294
});
295
296
final estimatedSize =
303
- estimatedTransactionSize(inputs.length, sendItemList.length + 1);
297
+ estimatedTransactionSize(inputs.length, outputs.length + 1);
298
final feeAmount = feeRate(transactionCredentials.priority) * estimatedSize;
299
final changeValue = totalInputAmount - amount - feeAmount;
300
lib/monero/monero_transaction_creation_credentials.dart
+3
-3
@@ -1,11 +1,11 @@
1
import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
2
import 'package:cake_wallet/entities/monero_transaction_priority.dart';
3
-import 'package:cake_wallet/view_model/send/send_item.dart';
3
+import 'package:cake_wallet/view_model/send/output.dart';
4
5
class MoneroTransactionCreationCredentials
6
extends TransactionCreationCredentials {
7
- MoneroTransactionCreationCredentials({this.sendItemList, this.priority});
7
+ MoneroTransactionCreationCredentials({this.outputs, this.priority});
8
9
- final List<SendItem> sendItemList;
9
+ final List<Output> outputs;
10
final MoneroTransactionPriority priority;
11
}
lib/monero/monero_wallet.dart
+22
-23
@@ -13,6 +13,7 @@ import 'package:cw_monero/transaction_history.dart'
13
import 'package:cw_monero/wallet.dart';
14
import 'package:cw_monero/wallet.dart' as monero_wallet;
15
import 'package:cw_monero/transaction_history.dart' as transaction_history;
16
+import 'package:cw_monero/monero_output.dart';
17
import 'package:cake_wallet/monero/monero_transaction_creation_credentials.dart';
18
import 'package:cake_wallet/monero/pending_monero_transaction.dart';
19
import 'package:cake_wallet/monero/monero_wallet_keys.dart';
@@ -150,8 +151,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
151
@override
152
Future<PendingTransaction> createTransaction(Object credentials) async {
153
final _credentials = credentials as MoneroTransactionCreationCredentials;
153
- final sendItemList = _credentials.sendItemList;
154
- final listSize = sendItemList.length;
154
+ final outputs = _credentials.outputs;
155
+ final hasMultiDestination = outputs.length > 1;
156
final unlockedBalance =
157
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
158
@@ -161,16 +162,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
162
throw MoneroTransactionCreationException('The wallet is not synced.');
163
}
164
164
- if (listSize > 1) {
165
- final sendAllItems = sendItemList.where((item) => item.sendAll).toList();
165
+ if (hasMultiDestination) {
166
+ final sendAllItems = outputs.where((item) => item.sendAll).toList();
167
168
if (sendAllItems?.isNotEmpty ?? false) {
169
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
170
}
171
171
- final nullAmountItems = sendItemList.where((item) =>
172
- moneroParseAmount(amount: item.cryptoAmount.replaceAll(',', '.')) <= 0)
173
- .toList();
172
+ final nullAmountItems = outputs.where((item) =>
173
+ item.formattedCryptoAmount <= 0).toList();
174
175
if (nullAmountItems?.isNotEmpty ?? false) {
176
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
@@ -178,42 +178,41 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
178
179
var credentialsAmount = 0;
180
181
- credentialsAmount = sendItemList.fold(0, (previousValue, element) =>
182
- previousValue + moneroParseAmount(
183
- amount: element.cryptoAmount.replaceAll(',', '.')));
181
+ credentialsAmount = outputs.fold(0, (acc, value) =>
182
+ acc + value.formattedCryptoAmount);
183
184
if (unlockedBalance < credentialsAmount) {
185
throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
186
}
187
189
- final addresses = sendItemList.map((e) => e.address).toList();
190
- final amounts = sendItemList.map((e) =>
191
- e.cryptoAmount.replaceAll(',', '.')).toList();
188
+ final moneroOutputs = outputs.map((output) =>
189
+ MoneroOutput(
190
+ address: output.address,
191
+ amount: output.cryptoAmount.replaceAll(',', '.')))
192
+ .toList();
193
194
pendingTransactionDescription =
195
await transaction_history.createTransactionMultDest(
195
- addresses: addresses,
196
+ outputs: moneroOutputs,
197
paymentId: '',
197
- amounts: amounts,
198
- size: listSize,
198
priorityRaw: _credentials.priority.serialize(),
199
accountIndex: walletAddresses.account.id);
200
} else {
202
- final item = sendItemList.first;
203
- final address = item.address;
204
- final amount = item.sendAll
201
+ final output = outputs.first;
202
+ final address = output.address;
203
+ final amount = output.sendAll
204
? null
206
- : item.cryptoAmount.replaceAll(',', '.');
207
- final formattedAmount = item.sendAll
205
+ : output.cryptoAmount.replaceAll(',', '.');
206
+ final formattedAmount = output.sendAll
207
? null
209
- : moneroParseAmount(amount: amount);
208
+ : output.formattedCryptoAmount;
209
210
if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
211
(formattedAmount == null && unlockedBalance <= 0)) {
212
final formattedBalance = moneroAmountToString(amount: unlockedBalance);
213
214
throw MoneroTransactionCreationException(
216
- 'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${item.cryptoAmount}.');
215
+ 'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
216
}
217
218
pendingTransactionDescription =
lib/src/screens/exchange_trade/exchange_trade_page.dart
+2
-2
@@ -385,8 +385,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
385
.pendingTransactionFiatAmount +
386
' ' +
387
widget.exchangeTradeViewModel.sendViewModel.fiat.title,
388
- sendItemList: widget.exchangeTradeViewModel.sendViewModel
389
- .sendItemList);
388
+ outputs: widget.exchangeTradeViewModel.sendViewModel
389
+ .outputs);
390
});
391
});
392
}
lib/src/screens/send/send_page.dart
+22
-22
@@ -3,7 +3,7 @@ import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_a
3
import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
4
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
5
import 'package:cake_wallet/src/widgets/template_tile.dart';
6
-import 'package:cake_wallet/view_model/send/send_item.dart';
6
+import 'package:cake_wallet/view_model/send/output.dart';
7
import 'package:flutter/cupertino.dart';
8
import 'package:flutter/material.dart';
9
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -55,16 +55,16 @@ class SendPage extends BasePage {
55
onPressed: () {
56
var pageToJump = controller.page.round() - 1;
57
pageToJump = pageToJump > 0 ? pageToJump : 0;
58
- final item = _defineCurrentSendItem();
59
- sendViewModel.removeSendItem(item);
58
+ final output = _defineCurrentOutput();
59
+ sendViewModel.removeOutput(output);
60
controller.jumpToPage(pageToJump);
61
})
62
: TrailButton(
63
caption: S.of(context).clear,
64
onPressed: () {
65
- final item = _defineCurrentSendItem();
65
+ final output = _defineCurrentOutput();
66
_formKey.currentState.reset();
67
- item.reset();
67
+ output.reset();
68
});
69
});
70
@@ -85,13 +85,13 @@ class SendPage extends BasePage {
85
return PageView.builder(
86
scrollDirection: Axis.horizontal,
87
controller: controller,
88
- itemCount: sendViewModel.sendItemList.length,
88
+ itemCount: sendViewModel.outputs.length,
89
itemBuilder: (context, index) {
90
- final item = sendViewModel.sendItemList[index];
90
+ final output = sendViewModel.outputs[index];
91
92
return SendCard(
93
- key: item.key,
94
- item: item,
93
+ key: output.key,
94
+ output: output,
95
sendViewModel: sendViewModel,
96
);
97
}
@@ -104,7 +104,7 @@ class SendPage extends BasePage {
104
child: Container(
105
height: 10,
106
child: Observer(builder: (_) {
107
- final count = sendViewModel.sendItemList.length;
107
+ final count = sendViewModel.outputs.length;
108
109
return count > 1
110
? SmoothPageIndicator(
@@ -211,11 +211,11 @@ class SendPage extends BasePage {
211
amount: template.amount,
212
from: template.cryptoCurrency,
213
onTap: () async {
214
- final item = _defineCurrentSendItem();
215
- item.address =
214
+ final output = _defineCurrentOutput();
215
+ output.address =
216
template.address;
217
- item.setCryptoAmount(template.amount);
218
- final parsedAddress = await item
217
+ output.setCryptoAmount(template.amount);
218
+ final parsedAddress = await output
219
.applyOpenaliasOrUnstoppableDomains();
220
showAddressAlert(context, parsedAddress);
221
},
@@ -263,7 +263,7 @@ class SendPage extends BasePage {
263
padding: EdgeInsets.only(bottom: 12),
264
child: PrimaryButton(
265
onPressed: () {
266
- sendViewModel.addSendItem();
266
+ sendViewModel.addOutput();
267
},
268
text: S.of(context).add_receiver,
269
color: Colors.green,
@@ -274,16 +274,16 @@ class SendPage extends BasePage {
274
return LoadingPrimaryButton(
275
onPressed: () async {
276
if (!_formKey.currentState.validate()) {
277
- if (sendViewModel.sendItemList.length > 1) {
277
+ if (sendViewModel.outputs.length > 1) {
278
showErrorValidationAlert(context);
279
}
280
281
return;
282
}
283
284
- final notValidItems = sendViewModel.sendItemList
284
+ final notValidItems = sendViewModel.outputs
285
.where((item) =>
286
- item.address.isEmpty || item.cryptoAmount.isEmpty)
286
+ item.address.isEmpty || item.cryptoAmount.isEmpty)
287
.toList();
288
289
if (notValidItems?.isNotEmpty ?? false) {
@@ -343,7 +343,7 @@ class SendPage extends BasePage {
343
feeValue: sendViewModel.pendingTransaction.feeFormatted,
344
feeFiatAmount: sendViewModel.pendingTransactionFeeFiatAmount
345
+ ' ' + sendViewModel.fiat.title,
346
- sendItemList: sendViewModel.sendItemList,
346
+ outputs: sendViewModel.outputs,
347
rightButtonText: S.of(context).ok,
348
leftButtonText: S.of(context).cancel,
349
actionRightButton: () {
@@ -381,7 +381,7 @@ class SendPage extends BasePage {
381
382
if (state is TransactionCommitted) {
383
WidgetsBinding.instance.addPostFrameCallback((_) {
384
- sendViewModel.clearSendItemList();
384
+ sendViewModel.clearOutputs();
385
});
386
}
387
});
@@ -389,9 +389,9 @@ class SendPage extends BasePage {
389
_effectsInstalled = true;
390
}
391
392
- SendItem _defineCurrentSendItem() {
392
+ Output _defineCurrentOutput() {
393
final itemCount = controller.page.round();
394
- return sendViewModel.sendItemList[itemCount];
394
+ return sendViewModel.outputs[itemCount];
395
}
396
397
void showErrorValidationAlert(BuildContext context) async {
lib/src/screens/send/send_template_page.dart
+11
-11
@@ -14,7 +14,7 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
14
15
class SendTemplatePage extends BasePage {
16
SendTemplatePage({@required this.sendTemplateViewModel}) {
17
- sendTemplateViewModel.sendItem.reset();
17
+ sendTemplateViewModel.output.reset();
18
}
19
20
final SendTemplateViewModel sendTemplateViewModel;
@@ -258,21 +258,21 @@ class SendTemplatePage extends BasePage {
258
return;
259
}
260
261
- final item = sendTemplateViewModel.sendItem;
261
+ final output = sendTemplateViewModel.output;
262
263
- reaction((_) => item.fiatAmount, (String amount) {
263
+ reaction((_) => output.fiatAmount, (String amount) {
264
if (amount != _fiatAmountController.text) {
265
_fiatAmountController.text = amount;
266
}
267
});
268
269
- reaction((_) => item.cryptoAmount, (String amount) {
269
+ reaction((_) => output.cryptoAmount, (String amount) {
270
if (amount != _cryptoAmountController.text) {
271
_cryptoAmountController.text = amount;
272
}
273
});
274
275
- reaction((_) => item.address, (String address) {
275
+ reaction((_) => output.address, (String address) {
276
if (address != _addressController.text) {
277
_addressController.text = address;
278
}
@@ -281,24 +281,24 @@ class SendTemplatePage extends BasePage {
281
_cryptoAmountController.addListener(() {
282
final amount = _cryptoAmountController.text;
283
284
- if (amount != item.cryptoAmount) {
285
- item.setCryptoAmount(amount);
284
+ if (amount != output.cryptoAmount) {
285
+ output.setCryptoAmount(amount);
286
}
287
});
288
289
_fiatAmountController.addListener(() {
290
final amount = _fiatAmountController.text;
291
292
- if (amount != item.fiatAmount) {
293
- item.setFiatAmount(amount);
292
+ if (amount != output.fiatAmount) {
293
+ output.setFiatAmount(amount);
294
}
295
});
296
297
_addressController.addListener(() {
298
final address = _addressController.text;
299
300
- if (item.address != address) {
301
- item.address = address;
300
+ if (output.address != address) {
301
+ output.address = address;
302
}
303
});
304
lib/src/screens/send/widgets/confirm_sending_alert.dart
+7
-7
@@ -1,5 +1,5 @@
1
import 'package:cake_wallet/palette.dart';
2
-import 'package:cake_wallet/view_model/send/send_item.dart';
2
+import 'package:cake_wallet/view_model/send/output.dart';
3
import 'package:flutter/material.dart';
4
import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
5
import 'package:cake_wallet/generated/i18n.dart';
@@ -13,14 +13,14 @@ class ConfirmSendingAlert extends BaseAlertDialog {
13
@required this.fee,
14
@required this.feeValue,
15
@required this.feeFiatAmount,
16
- @required this.sendItemList,
16
+ @required this.outputs,
17
@required this.leftButtonText,
18
@required this.rightButtonText,
19
@required this.actionLeftButton,
20
@required this.actionRightButton,
21
this.alertBarrierDismissible = true
22
}) {
23
- itemCount = sendItemList.length;
23
+ itemCount = outputs.length;
24
recipientTitle = itemCount > 1
25
? S.current.transaction_details_recipient_address
26
: S.current.recipient_address;
@@ -33,7 +33,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
33
final String fee;
34
final String feeValue;
35
final String feeFiatAmount;
36
- final List<SendItem> sendItemList;
36
+ final List<Output> outputs;
37
final String leftButtonText;
38
final String rightButtonText;
39
final VoidCallback actionLeftButton;
@@ -179,10 +179,10 @@ class ConfirmSendingAlert extends BaseAlertDialog {
179
physics: NeverScrollableScrollPhysics(),
180
itemCount: itemCount,
181
itemBuilder: (context, index) {
182
- final item = sendItemList[index];
182
+ final item = outputs[index];
183
final _address = item.address;
184
final _amount =
185
- item.cryptoAmount.replaceAll(',', '.');
185
+ item.cryptoAmount.replaceAll(',', '.');
186
187
return Column(
188
children: [
@@ -225,7 +225,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
225
: Padding(
226
padding: EdgeInsets.only(top: 8),
227
child: Text(
228
- sendItemList.first.address,
228
+ outputs.first.address,
229
style: TextStyle(
230
fontSize: 12,
231
fontWeight: FontWeight.w600,
lib/src/screens/send/widgets/send_card.dart
+34
-34
@@ -4,7 +4,7 @@ import 'package:cake_wallet/routes.dart';
4
import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_alert.dart';
5
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
6
import 'package:cake_wallet/src/widgets/picker.dart';
7
-import 'package:cake_wallet/view_model/send/send_item.dart';
7
+import 'package:cake_wallet/view_model/send/output.dart';
8
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
9
import 'package:flutter/cupertino.dart';
10
import 'package:flutter/material.dart';
@@ -19,21 +19,21 @@ import 'package:cake_wallet/generated/i18n.dart';
19
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
20
21
class SendCard extends StatefulWidget {
22
- SendCard({Key key, @required this.item, @required this.sendViewModel}) : super(key: key);
22
+ SendCard({Key key, @required this.output, @required this.sendViewModel}) : super(key: key);
23
24
- final SendItem item;
24
+ final Output output;
25
final SendViewModel sendViewModel;
26
27
@override
28
SendCardState createState() => SendCardState(
29
- item: item,
29
+ output: output,
30
sendViewModel: sendViewModel
31
);
32
}
33
34
class SendCardState extends State<SendCard>
35
with AutomaticKeepAliveClientMixin<SendCard> {
36
- SendCardState({@required this.item, @required this.sendViewModel})
36
+ SendCardState({@required this.output, @required this.sendViewModel})
37
: addressController = TextEditingController(),
38
cryptoAmountController = TextEditingController(),
39
fiatAmountController = TextEditingController(),
@@ -45,7 +45,7 @@ class SendCardState extends State<SendCard>
45
static const prefixIconWidth = 34.0;
46
static const prefixIconHeight = 34.0;
47
48
- final SendItem item;
48
+ final Output output;
49
final SendViewModel sendViewModel;
50
51
final TextEditingController addressController;
@@ -143,7 +143,7 @@ class SendCardState extends State<SendCard>
143
.decorationColor),
144
onPushPasteButton: (context) async {
145
final parsedAddress =
146
- await item.applyOpenaliasOrUnstoppableDomains();
146
+ await output.applyOpenaliasOrUnstoppableDomains();
147
showAddressAlert(context, parsedAddress);
148
},
149
validator: sendViewModel.addressValidator,
@@ -189,7 +189,7 @@ class SendCardState extends State<SendCard>
189
.decorationColor,
190
fontWeight: FontWeight.w500,
191
fontSize: 14),
192
- validator: item.sendAll
192
+ validator: output.sendAll
193
? sendViewModel.allAmountValidator
194
: sendViewModel
195
.amountValidator),
@@ -201,7 +201,7 @@ class SendCardState extends State<SendCard>
201
height: prefixIconHeight,
202
child: InkWell(
203
onTap: () async =>
204
- item.setSendAll(),
204
+ output.setSendAll(),
205
child: Container(
206
decoration: BoxDecoration(
207
color: Theme.of(context)
@@ -349,7 +349,7 @@ class SendCardState extends State<SendCard>
349
crossAxisAlignment: CrossAxisAlignment.end,
350
children: [
351
Text(
352
- item
352
+ output
353
.estimatedFee
354
.toString() +
355
' ' +
@@ -366,7 +366,7 @@ class SendCardState extends State<SendCard>
366
padding:
367
EdgeInsets.only(top: 5),
368
child: Text(
369
- item
369
+ output
370
.estimatedFeeFiatAmount
371
+ ' ' +
372
sendViewModel
@@ -435,10 +435,10 @@ class SendCardState extends State<SendCard>
435
}
436
437
void _setEffects(BuildContext context) {
438
- addressController.text = item.address;
439
- cryptoAmountController.text = item.cryptoAmount;
440
- fiatAmountController.text = item.fiatAmount;
441
- noteController.text = item.note;
438
+ addressController.text = output.address;
439
+ cryptoAmountController.text = output.cryptoAmount;
440
+ fiatAmountController.text = output.fiatAmount;
441
+ noteController.text = output.note;
442
443
if (_effectsInstalled) {
444
return;
@@ -447,48 +447,48 @@ class SendCardState extends State<SendCard>
447
cryptoAmountController.addListener(() {
448
final amount = cryptoAmountController.text;
449
450
- if (item.sendAll && amount != S.current.all) {
451
- item.sendAll = false;
450
+ if (output.sendAll && amount != S.current.all) {
451
+ output.sendAll = false;
452
}
453
454
- if (amount != item.cryptoAmount) {
455
- item.setCryptoAmount(amount);
454
+ if (amount != output.cryptoAmount) {
455
+ output.setCryptoAmount(amount);
456
}
457
});
458
459
fiatAmountController.addListener(() {
460
final amount = fiatAmountController.text;
461
462
- if (amount != item.fiatAmount) {
463
- item.sendAll = false;
464
- item.setFiatAmount(amount);
462
+ if (amount != output.fiatAmount) {
463
+ output.sendAll = false;
464
+ output.setFiatAmount(amount);
465
}
466
});
467
468
noteController.addListener(() {
469
final note = noteController.text ?? '';
470
471
- if (note != item.note) {
472
- item.note = note;
471
+ if (note != output.note) {
472
+ output.note = note;
473
}
474
});
475
476
- reaction((_) => item.sendAll, (bool all) {
476
+ reaction((_) => output.sendAll, (bool all) {
477
if (all) {
478
cryptoAmountController.text = S.current.all;
479
fiatAmountController.text = null;
480
}
481
});
482
483
- reaction((_) => item.fiatAmount, (String amount) {
483
+ reaction((_) => output.fiatAmount, (String amount) {
484
if (amount != fiatAmountController.text) {
485
fiatAmountController.text = amount;
486
}
487
});
488
489
- reaction((_) => item.cryptoAmount, (String amount) {
490
- if (item.sendAll && amount != S.current.all) {
491
- item.sendAll = false;
489
+ reaction((_) => output.cryptoAmount, (String amount) {
490
+ if (output.sendAll && amount != S.current.all) {
491
+ output.sendAll = false;
492
}
493
494
if (amount != cryptoAmountController.text) {
@@ -496,7 +496,7 @@ class SendCardState extends State<SendCard>
496
}
497
});
498
499
- reaction((_) => item.address, (String address) {
499
+ reaction((_) => output.address, (String address) {
500
if (address != addressController.text) {
501
addressController.text = address;
502
}
@@ -505,12 +505,12 @@ class SendCardState extends State<SendCard>
505
addressController.addListener(() {
506
final address = addressController.text;
507
508
- if (item.address != address) {
509
- item.address = address;
508
+ if (output.address != address) {
509
+ output.address = address;
510
}
511
});
512
513
- reaction((_) => item.note, (String note) {
513
+ reaction((_) => output.note, (String note) {
514
if (note != noteController.text) {
515
noteController.text = note;
516
}
@@ -518,7 +518,7 @@ class SendCardState extends State<SendCard>
518
519
addressFocusNode.addListener(() async {
520
if (!addressFocusNode.hasFocus && addressController.text.isNotEmpty) {
521
- final parsedAddress = await item.applyOpenaliasOrUnstoppableDomains();
521
+ final parsedAddress = await output.applyOpenaliasOrUnstoppableDomains();
522
showAddressAlert(context, parsedAddress);
523
}
524
});
lib/view_model/exchange/exchange_trade_view_model.dart
+4
-4
@@ -79,11 +79,11 @@ abstract class ExchangeTradeViewModelBase with Store {
79
return;
80
}
81
82
- sendViewModel.clearSendItemList();
83
- final item = sendViewModel.sendItemList.first;
82
+ sendViewModel.clearOutputs();
83
+ final output = sendViewModel.outputs.first;
84
85
- item.address = trade.inputAddress;
86
- item.setCryptoAmount(trade.amount);
85
+ output.address = trade.inputAddress;
86
+ output.setCryptoAmount(trade.amount);
87
await sendViewModel.createTransaction();
88
}
89
lib/view_model/send/output.dart
renamed
+16
-7
@@ -15,14 +15,14 @@ import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
15
import 'package:cake_wallet/store/settings_store.dart';
16
import 'package:cake_wallet/generated/i18n.dart';
17
18
-part 'send_item.g.dart';
18
+part 'output.g.dart';
19
20
const String cryptoNumberPattern = '0.0';
21
22
-class SendItem = SendItemBase with _$SendItem;
22
+class Output = OutputBase with _$Output;
23
24
-abstract class SendItemBase with Store {
25
- SendItemBase(this._wallet, this._settingsStore, this._fiatConversationStore)
24
+abstract class OutputBase with Store {
25
+ OutputBase(this._wallet, this._settingsStore, this._fiatConversationStore)
26
:_cryptoNumberFormat = NumberFormat(cryptoNumberPattern) {
27
reset();
28
_setCryptoNumMaximumFractionDigits();
@@ -47,8 +47,8 @@ abstract class SendItemBase with Store {
47
bool sendAll;
48
49
@computed
50
- double get estimatedFee {
51
- int amount;
50
+ int get formattedCryptoAmount {
51
+ int amount = 0;
52
53
try {
54
if (cryptoAmount?.isNotEmpty ?? false) {
@@ -72,9 +72,18 @@ abstract class SendItemBase with Store {
72
amount = _amount;
73
}
74
}
75
+ } catch(e) {
76
+ amount = 0;
77
+ }
78
+
79
+ return amount;
80
+ }
81
82
+ @computed
83
+ double get estimatedFee {
84
+ try {
85
final fee = _wallet.calculateEstimatedFee(
77
- _settingsStore.priority[_wallet.type], amount);
86
+ _settingsStore.priority[_wallet.type], formattedCryptoAmount);
87
88
if (_wallet is ElectrumWallet) {
89
return bitcoinAmountToDouble(amount: fee);
lib/view_model/send/send_template_view_model.dart
+3
-3
@@ -1,4 +1,4 @@
1
-import 'package:cake_wallet/view_model/send/send_item.dart';
1
+import 'package:cake_wallet/view_model/send/output.dart';
2
import 'package:mobx/mobx.dart';
3
import 'package:cake_wallet/entities/template.dart';
4
import 'package:cake_wallet/store/templates/send_template_store.dart';
@@ -21,10 +21,10 @@ abstract class SendTemplateViewModelBase with Store {
21
SendTemplateViewModelBase(this._wallet, this._settingsStore,
22
this._sendTemplateStore, this._fiatConversationStore) {
23
24
- sendItem = SendItem(_wallet, _settingsStore, _fiatConversationStore);
24
+ output = Output(_wallet, _settingsStore, _fiatConversationStore);
25
}
26
27
- SendItem sendItem;
27
+ Output output;
28
29
Validator get amountValidator => AmountValidator(type: _wallet.type);
30
lib/view_model/send/send_view_model.dart
+19
-19
@@ -2,7 +2,7 @@ import 'package:cake_wallet/bitcoin/bitcoin_transaction_priority.dart';
2
import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
3
import 'package:cake_wallet/entities/transaction_description.dart';
4
import 'package:cake_wallet/entities/transaction_priority.dart';
5
-import 'package:cake_wallet/view_model/send/send_item.dart';
5
+import 'package:cake_wallet/view_model/send/output.dart';
6
import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
7
import 'package:cake_wallet/view_model/settings/settings_view_model.dart';
8
import 'package:hive/hive.dart';
@@ -42,33 +42,33 @@ abstract class SendViewModelBase with Store {
42
_settingsStore.priority[_wallet.type] = priorities.first;
43
}
44
45
- sendItemList = ObservableList<SendItem>()
46
- ..add(SendItem(_wallet, _settingsStore, _fiatConversationStore));
45
+ outputs = ObservableList<Output>()
46
+ ..add(Output(_wallet, _settingsStore, _fiatConversationStore));
47
}
48
49
@observable
50
ExecutionState state;
51
52
- ObservableList<SendItem> sendItemList;
52
+ ObservableList<Output> outputs;
53
54
@action
55
- void addSendItem() {
56
- sendItemList.add(SendItem(_wallet, _settingsStore, _fiatConversationStore));
55
+ void addOutput() {
56
+ outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore));
57
}
58
59
@action
60
- void removeSendItem(SendItem item) {
61
- sendItemList.remove(item);
60
+ void removeOutput(Output output) {
61
+ outputs.remove(output);
62
}
63
64
@action
65
- void clearSendItemList() {
66
- sendItemList.clear();
67
- addSendItem();
65
+ void clearOutputs() {
66
+ outputs.clear();
67
+ addOutput();
68
}
69
70
@computed
71
- bool get isBatchSending => sendItemList.length > 1;
71
+ bool get isBatchSending => outputs.length > 1;
72
73
@computed
74
String get pendingTransactionFiatAmount {
@@ -150,14 +150,14 @@ abstract class SendViewModelBase with Store {
150
151
@action
152
Future<void> commitTransaction() async {
153
- String address = sendItemList.fold('', (previousValue, item) {
154
- return previousValue + item.address + '\n';
153
+ String address = outputs.fold('', (acc, value) {
154
+ return acc + value.address + '\n';
155
});
156
157
address = address.trim();
158
159
- String note = sendItemList.fold('', (previousValue, item) {
160
- return previousValue + item.note + '\n';
159
+ String note = outputs.fold('', (acc, value) {
160
+ return acc + value.note + '\n';
161
});
162
163
note = note.trim();
@@ -192,17 +192,17 @@ abstract class SendViewModelBase with Store {
192
final priority = _settingsStore.priority[_wallet.type];
193
194
return BitcoinTransactionCredentials(
195
- sendItemList, priority as BitcoinTransactionPriority);
195
+ outputs, priority as BitcoinTransactionPriority);
196
case WalletType.litecoin:
197
final priority = _settingsStore.priority[_wallet.type];
198
199
return BitcoinTransactionCredentials(
200
- sendItemList, priority as BitcoinTransactionPriority);
200
+ outputs, priority as BitcoinTransactionPriority);
201
case WalletType.monero:
202
final priority = _settingsStore.priority[_wallet.type];
203
204
return MoneroTransactionCreationCredentials(
205
- sendItemList: sendItemList,
205
+ outputs: outputs,
206
priority: priority as MoneroTransactionPriority);
207
default:
208
return null;