CW-425 use the open alias new line UI (#1004)
* CW-425 Display Contact Name in the send view * CW-425 Ignore false positives on OpenAlias
Konstantin Ullrich committed
Aug 1, 2023 at 14:00 UTC
cfaa89d1657f95f25b8061791c1a3ec1599240e0
7 files changed
+89
-94
lib/entities/openalias_record.dart
+1
-1
@@ -37,7 +37,7 @@ class OpenaliasRecord {
37
required String ticker,
38
required List<RRecord> txtRecord,
39
}) {
40
- String address = formattedName;
40
+ String address = '';
41
String name = formattedName;
42
String note = '';
43
lib/entities/parsed_address.dart
+20
-8
@@ -1,7 +1,7 @@
1
import 'package:cake_wallet/entities/openalias_record.dart';
2
import 'package:cake_wallet/entities/yat_record.dart';
3
4
-enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed, twitter }
4
+enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed, twitter, contact }
5
6
class ParsedAddress {
7
ParsedAddress({
@@ -40,13 +40,17 @@ class ParsedAddress {
40
);
41
}
42
43
- factory ParsedAddress.fetchOpenAliasAddress({required OpenaliasRecord record, required String name}){
44
- return ParsedAddress(
45
- addresses: [record.address],
46
- name: record.name,
47
- description: record.description,
48
- parseFrom: ParseFrom.openAlias,
49
- );
43
+ factory ParsedAddress.fetchOpenAliasAddress(
44
+ {required OpenaliasRecord record, required String name}) {
45
+ if (record.address.isEmpty) {
46
+ return ParsedAddress(addresses: [name]);
47
+ }
48
+ return ParsedAddress(
49
+ addresses: [record.address],
50
+ name: record.name,
51
+ description: record.description,
52
+ parseFrom: ParseFrom.openAlias,
53
+ );
54
}
55
56
factory ParsedAddress.fetchFioAddress({required String address, required String name}){
@@ -65,6 +69,14 @@ class ParsedAddress {
69
);
70
}
71
72
+ factory ParsedAddress.fetchContactAddress({required String address, required String name}){
73
+ return ParsedAddress(
74
+ addresses: [address],
75
+ name: name,
76
+ parseFrom: ParseFrom.contact,
77
+ );
78
+ }
79
+
80
final List<String> addresses;
81
final String name;
82
final String description;
lib/src/screens/send/widgets/extract_address_from_parsed.dart
+2
-1
@@ -68,6 +68,7 @@ Future<String> extractAddressFromParsed(
68
}
69
70
return address;
71
+ case ParseFrom.contact:
72
case ParseFrom.notParsed:
73
address = parsedAddress.addresses.first;
74
return address;
@@ -85,4 +86,4 @@ Future<String> extractAddressFromParsed(
86
});
87
88
return address;
88
-}
\ No newline at end of file
89
+}
lib/src/screens/send/widgets/send_card.dart
+25
-23
@@ -103,7 +103,7 @@ class SendCardState extends State<SendCard>
103
config: KeyboardActionsConfig(
104
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
105
keyboardBarColor: Theme.of(context)
106
- .accentTextTheme!
106
+ .accentTextTheme
107
.bodyLarge!
108
.backgroundColor!,
109
nextFocus: false,
@@ -127,9 +127,9 @@ class SendCardState extends State<SendCard>
127
bottomLeft: Radius.circular(24),
128
bottomRight: Radius.circular(24)),
129
gradient: LinearGradient(colors: [
130
- Theme.of(context).primaryTextTheme!.titleMedium!.color!,
130
+ Theme.of(context).primaryTextTheme.titleMedium!.color!,
131
Theme.of(context)
132
- .primaryTextTheme!
132
+ .primaryTextTheme
133
.titleMedium!
134
.decorationColor!,
135
], begin: Alignment.topLeft, end: Alignment.bottomRight),
@@ -165,11 +165,11 @@ class SendCardState extends State<SendCard>
165
AddressTextFieldOption.addressBook
166
],
167
buttonColor: Theme.of(context)
168
- .primaryTextTheme!
168
+ .primaryTextTheme
169
.headlineMedium!
170
.color!,
171
borderColor: Theme.of(context)
172
- .primaryTextTheme!
172
+ .primaryTextTheme
173
.headlineSmall!
174
.color!,
175
textStyle: TextStyle(
@@ -180,7 +180,7 @@ class SendCardState extends State<SendCard>
180
fontSize: 14,
181
fontWeight: FontWeight.w500,
182
color: Theme.of(context)
183
- .primaryTextTheme!
183
+ .primaryTextTheme
184
.headlineSmall!
185
.decorationColor!),
186
onPushPasteButton: (context) async {
@@ -189,7 +189,9 @@ class SendCardState extends State<SendCard>
189
},
190
onPushAddressBookButton: (context) async {
191
output.resetParsedAddress();
192
- await output.fetchParsedAddress(context);
192
+ },
193
+ onSelectedContact: (contact) {
194
+ output.loadContact(contact);
195
},
196
validator: validator,
197
selectedCurrency: sendViewModel.currency,
@@ -201,7 +203,7 @@ class SendCardState extends State<SendCard>
203
controller: extractedAddressController,
204
readOnly: true,
205
borderColor: Theme.of(context)
204
- .primaryTextTheme!
206
+ .primaryTextTheme
207
.headlineSmall!
208
.color!,
209
textStyle: TextStyle(
@@ -233,7 +235,7 @@ class SendCardState extends State<SendCard>
235
height: 32,
236
decoration: BoxDecoration(
237
color: Theme.of(context)
236
- .primaryTextTheme!
238
+ .primaryTextTheme
239
.headlineMedium!
240
.color!,
241
borderRadius:
@@ -246,7 +248,7 @@ class SendCardState extends State<SendCard>
248
fontSize: 12,
249
fontWeight: FontWeight.bold,
250
color: Theme.of(context)
249
- .primaryTextTheme!
251
+ .primaryTextTheme
252
.headlineMedium!
253
.decorationColor!)),
254
),
@@ -287,7 +289,7 @@ class SendCardState extends State<SendCard>
289
color: Colors.white),
290
placeholderTextStyle: TextStyle(
291
color: Theme.of(context)
290
- .primaryTextTheme!
292
+ .primaryTextTheme
293
.headlineSmall!
294
.decorationColor!,
295
fontWeight: FontWeight.w500,
@@ -308,7 +310,7 @@ class SendCardState extends State<SendCard>
310
child: Container(
311
decoration: BoxDecoration(
312
color: Theme.of(context)
311
- .primaryTextTheme!
313
+ .primaryTextTheme
314
.headlineMedium!
315
.color!,
316
borderRadius:
@@ -325,7 +327,7 @@ class SendCardState extends State<SendCard>
327
FontWeight.bold,
328
color:
329
Theme.of(context)
328
- .primaryTextTheme!
330
+ .primaryTextTheme
331
.headlineMedium!
332
.decorationColor!))),
333
))))]),
@@ -334,7 +336,7 @@ class SendCardState extends State<SendCard>
336
)
337
)),
338
Divider(height: 1,color: Theme.of(context)
337
- .primaryTextTheme!
339
+ .primaryTextTheme
340
.headlineSmall!
341
.decorationColor!),
342
Observer(
@@ -353,7 +355,7 @@ class SendCardState extends State<SendCard>
355
fontSize: 12,
356
fontWeight: FontWeight.w600,
357
color: Theme.of(context)
356
- .primaryTextTheme!
358
+ .primaryTextTheme
359
.headlineSmall!
360
.decorationColor!),
361
)),
@@ -363,7 +365,7 @@ class SendCardState extends State<SendCard>
365
fontSize: 12,
366
fontWeight: FontWeight.w600,
367
color: Theme.of(context)
366
- .primaryTextTheme!
368
+ .primaryTextTheme
369
.headlineSmall!
370
.decorationColor!),
371
)
@@ -394,7 +396,7 @@ class SendCardState extends State<SendCard>
396
),
397
hintText: '0.00',
398
borderColor: Theme.of(context)
397
- .primaryTextTheme!
399
+ .primaryTextTheme
400
.headlineSmall!
401
.color!,
402
textStyle: TextStyle(
@@ -403,7 +405,7 @@ class SendCardState extends State<SendCard>
405
color: Colors.white),
406
placeholderTextStyle: TextStyle(
407
color: Theme.of(context)
406
- .primaryTextTheme!.headlineSmall!.decorationColor!,
408
+ .primaryTextTheme.headlineSmall!.decorationColor!,
409
fontWeight: FontWeight.w500,
410
fontSize: 14),
411
)),
@@ -414,7 +416,7 @@ class SendCardState extends State<SendCard>
416
keyboardType: TextInputType.multiline,
417
maxLines: null,
418
borderColor: Theme.of(context)
417
- .primaryTextTheme!
419
+ .primaryTextTheme
420
.headlineSmall!
421
.color!,
422
textStyle: TextStyle(
@@ -426,7 +428,7 @@ class SendCardState extends State<SendCard>
428
fontSize: 14,
429
fontWeight: FontWeight.w500,
430
color: Theme.of(context)
429
- .primaryTextTheme!
431
+ .primaryTextTheme
432
.headlineSmall!
433
.decorationColor!),
434
),
@@ -490,7 +492,7 @@ class SendCardState extends State<SendCard>
492
FontWeight.w600,
493
color: Theme
494
.of(context)
493
- .primaryTextTheme!
495
+ .primaryTextTheme
496
.headlineSmall!
497
.decorationColor!))
498
),
@@ -586,7 +588,7 @@ class SendCardState extends State<SendCard>
588
});
589
590
noteController.addListener(() {
589
- final note = noteController.text ?? '';
591
+ final note = noteController.text;
592
593
if (note != output.note) {
594
output.note = note;
@@ -676,4 +678,4 @@ class SendCardState extends State<SendCard>
678
679
@override
680
bool get wantKeepAlive => true;
679
-}
\ No newline at end of file
681
+}
lib/src/widgets/address_text_field.dart
+30
-58
@@ -1,4 +1,3 @@
1
-
1
import 'package:cake_wallet/utils/device_info.dart';
2
import 'package:cake_wallet/utils/responsive_layout_util.dart';
3
import 'package:flutter/services.dart';
@@ -16,10 +15,7 @@ class AddressTextField extends StatelessWidget {
15
{required this.controller,
16
this.isActive = true,
17
this.placeholder,
19
- this.options = const [
20
- AddressTextFieldOption.qrCode,
21
- AddressTextFieldOption.addressBook
22
- ],
18
+ this.options = const [AddressTextFieldOption.qrCode, AddressTextFieldOption.addressBook],
19
this.onURIScanned,
20
this.focusNode,
21
this.isBorderExist = true,
@@ -31,6 +27,7 @@ class AddressTextField extends StatelessWidget {
27
this.validator,
28
this.onPushPasteButton,
29
this.onPushAddressBookButton,
30
+ this.onSelectedContact,
31
this.selectedCurrency});
32
33
static const prefixIconWidth = 34.0;
@@ -52,6 +49,7 @@ class AddressTextField extends StatelessWidget {
49
final FocusNode? focusNode;
50
final Function(BuildContext context)? onPushPasteButton;
51
final Function(BuildContext context)? onPushAddressBookButton;
52
+ final Function(ContactBase contact)? onSelectedContact;
53
final CryptoCurrency? selectedCurrency;
54
55
@override
@@ -66,34 +64,27 @@ class AddressTextField extends StatelessWidget {
64
controller: controller,
65
focusNode: focusNode,
66
style: textStyle ??
69
- TextStyle(
70
- fontSize: 16,
71
- color: Theme.of(context).primaryTextTheme!.titleLarge!.color!),
67
+ TextStyle(fontSize: 16, color: Theme.of(context).primaryTextTheme.titleLarge!.color!),
68
decoration: InputDecoration(
69
suffixIcon: SizedBox(
74
- width: prefixIconWidth * options.length +
75
- (spaceBetweenPrefixIcons * options.length),
70
+ width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length),
71
),
77
- hintStyle: hintStyle ??
78
- TextStyle(fontSize: 16, color: Theme.of(context).hintColor),
72
+ hintStyle: hintStyle ?? TextStyle(fontSize: 16, color: Theme.of(context).hintColor),
73
hintText: placeholder ?? S.current.widgets_address,
74
focusedBorder: isBorderExist
75
? UnderlineInputBorder(
76
borderSide: BorderSide(
83
- color: borderColor ?? Theme.of(context).dividerColor,
84
- width: 1.0))
77
+ color: borderColor ?? Theme.of(context).dividerColor, width: 1.0))
78
: InputBorder.none,
79
disabledBorder: isBorderExist
80
? UnderlineInputBorder(
81
borderSide: BorderSide(
89
- color: borderColor ?? Theme.of(context).dividerColor,
90
- width: 1.0))
82
+ color: borderColor ?? Theme.of(context).dividerColor, width: 1.0))
83
: InputBorder.none,
84
enabledBorder: isBorderExist
85
? UnderlineInputBorder(
86
borderSide: BorderSide(
95
- color: borderColor ?? Theme.of(context).dividerColor,
96
- width: 1.0))
87
+ color: borderColor ?? Theme.of(context).dividerColor, width: 1.0))
88
: InputBorder.none,
89
),
90
validator: validator,
@@ -102,11 +93,11 @@ class AddressTextField extends StatelessWidget {
93
top: 2,
94
right: 0,
95
child: SizedBox(
105
- width: prefixIconWidth * options.length +
106
- (spaceBetweenPrefixIcons * options.length),
96
+ width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length),
97
child: Row(
108
- mainAxisAlignment: ResponsiveLayoutUtil.instance.isMobile
109
- ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end,
98
+ mainAxisAlignment: ResponsiveLayoutUtil.instance.isMobile
99
+ ? MainAxisAlignment.spaceBetween
100
+ : MainAxisAlignment.end,
101
children: [
102
SizedBox(width: 5),
103
if (this.options.contains(AddressTextFieldOption.paste)) ...[
@@ -122,20 +113,14 @@ class AddressTextField extends StatelessWidget {
113
padding: EdgeInsets.all(8),
114
decoration: BoxDecoration(
115
color: buttonColor ??
125
- Theme.of(context)
126
- .accentTextTheme
127
- !
128
- .titleLarge!
129
- .color!,
130
- borderRadius:
131
- BorderRadius.all(Radius.circular(6))),
116
+ Theme.of(context).accentTextTheme.titleLarge!.color!,
117
+ borderRadius: BorderRadius.all(Radius.circular(6))),
118
child: Image.asset(
119
'assets/images/paste_ios.png',
120
color: iconColor ??
121
Theme.of(context)
122
.primaryTextTheme
137
- !
138
- .headlineMedium!
123
+ .headlineMedium!
124
.decorationColor!,
125
)),
126
),
@@ -155,28 +140,21 @@ class AddressTextField extends StatelessWidget {
140
padding: EdgeInsets.all(8),
141
decoration: BoxDecoration(
142
color: buttonColor ??
158
- Theme.of(context)
159
- .accentTextTheme
160
-
161
- .titleLarge!
162
- .color!,
163
- borderRadius:
164
- BorderRadius.all(Radius.circular(6))),
143
+ Theme.of(context).accentTextTheme.titleLarge!.color!,
144
+ borderRadius: BorderRadius.all(Radius.circular(6))),
145
child: Image.asset(
146
'assets/images/qr_code_icon.png',
147
color: iconColor ??
148
Theme.of(context)
149
.primaryTextTheme
170
- !.headlineMedium!
150
+ .headlineMedium!
151
.decorationColor!,
152
)),
153
),
154
))
155
] else
156
SizedBox(width: 5),
177
- if (this
178
- .options
179
- .contains(AddressTextFieldOption.addressBook)) ...[
157
+ if (this.options.contains(AddressTextFieldOption.addressBook)) ...[
158
Container(
159
width: prefixIconWidth,
160
height: prefixIconHeight,
@@ -184,26 +162,19 @@ class AddressTextField extends StatelessWidget {
162
child: Semantics(
163
label: S.of(context).address_book,
164
child: InkWell(
187
- onTap: () async =>
188
- _presetAddressBookPicker(context),
165
+ onTap: () async => _presetAddressBookPicker(context),
166
child: Container(
167
padding: EdgeInsets.all(8),
168
decoration: BoxDecoration(
169
color: buttonColor ??
193
- Theme.of(context)
194
- .accentTextTheme
195
- !
196
- .titleLarge!
197
- .color!,
198
- borderRadius:
199
- BorderRadius.all(Radius.circular(6))),
170
+ Theme.of(context).accentTextTheme.titleLarge!.color!,
171
+ borderRadius: BorderRadius.all(Radius.circular(6))),
172
child: Image.asset(
173
'assets/images/open_book.png',
174
color: iconColor ??
175
Theme.of(context)
176
.primaryTextTheme
205
- !
206
- .headlineMedium!
177
+ .headlineMedium!
178
.decorationColor!,
179
)),
180
),
@@ -221,30 +192,31 @@ class AddressTextField extends StatelessWidget {
192
if (code.isEmpty) {
193
return;
194
}
224
-
195
+
196
try {
197
final uri = Uri.parse(code);
198
controller?.text = uri.path;
199
onURIScanned?.call(uri);
229
- } catch(_){
200
+ } catch (_) {
201
controller?.text = code;
202
}
203
}
204
205
Future<void> _presetAddressBookPicker(BuildContext context) async {
206
final contact = await Navigator.of(context)
236
- .pushNamed(Routes.pickerAddressBook,arguments: selectedCurrency);
207
+ .pushNamed(Routes.pickerAddressBook, arguments: selectedCurrency);
208
238
- if (contact is ContactBase && contact.address != null) {
209
+ if (contact is ContactBase) {
210
controller?.text = contact.address;
211
onPushAddressBookButton?.call(context);
212
+ onSelectedContact?.call(contact);
213
}
214
}
215
216
Future<void> _pasteAddress(BuildContext context) async {
217
final clipboard = await Clipboard.getData('text/plain');
218
final address = clipboard?.text ?? '';
247
-
219
+
220
if (address.isNotEmpty) {
221
controller?.text = address;
222
}
lib/view_model/send/output.dart
+10
-1
@@ -17,6 +17,8 @@ import 'package:cake_wallet/store/settings_store.dart';
17
import 'package:cake_wallet/generated/i18n.dart';
18
import 'package:cake_wallet/bitcoin/bitcoin.dart';
19
20
+import 'package:cake_wallet/entities/contact_base.dart';
21
+
22
part 'output.g.dart';
23
24
const String cryptoNumberPattern = '0.0';
@@ -70,7 +72,7 @@ abstract class OutputBase with Store {
72
int amount = 0;
73
74
try {
73
- if (cryptoAmount?.isNotEmpty ?? false) {
75
+ if (cryptoAmount.isNotEmpty) {
76
final _cryptoAmount = cryptoAmount.replaceAll(',', '.');
77
int _amount = 0;
78
switch (walletType) {
@@ -240,4 +242,11 @@ abstract class OutputBase with Store {
242
extractedAddress = await extractAddressFromParsed(context, parsedAddress);
243
note = parsedAddress.description;
244
}
245
+
246
+ void loadContact(ContactBase contact) {
247
+ address = contact.name;
248
+ parsedAddress = ParsedAddress.fetchContactAddress(address: contact.address, name: contact.name);
249
+ extractedAddress = parsedAddress.addresses.first;
250
+ note = parsedAddress.description;
251
+ }
252
}
pubspec_base.yaml
+1
-2
@@ -3,7 +3,6 @@ dependencies:
3
sdk: flutter
4
flutter_localizations:
5
sdk: flutter
6
- flutter_cupertino_localizations: ^1.0.1
6
intl: ^0.17.0
7
url_launcher: ^6.1.4
8
qr_flutter:
@@ -128,4 +127,4 @@ flutter:
127
- asset: assets/fonts/Lato-Regular.ttf
128
- asset: assets/fonts/Lato-Medium.ttf
129
- asset: assets/fonts/Lato-Semibold.ttf
131
- - asset: assets/fonts/Lato-Bold.ttf
\ No newline at end of file
130
+ - asset: assets/fonts/Lato-Bold.ttf