CAKE-359 | added text field for extracted (from Yat, Unstoppable Domains, OpenAlias) address to send_card.dart; added extractedAddress and isParsedAddress parameters to output.dart; applied extractedAddress to monero_wallet.dart and electrum_wallet.dart; added TextValidator to send_view_model.dart

OleksandrSobol committed Sep 22, 2021 at 16:47 UTC 3b649ef6829628ff6a4bb5a6b431605c99288ad8
7 files changed +118 -71
lib/bitcoin/electrum_wallet.dart
+5 -1
@@ -280,8 +280,12 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
280 ? item.formattedCryptoAmount
281 : amount;
282
283 + final outputAddress = item.isParsedAddress
284 + ? item.extractedAddress
285 + : item.address;
286 +
287 txb.addOutput(
284 - addressToOutputScript(item.address, networkType),
288 + addressToOutputScript(outputAddress, networkType),
289 outputAmount);
290 });
291
lib/monero/monero_wallet.dart
+12 -6
@@ -175,11 +175,15 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
175 throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
176 }
177
178 - final moneroOutputs = outputs.map((output) =>
179 - MoneroOutput(
180 - address: output.address,
181 - amount: output.cryptoAmount.replaceAll(',', '.')))
182 - .toList();
178 + final moneroOutputs = outputs.map((output) {
179 + final outputAddress = output.isParsedAddress
180 + ? output.extractedAddress
181 + : output.address;
182 +
183 + return MoneroOutput(
184 + address: outputAddress,
185 + amount: output.cryptoAmount.replaceAll(',', '.'));
186 + }).toList();
187
188 pendingTransactionDescription =
189 await transaction_history.createTransactionMultDest(
@@ -188,7 +192,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
192 accountIndex: walletAddresses.account.id);
193 } else {
194 final output = outputs.first;
191 - final address = output.address;
195 + final address = output.isParsedAddress
196 + ? output.extractedAddress
197 + : output.address;
198 final amount = output.sendAll
199 ? null
200 : output.cryptoAmount.replaceAll(',', '.');
lib/src/screens/send/send_page.dart
-1
@@ -1,5 +1,4 @@
1 import 'dart:ui';
2 -import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_alert.dart';
2 import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
3 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
4 import 'package:cake_wallet/src/widgets/template_tile.dart';
lib/src/screens/send/widgets/confirm_sending_alert.dart
+8 -9
@@ -1,4 +1,3 @@
1 -import 'package:cake_wallet/entities/parsed_address.dart';
1 import 'package:cake_wallet/palette.dart';
2 import 'package:cake_wallet/view_model/send/output.dart';
3 import 'package:flutter/material.dart';
@@ -274,16 +273,15 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
273 itemCount: itemCount,
274 itemBuilder: (context, index) {
275 final item = outputs[index];
277 - final _address = item.address;
276 + final _address = item.isParsedAddress
277 + ? item.extractedAddress
278 + : item.address;
279 final _amount =
280 item.cryptoAmount.replaceAll(',', '.');
280 - final isParsedAddress =
281 - item.parsedAddress.parseFrom !=
282 - ParseFrom.notParsed;
281
282 return Column(
283 children: [
286 - if (isParsedAddress) Padding(
284 + if (item.isParsedAddress) Padding(
285 padding: EdgeInsets.only(top: 8),
286 child: Text(
287 item.parsedAddress.name,
@@ -334,8 +332,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
332 })
333 : Column(
334 children: [
337 - if (outputs.first.parsedAddress.parseFrom !=
338 - ParseFrom.notParsed) Padding(
335 + if (outputs.first.isParsedAddress) Padding(
336 padding: EdgeInsets.only(top: 8),
337 child: Text(
338 outputs.first.parsedAddress.name,
@@ -352,7 +349,9 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
349 Padding(
350 padding: EdgeInsets.only(top: 8),
351 child: Text(
355 - outputs.first.address,
352 + outputs.first.isParsedAddress
353 + ? outputs.first.extractedAddress
354 + : outputs.first.address,
355 style: TextStyle(
356 fontSize: 10,
357 fontWeight: FontWeight.w600,
lib/src/screens/send/widgets/send_card.dart
+81 -53
@@ -1,7 +1,6 @@
1 import 'dart:ui';
2 import 'package:cake_wallet/entities/transaction_priority.dart';
3 import 'package:cake_wallet/routes.dart';
4 -import 'package:cake_wallet/src/screens/send/widgets/parse_address_from_domain_alert.dart';
4 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
5 import 'package:cake_wallet/src/widgets/picker.dart';
6 import 'package:cake_wallet/view_model/send/output.dart';
@@ -38,6 +37,7 @@ class SendCardState extends State<SendCard>
37 cryptoAmountController = TextEditingController(),
38 fiatAmountController = TextEditingController(),
39 noteController = TextEditingController(),
40 + extractedAddressController = TextEditingController(),
41 cryptoAmountFocus = FocusNode(),
42 fiatAmountFocus = FocusNode(),
43 addressFocusNode = FocusNode();
@@ -52,6 +52,7 @@ class SendCardState extends State<SendCard>
52 final TextEditingController cryptoAmountController;
53 final TextEditingController fiatAmountController;
54 final TextEditingController noteController;
55 + final TextEditingController extractedAddressController;
56 final FocusNode cryptoAmountFocus;
57 final FocusNode fiatAmountFocus;
58 final FocusNode addressFocusNode;
@@ -101,58 +102,80 @@ class SendCardState extends State<SendCard>
102 child: Padding(
103 padding: EdgeInsets.fromLTRB(24, 100, 24, 32),
104 child: SingleChildScrollView(
104 - child: Column(
105 + child: Observer(builder: (_) => Column(
106 mainAxisSize: MainAxisSize.min,
107 children: <Widget>[
107 - AddressTextField(
108 - focusNode: addressFocusNode,
109 - controller: addressController,
110 - onURIScanned: (uri) {
111 - var address = '';
112 - var amount = '';
113 -
114 - if (uri != null) {
115 - address = uri.path;
116 - amount = uri.queryParameters['tx_amount'] ??
117 - uri.queryParameters['amount'];
118 - } else {
119 - address = uri.toString();
120 - }
121 -
122 - addressController.text = address;
123 - cryptoAmountController.text = amount;
124 - },
125 - options: [
126 - AddressTextFieldOption.paste,
127 - AddressTextFieldOption.qrCode,
128 - AddressTextFieldOption.addressBook
129 - ],
130 - buttonColor: Theme.of(context)
131 - .primaryTextTheme
132 - .display1
133 - .color,
134 - borderColor: Theme.of(context)
135 - .primaryTextTheme
136 - .headline
137 - .color,
138 - textStyle: TextStyle(
139 - fontSize: 14,
140 - fontWeight: FontWeight.w500,
141 - color: Colors.white),
142 - hintStyle: TextStyle(
143 - fontSize: 14,
144 - fontWeight: FontWeight.w500,
145 - color: Theme.of(context)
146 - .primaryTextTheme
147 - .headline
148 - .decorationColor),
149 - onPushPasteButton: (context) async {
150 - output.resetParsedAddress();
151 - await output.fetchParsedAddress(context);
152 - },
153 - onPushAddressBookButton: (context) =>
154 - output.resetParsedAddress(),
155 - validator: sendViewModel.addressValidator,
108 + Observer(builder: (_) {
109 + final validator = output.isParsedAddress
110 + ? sendViewModel.textValidator
111 + : sendViewModel.addressValidator;
112 +
113 + return AddressTextField(
114 + focusNode: addressFocusNode,
115 + controller: addressController,
116 + onURIScanned: (uri) {
117 + var address = '';
118 + var amount = '';
119 +
120 + if (uri != null) {
121 + address = uri.path;
122 + amount = uri.queryParameters['tx_amount'] ??
123 + uri.queryParameters['amount'];
124 + } else {
125 + address = uri.toString();
126 + }
127 +
128 + addressController.text = address;
129 + cryptoAmountController.text = amount;
130 + },
131 + options: [
132 + AddressTextFieldOption.paste,
133 + AddressTextFieldOption.qrCode,
134 + AddressTextFieldOption.addressBook
135 + ],
136 + buttonColor: Theme.of(context)
137 + .primaryTextTheme
138 + .display1
139 + .color,
140 + borderColor: Theme.of(context)
141 + .primaryTextTheme
142 + .headline
143 + .color,
144 + textStyle: TextStyle(
145 + fontSize: 14,
146 + fontWeight: FontWeight.w500,
147 + color: Colors.white),
148 + hintStyle: TextStyle(
149 + fontSize: 14,
150 + fontWeight: FontWeight.w500,
151 + color: Theme.of(context)
152 + .primaryTextTheme
153 + .headline
154 + .decorationColor),
155 + onPushPasteButton: (context) async {
156 + output.resetParsedAddress();
157 + await output.fetchParsedAddress(context);
158 + },
159 + onPushAddressBookButton: (context) =>
160 + output.resetParsedAddress(),
161 + validator: validator,
162 + );
163 + }),
164 + if (output.isParsedAddress) Padding(
165 + padding: const EdgeInsets.only(top: 20),
166 + child: BaseTextFormField(
167 + controller: extractedAddressController,
168 + readOnly: true,
169 + borderColor: Theme.of(context)
170 + .primaryTextTheme
171 + .headline
172 + .color,
173 + textStyle: TextStyle(
174 + fontSize: 14,
175 + fontWeight: FontWeight.w500,
176 + color: Colors.white),
177 + validator: sendViewModel.addressValidator
178 + )
179 ),
180 Observer(
181 builder: (_) => Padding(
@@ -440,7 +463,7 @@ class SendCardState extends State<SendCard>
463 )
464 )
465 ],
443 - )
466 + ))
467 ),
468 ),
469 )
@@ -453,6 +476,7 @@ class SendCardState extends State<SendCard>
476 cryptoAmountController.text = output.cryptoAmount;
477 fiatAmountController.text = output.fiatAmount;
478 noteController.text = output.note;
479 + extractedAddressController.text = output.extractedAddress;
480
481 if (_effectsInstalled) {
482 return;
@@ -520,6 +544,7 @@ class SendCardState extends State<SendCard>
544 final address = addressController.text;
545
546 if (output.address != address) {
547 + output.resetParsedAddress();
548 output.address = address;
549 }
550 });
@@ -532,11 +557,14 @@ class SendCardState extends State<SendCard>
557
558 addressFocusNode.addListener(() async {
559 if (!addressFocusNode.hasFocus && addressController.text.isNotEmpty) {
535 - output.resetParsedAddress();
560 await output.fetchParsedAddress(context);
561 }
562 });
563
564 + reaction((_) => output.extractedAddress, (String extractedAddress) {
565 + extractedAddressController.text = extractedAddress;
566 + });
567 +
568 _effectsInstalled = true;
569 }
570
lib/view_model/send/output.dart
+10 -1
@@ -47,8 +47,16 @@ abstract class OutputBase with Store {
47 @observable
48 bool sendAll;
49
50 + @observable
51 ParsedAddress parsedAddress;
52
53 + @observable
54 + String extractedAddress;
55 +
56 + @computed
57 + bool get isParsedAddress => parsedAddress.parseFrom != ParseFrom.notParsed
58 + && parsedAddress.name.isNotEmpty;
59 +
60 @computed
61 int get formattedCryptoAmount {
62 int amount = 0;
@@ -134,6 +142,7 @@ abstract class OutputBase with Store {
142 }
143
144 void resetParsedAddress() {
145 + extractedAddress = '';
146 parsedAddress = ParsedAddress(addresses: []);
147 }
148
@@ -206,6 +215,6 @@ abstract class OutputBase with Store {
215 final domain = address;
216 final ticker = _wallet.currency.title.toLowerCase();
217 parsedAddress = await parseAddressFromDomain(domain, ticker);
209 - address = await defineAddress(context, parsedAddress);
218 + extractedAddress = await defineAddress(context, parsedAddress);
219 }
220 }
\ No newline at end of file
lib/view_model/send/send_view_model.dart
+2
@@ -117,6 +117,8 @@ abstract class SendViewModelBase with Store {
117
118 Validator get addressValidator => AddressValidator(type: _wallet.currency);
119
120 + Validator get textValidator => TextValidator();
121 +
122 @observable
123 PendingTransaction pendingTransaction;
124