| 1 | import 'package:cake_wallet/new-ui/widgets/modern_button.dart'; |
| 2 | import 'package:flutter/material.dart'; |
| 3 | |
| 4 | void nothing() {} |
| 5 | |
| 6 | class ModalTopBar extends StatelessWidget { |
| 7 | ModalTopBar( |
| 8 | {super.key, |
| 9 | required this.title, |
| 10 | this.subtitle, |
| 11 | this.onLeadingPressed = nothing, |
| 12 | this.onTrailingPressed = nothing, |
| 13 | this.leadingIcon, |
| 14 | this.trailingIcon, |
| 15 | this.padding, |
| 16 | this.leadingWidget, |
| 17 | this.trailingWidget, |
| 18 | this.leadingSemanticLabel, |
| 19 | this.trailingSemanticLabel}) { |
| 20 | if (leadingIcon != null && leadingWidget != null) { |
| 21 | throw Exception("Cannot have both leadingIcon and leadingWidget"); |
| 22 | } |
| 23 | if (trailingIcon != null && trailingWidget != null) { |
| 24 | throw Exception("Cannot have both trailingIcon and trailingWidget"); |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | final String title; |
| 29 | final String? subtitle; |
| 30 | final VoidCallback onLeadingPressed; |
| 31 | final VoidCallback onTrailingPressed; |
| 32 | final Widget? leadingIcon; |
| 33 | final EdgeInsets? padding; |
| 34 | final Widget? trailingIcon; |
| 35 | final Widget? leadingWidget; |
| 36 | final Widget? trailingWidget; |
| 37 | |
| 38 | /// Accessible name for the leading chrome button. Required (and must be |
| 39 | /// non-empty) whenever a [leadingIcon] is supplied, because the icon alone |
| 40 | /// does not say whether it closes the modal or goes back. Must be localized |
| 41 | /// by the caller. |
| 42 | final String? leadingSemanticLabel; |
| 43 | |
| 44 | /// Accessible name for the trailing chrome button. Required (and must be |
| 45 | /// non-empty) whenever a [trailingIcon] is supplied. Must be localized by |
| 46 | /// the caller. |
| 47 | final String? trailingSemanticLabel; |
| 48 | |
| 49 | static const buttonSize = 36.0; |
| 50 | |
| 51 | @override |
| 52 | Widget build(BuildContext context) { |
| 53 | return Padding( |
| 54 | padding: padding ?? EdgeInsets.all(18), |
| 55 | child: Stack( |
| 56 | alignment: Alignment.topCenter, |
| 57 | children: [ |
| 58 | Positioned( |
| 59 | top: 6, |
| 60 | child: Row( |
| 61 | mainAxisSize: MainAxisSize.max, |
| 62 | mainAxisAlignment: MainAxisAlignment.center, |
| 63 | spacing: 4, |
| 64 | children: [ |
| 65 | AnimatedSwitcher( |
| 66 | duration: const Duration(milliseconds: 200), |
| 67 | child: Semantics( |
| 68 | key: ValueKey(title), |
| 69 | header: title.isNotEmpty, |
| 70 | // Android reads the heading from headingLevel since the |
| 71 | // Flutter 3.41 engine; header: alone only covers iOS. |
| 72 | headingLevel: title.isNotEmpty ? 1 : null, |
| 73 | child: Text( |
| 74 | title, |
| 75 | style: Theme.of(context).textTheme.headlineMedium, |
| 76 | ), |
| 77 | ), |
| 78 | ), |
| 79 | if (subtitle != null && subtitle!.isNotEmpty) |
| 80 | Text(subtitle!, |
| 81 | style: Theme.of(context) |
| 82 | .textTheme |
| 83 | .headlineMedium |
| 84 | ?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant)) |
| 85 | ], |
| 86 | ), |
| 87 | ), |
| 88 | Row( |
| 89 | mainAxisSize: MainAxisSize.max, |
| 90 | mainAxisAlignment: MainAxisAlignment.spaceBetween, |
| 91 | children: [ |
| 92 | if (leadingIcon != null || leadingWidget != null) |
| 93 | leadingIcon != null |
| 94 | ? ModernButton( |
| 95 | key: ValueKey(leadingIcon.hashCode), |
| 96 | size: buttonSize, |
| 97 | onPressed: onLeadingPressed, |
| 98 | icon: leadingIcon!, |
| 99 | semanticLabel: leadingSemanticLabel, |
| 100 | iconColor: Theme.of(context).colorScheme.onSurfaceVariant) |
| 101 | : leadingWidget! |
| 102 | else |
| 103 | Container(width: buttonSize), |
| 104 | if (trailingIcon != null || trailingWidget != null) |
| 105 | AnimatedSwitcher( |
| 106 | duration: const Duration(milliseconds: 200), |
| 107 | child: trailingIcon != null |
| 108 | ? ModernButton( |
| 109 | key: ValueKey(trailingIcon.hashCode), |
| 110 | size: buttonSize, |
| 111 | onPressed: onTrailingPressed, |
| 112 | icon: trailingIcon!, |
| 113 | semanticLabel: trailingSemanticLabel, |
| 114 | ) |
| 115 | : trailingWidget!, |
| 116 | ) |
| 117 | else |
| 118 | Container(width: buttonSize), |
| 119 | ], |
| 120 | ), |
| 121 | ], |
| 122 | ), |
| 123 | ); |
| 124 | } |
| 125 | } |