20
import 'package:cw_core/card_design.dart';
21
import 'package:cw_core/wallet_type.dart';
22
import 'package:flutter/material.dart';
23
+import 'package:flutter/semantics.dart';
24
import 'package:flutter_mobx/flutter_mobx.dart';
25
26
import 'package:cake_wallet/utils/list_item.dart';
214
border: Border.all(
215
color: Theme.of(context).colorScheme.surfaceContainerHighest, width: 1),
216
borderRadius: BorderRadius.circular(99999)),
216
- child: TextField(
217
- controller: controller,
218
- decoration: InputDecoration(
219
- hintText: S.of(context).search,
220
- hintStyle: TextStyle(
221
- fontWeight: FontWeight.w600,
222
- ),
223
- prefixIcon: Icon(Icons.search),
224
- filled: false,
225
- enabledBorder: OutlineInputBorder(
226
- borderRadius: BorderRadius.circular(99999),
227
- borderSide: BorderSide.none,
228
- ),
229
- focusedBorder: OutlineInputBorder(
230
- borderRadius: BorderRadius.circular(99999),
231
- borderSide: BorderSide.none,
217
+ // The hint names the field only while it is empty, so the label is
218
+ // supplied once there is text to keep exactly one announcement.
219
+ child: MergeSemantics(
220
+ child: Semantics(
221
+ label: controller.text.isEmpty ? null : S.of(context).search,
222
+ child: TextField(
223
+ controller: controller,
224
+ decoration: InputDecoration(
225
+ hintText: S.of(context).search,
226
+ hintStyle: TextStyle(
227
+ fontWeight: FontWeight.w600,
228
+ ),
229
+ prefixIcon: ExcludeSemantics(child: Icon(Icons.search)),
230
+ filled: false,
231
+ enabledBorder: OutlineInputBorder(
232
+ borderRadius: BorderRadius.circular(99999),
233
+ borderSide: BorderSide.none,
234
+ ),
235
+ focusedBorder: OutlineInputBorder(
236
+ borderRadius: BorderRadius.circular(99999),
237
+ borderSide: BorderSide.none,
238
+ ),
239
+ contentPadding: EdgeInsets.symmetric(vertical: 8),
240
+ ),
241
),
233
- contentPadding: EdgeInsets.symmetric(vertical: 8),
242
),
243
),
244
),
342
@override
343
Widget build(BuildContext context) {
344
final hasLabel = item.name != null && item.name!.isNotEmpty;
345
+ final hideLabel = item.isHidden ? S.of(context).unhide_address : S.of(context).hide_address;
346
338
- return GestureDetector(
339
- onTap: onSelect,
340
- child: Padding(
341
- padding: const EdgeInsets.symmetric(horizontal: 16.0),
342
- child: LongPressPopupBuilder(
343
- popup: LongPressMenu(
344
- items: [
345
- LongPressMenuItem(
346
- label: S.of(context).set_label,
347
- iconPath: "assets/new-ui/address_set_label.svg",
348
- onSelected: () async {
349
- Navigator.of(context, rootNavigator: true).pop();
350
- final res = await showPopUp(
351
- context: context,
352
- builder: (context) => getIt.get<AddressLabelInputPopup>(param1: item));
347
+ Future<void> editLabel() async {
348
+ final res = await showPopUp(
349
+ context: context, builder: (context) => getIt.get<AddressLabelInputPopup>(param1: item));
350
354
- if (res != null) {
355
- onLabelChanged();
356
- }
357
- }),
358
- LongPressMenuItem(
359
- label: item.isHidden ? S.of(context).unhide_address : S.of(context).hide_address,
360
- iconPath: "assets/new-ui/address_hide.svg",
361
- onSelected: () {
362
- Navigator.of(context, rootNavigator: true).pop();
363
- onAddressHidden();
364
- },
365
- color: Theme.of(context).colorScheme.error),
366
- LongPressMenuItem(
367
- label: 'Info',
368
- iconPath: "assets/images/info_icon.svg",
369
- onSelected: () async {
370
- Navigator.of(context, rootNavigator: true).pop();
371
- await showPopUp(
372
- context: context,
373
- builder: (context) => getIt.get<AddressInfoPopup>(param1: item));
374
- }),
375
- ],
376
- ),
377
- child: AnimatedContainer(
378
- duration: Duration(milliseconds: 150),
379
- decoration: BoxDecoration(
380
- color: selected
381
- ? Theme.of(context).colorScheme.surfaceContainerHigh
382
- : Theme.of(context).colorScheme.surfaceContainer,
383
- borderRadius: BorderRadius.vertical(
384
- top: Radius.circular(first ? 16 : 0),
385
- bottom: Radius.circular(last ? 16 : 0),
351
+ if (res != null) {
352
+ onLabelChanged();
353
+ }
354
+ }
355
+
356
+ Future<void> showInfo() async {
357
+ await showPopUp(
358
+ context: context, builder: (context) => getIt.get<AddressInfoPopup>(param1: item));
359
+ }
360
+
361
+ // The row is a single control: selection on tap, and the actions that are
362
+ // otherwise reachable only by long press exposed as custom actions.
363
+ return MergeSemantics(
364
+ child: Semantics(
365
+ button: true,
366
+ selected: selected,
367
+ customSemanticsActions: <CustomSemanticsAction, VoidCallback>{
368
+ CustomSemanticsAction(label: S.of(context).set_label): editLabel,
369
+ CustomSemanticsAction(label: hideLabel): onAddressHidden,
370
+ CustomSemanticsAction(label: S.of(context).info): showInfo,
371
+ },
372
+ child: GestureDetector(
373
+ onTap: onSelect,
374
+ child: Padding(
375
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
376
+ child: LongPressPopupBuilder(
377
+ popup: LongPressMenu(
378
+ items: [
379
+ LongPressMenuItem(
380
+ label: S.of(context).set_label,
381
+ iconPath: "assets/new-ui/address_set_label.svg",
382
+ onSelected: () {
383
+ Navigator.of(context, rootNavigator: true).pop();
384
+ editLabel();
385
+ }),
386
+ LongPressMenuItem(
387
+ label: hideLabel,
388
+ iconPath: "assets/new-ui/address_hide.svg",
389
+ onSelected: () {
390
+ Navigator.of(context, rootNavigator: true).pop();
391
+ onAddressHidden();
392
+ },
393
+ color: Theme.of(context).colorScheme.error),
394
+ LongPressMenuItem(
395
+ label: S.of(context).info,
396
+ iconPath: "assets/images/info_icon.svg",
397
+ onSelected: () {
398
+ Navigator.of(context, rootNavigator: true).pop();
399
+ showInfo();
400
+ }),
401
+ ],
402
),
387
- ),
388
- child: Padding(
389
- padding: const EdgeInsets.all(12.0),
390
- child: Row(
391
- spacing: 8,
392
- mainAxisSize: MainAxisSize.max,
393
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
394
- children: [
395
- Expanded(
396
- child: Column(
397
- children: [
398
- Row(
399
- spacing: 4,
403
+ child: AnimatedContainer(
404
+ duration: Duration(milliseconds: 150),
405
+ decoration: BoxDecoration(
406
+ color: selected
407
+ ? Theme.of(context).colorScheme.surfaceContainerHigh
408
+ : Theme.of(context).colorScheme.surfaceContainer,
409
+ borderRadius: BorderRadius.vertical(
410
+ top: Radius.circular(first ? 16 : 0),
411
+ bottom: Radius.circular(last ? 16 : 0),
412
+ ),
413
+ ),
414
+ child: Padding(
415
+ padding: const EdgeInsets.all(12.0),
416
+ child: Row(
417
+ spacing: 8,
418
+ mainAxisSize: MainAxisSize.max,
419
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
420
+ children: [
421
+ Expanded(
422
+ child: Column(
423
children: [
401
- if (hasLabel)
402
- Text(
403
- item.name!,
404
- style: TextStyle(
405
- fontSize: 12,
406
- color: Theme.of(context).colorScheme.onSurface,
407
- fontWeight: FontWeight.w500),
408
- ),
409
- Expanded(
410
- child: AddressFormatter.buildSegmentedAddress(
411
- address: item.address,
412
- walletType: walletType,
413
- textAlign: TextAlign.left,
414
- evenTextStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
424
+ Row(
425
+ spacing: 4,
426
+ children: [
427
+ if (hasLabel)
428
+ Text(
429
+ item.name!,
430
+ style: TextStyle(
431
fontSize: 12,
416
- fontWeight: FontWeight.w400,
417
- color: hasLabel
418
- ? Theme.of(context).colorScheme.onSurfaceVariant
419
- : Theme.of(context).colorScheme.onSurface,
420
- ),
421
- shouldTruncate: (hasLabel)),
432
+ color: Theme.of(context).colorScheme.onSurface,
433
+ fontWeight: FontWeight.w500),
434
+ ),
435
+ Expanded(
436
+ child: AddressFormatter.buildSegmentedAddress(
437
+ address: item.address,
438
+ walletType: walletType,
439
+ textAlign: TextAlign.left,
440
+ evenTextStyle: Theme.of(context).textTheme.bodyMedium!.copyWith(
441
+ fontSize: 12,
442
+ fontWeight: FontWeight.w400,
443
+ color: hasLabel
444
+ ? Theme.of(context).colorScheme.onSurfaceVariant
445
+ : Theme.of(context).colorScheme.onSurface,
446
+ ),
447
+ shouldTruncate: (hasLabel)),
448
+ ),
449
+ ],
450
),
451
+ Row(
452
+ mainAxisSize: MainAxisSize.max,
453
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
454
+ children: [
455
+ Text(
456
+ "${S.of(context).transactions}: ${item.txCount}",
457
+ style: TextStyle(
458
+ fontSize: 12,
459
+ color: Theme.of(context).colorScheme.onSurfaceVariant),
460
+ ),
461
+ Text(
462
+ "${hasReceived ? S.of(context).received : S.of(context).balance}: ${item.balance}",
463
+ style: TextStyle(
464
+ fontSize: 12,
465
+ color: Theme.of(context).colorScheme.onSurfaceVariant)),
466
+ ],
467
+ )
468
],
469
),
425
- Row(
426
- mainAxisSize: MainAxisSize.max,
427
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
428
- children: [
429
- Text(
430
- "${S.of(context).transactions}: ${item.txCount}",
431
- style: TextStyle(
432
- fontSize: 12,
433
- color: Theme.of(context).colorScheme.onSurfaceVariant),
434
- ),
435
- Text(
436
- "${hasReceived ? S.of(context).received : S.of(context).balance}: ${item.balance}",
437
- style: TextStyle(
438
- fontSize: 12,
439
- color: Theme.of(context).colorScheme.onSurfaceVariant)),
440
- ],
441
- )
442
- ],
443
- ),
470
+ ),
471
+ // The row's selected state carries this information.
472
+ if (selected)
473
+ ExcludeSemantics(
474
+ child: CakeImageWidget(imageUrl: "assets/new-ui/checkmark.svg"))
475
+ ],
476
),
445
- if (selected) CakeImageWidget(imageUrl: "assets/new-ui/checkmark.svg")
446
- ],
477
+ ),
478
),
479
),
480
),
494
child: Column(
495
children: [
496
Material(
466
- child: InkWell(
467
- onTap: () {
468
- Navigator.of(context).pushNamed(Routes.receiveAddresses, arguments: true);
469
- },
470
- child: Container(
471
- height: 48,
472
- decoration: BoxDecoration(
473
- color: Theme.of(context).colorScheme.surfaceContainer,
474
- borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
475
- ),
476
- child: Padding(
477
- padding: const EdgeInsets.symmetric(horizontal: 16.0),
478
- child: Row(
479
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
480
- children: [
481
- Text(S.of(context).show_hidden_addresses),
482
- RotatedBox(
483
- quarterTurns: 1,
484
- child: CakeImageWidget(imageUrl: "assets/new-ui/dropdown_arrow.svg"))
485
- ],
497
+ child: MergeSemantics(
498
+ child: Semantics(
499
+ button: true,
500
+ child: InkWell(
501
+ onTap: () {
502
+ Navigator.of(context).pushNamed(Routes.receiveAddresses, arguments: true);
503
+ },
504
+ child: Container(
505
+ height: 48,
506
+ decoration: BoxDecoration(
507
+ color: Theme.of(context).colorScheme.surfaceContainer,
508
+ borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
509
+ ),
510
+ child: Padding(
511
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
512
+ child: Row(
513
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
514
+ children: [
515
+ Text(S.of(context).show_hidden_addresses),
516
+ ExcludeSemantics(
517
+ child: RotatedBox(
518
+ quarterTurns: 1,
519
+ child:
520
+ CakeImageWidget(imageUrl: "assets/new-ui/dropdown_arrow.svg")),
521
+ )
522
+ ],
523
+ ),
524
+ ),
525
),
526
),
527
),