improve dialog box design (#3145)

malik1004x committed Apr 2, 2026 at 13:04 UTC ac410f40c92fb7a3c058eefe30fe5d14b974513e
4 files changed +169 -127
lib/src/screens/backup/backup_page.dart
+3
@@ -3,6 +3,7 @@ import 'dart:ui';
3 import 'package:cake_wallet/core/execution_state.dart';
4 import 'package:cake_wallet/src/screens/base_page.dart';
5 import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
6 +import 'package:cake_wallet/src/widgets/base_alert_dialog.dart';
7 import 'package:cake_wallet/src/widgets/primary_button.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
9 import 'package:cake_wallet/routes.dart';
@@ -116,6 +117,8 @@ class BackupPage extends BasePage {
117 alertContent: S.of(context).save_backup_password,
118 rightButtonText: S.of(context).seed_alert_yes,
119 leftButtonText: S.of(context).seed_alert_back,
120 + leftAlertButtonStyle: AlertButtonStyle.error(context),
121 + rightAlertButtonStyle: AlertButtonStyle.secondary(context),
122 actionRightButton: () async {
123 Navigator.of(dialogContext).pop();
124 final backupFuture = backupViewModelBase.exportBackup();
lib/src/widgets/alert_with_one_action.dart
+35 -28
@@ -39,32 +39,39 @@ class AlertWithOneAction extends BaseAlertDialog {
39 String? get headerText => headerTitleText;
40
41 @override
42 - Widget actionButtons(BuildContext context) {
43 - return Container(
44 - width: 300,
45 - height: 52,
46 - padding: EdgeInsets.only(left: 12, right: 12),
47 - color: Theme.of(context).colorScheme.surface,
48 - child: ButtonTheme(
49 - minWidth: double.infinity,
50 - child: TextButton(
51 - key: buttonKey,
52 - onPressed: buttonAction,
53 - // FIX-ME: Style
54 - //highlightColor: Colors.transparent,
55 - //splashColor: Colors.transparent,
56 - child: Text(
57 - buttonText,
58 - textAlign: TextAlign.center,
59 - style: Theme.of(context).textTheme.bodyMedium!.copyWith(
60 - fontSize: 15,
61 - fontWeight: FontWeight.w600,
62 - color: Theme.of(context).colorScheme.primary,
63 - decoration: TextDecoration.none,
64 - ),
65 - ),
66 - ),
67 - ),
68 - );
69 - }
42 + VoidCallback get actionRight => buttonAction;
43 +
44 + @override
45 + bool get showLeftButton => false;
46 +
47 + @override
48 + String get rightActionButtonText => buttonText;
49 +
50 + // @override
51 + // Widget actionButtons(BuildContext context) {
52 + // return Container(
53 + // padding: EdgeInsets.only(left: 12, right: 12),
54 + // color: Theme.of(context).colorScheme.surface,
55 + // child: ButtonTheme(
56 + // minWidth: double.infinity,
57 + // child: TextButton(
58 + // key: buttonKey,
59 + // onPressed: buttonAction,
60 + // // FIX-ME: Style
61 + // //highlightColor: Colors.transparent,
62 + // //splashColor: Colors.transparent,
63 + // child: Text(
64 + // buttonText,
65 + // textAlign: TextAlign.center,
66 + // style: Theme.of(context).textTheme.bodyMedium!.copyWith(
67 + // fontSize: 15,
68 + // fontWeight: FontWeight.w600,
69 + // color: Theme.of(context).colorScheme.primary,
70 + // decoration: TextDecoration.none,
71 + // ),
72 + // ),
73 + // ),
74 + // ),
75 + // );
76 + // }
77 }
lib/src/widgets/alert_with_two_actions.dart
+6
@@ -14,6 +14,8 @@ class AlertWithTwoActions extends BaseAlertDialog {
14 this.isDividerExist = false,
15 // this.leftActionColor,
16 // this.rightActionColor,
17 + this.leftAlertButtonStyle,
18 + this.rightAlertButtonStyle,
19 this.alertRightActionButtonKey,
20 this.alertLeftActionButtonKey,
21 this.alertDialogKey,
@@ -29,6 +31,10 @@ class AlertWithTwoActions extends BaseAlertDialog {
31 final bool alertBarrierDismissible;
32 // final Color leftActionColor;
33 // final Color rightActionColor;
34 + @override
35 + final AlertButtonStyle? leftAlertButtonStyle;
36 + @override
37 + final AlertButtonStyle? rightAlertButtonStyle;
38 final bool isDividerExist;
39 final Key? alertRightActionButtonKey;
40 final Key? alertLeftActionButtonKey;
lib/src/widgets/base_alert_dialog.dart
+125 -99
@@ -1,14 +1,45 @@
1 import 'dart:ui';
2
3 +import 'package:auto_size_text/auto_size_text.dart';
4 import 'package:cake_wallet/src/widgets/section_divider.dart';
5 import 'package:flutter/material.dart';
6
7 +
8 +class AlertButtonStyle {
9 + final Color backgroundColor;
10 + final Color textColor;
11 + final FontWeight fontWeight;
12 +
13 + const AlertButtonStyle({
14 + required this.backgroundColor,
15 + required this.textColor,
16 + this.fontWeight = FontWeight.w400
17 + });
18 +
19 + factory AlertButtonStyle.primary(BuildContext context) => AlertButtonStyle(
20 + backgroundColor: Theme.of(context).colorScheme.primary,
21 + textColor: Theme.of(context).colorScheme.onPrimary,
22 + );
23 +
24 + factory AlertButtonStyle.secondary(BuildContext context) => AlertButtonStyle(
25 + backgroundColor: Theme.of(context).colorScheme.surfaceContainer,
26 + textColor: Theme.of(context).colorScheme.primary,
27 + );
28 +
29 + factory AlertButtonStyle.error(BuildContext context) => AlertButtonStyle(
30 + backgroundColor: Theme.of(context).colorScheme.errorContainer,
31 + textColor: Theme.of(context).colorScheme.error,
32 + fontWeight: FontWeight.w500
33 + );
34 +}
35 +
36 +
37 class BaseAlertDialog extends StatelessWidget {
38 String? get headerText => '';
39
40 String? get titleText => '';
41
11 - double? get titleTextSize => 20;
42 + double? get titleTextSize => 18;
43
44 String get contentText => '';
45
@@ -28,14 +59,6 @@ class BaseAlertDialog extends StatelessWidget {
59
60 bool get barrierDismissible => true;
61
31 - Color? get leftActionButtonTextColor => null;
32 -
33 - Color? get rightActionButtonTextColor => null;
34 -
35 - Color? get leftActionButtonColor => null;
36 -
37 - Color? get rightActionButtonColor => null;
38 -
62 String? get headerImageUrl => null;
63
64 Key? leftActionButtonKey;
@@ -43,6 +66,12 @@ class BaseAlertDialog extends StatelessWidget {
66 Key? rightActionButtonKey;
67
68 Key? dialogKey;
69 +
70 + AlertButtonStyle? get leftAlertButtonStyle => null;
71 +
72 + AlertButtonStyle? get rightAlertButtonStyle => null;
73 +
74 + bool get showLeftButton => true;
75
76 Widget title(BuildContext context) {
77 return Text(
@@ -83,7 +112,7 @@ class BaseAlertDialog extends StatelessWidget {
112 contentText,
113 textAlign: TextAlign.center,
114 style: Theme.of(context).textTheme.bodyMedium?.copyWith(
86 - fontSize: 16,
115 + fontSize: 14,
116 decoration: TextDecoration.none,
117 ),
118 ),
@@ -93,59 +122,56 @@ class BaseAlertDialog extends StatelessWidget {
122 }
123
124 Widget actionButtons(BuildContext context) {
96 - return Container(
97 - height: 60,
98 - child: Row(
99 - mainAxisSize: MainAxisSize.max,
100 - crossAxisAlignment: CrossAxisAlignment.stretch,
101 - children: <Widget>[
102 - Expanded(
103 - child: TextButton(
104 - key: leftActionButtonKey,
105 - onPressed: actionLeft,
106 - style: TextButton.styleFrom(
107 - backgroundColor: leftActionButtonColor ?? Theme.of(context).colorScheme.surface,
108 - shape: const RoundedRectangleBorder(
109 - borderRadius: BorderRadius.all(Radius.zero),
125 + final rightButtonStyle = rightAlertButtonStyle ?? AlertButtonStyle.primary(context);
126 + final leftButtonStyle = leftAlertButtonStyle ?? AlertButtonStyle.secondary(context);
127 +
128 + return Row(
129 + mainAxisAlignment: MainAxisAlignment.center,
130 + mainAxisSize: MainAxisSize.max,
131 + spacing:8,
132 + children: <Widget>[
133 + if(showLeftButton)
134 + Expanded(
135 + child: GestureDetector(
136 + key: leftActionButtonKey,
137 + onTap: actionLeft,
138 + child: Container(
139 + decoration: BoxDecoration(
140 + borderRadius: BorderRadius.circular(999999),
141 + color: leftButtonStyle.backgroundColor
142 + ),
143 + child: Padding(
144 + padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8),
145 + child: AutoSizeText(
146 + maxLines:1,
147 + leftActionButtonText,
148 + textAlign: TextAlign.center,
149 + style: TextStyle(fontSize: 16, color: leftButtonStyle.textColor, fontWeight: leftButtonStyle.fontWeight)
150 ),
151 ),
112 - child: Text(
113 - leftActionButtonText,
114 - textAlign: TextAlign.center,
115 - style: Theme.of(context).textTheme.bodyMedium!.copyWith(
116 - fontSize: 15,
117 - fontWeight: FontWeight.w600,
118 - color: leftActionButtonTextColor ??
119 - Theme.of(context).colorScheme.errorContainer,
120 - decoration: TextDecoration.none,
121 - ),
122 - )),
123 - ),
124 - const VerticalSectionDivider(),
125 - Expanded(
126 - child: TextButton(
152 + )),
153 + ),
154 + Expanded(
155 + child: GestureDetector(
156 key: rightActionButtonKey,
128 - onPressed: actionRight,
129 - style: TextButton.styleFrom(
130 - backgroundColor: rightActionButtonColor ?? Theme.of(context).colorScheme.surface,
131 - shape: const RoundedRectangleBorder(
132 - borderRadius: BorderRadius.all(Radius.zero),
157 + onTap: actionRight,
158 + child: Container(
159 + decoration: BoxDecoration(
160 + borderRadius: BorderRadius.circular(999999),
161 + color: rightButtonStyle.backgroundColor
162 ),
134 - ),
135 - child: Text(
136 - rightActionButtonText,
137 - textAlign: TextAlign.center,
138 - style: Theme.of(context).textTheme.bodyMedium!.copyWith(
139 - fontSize: 15,
140 - fontWeight: FontWeight.w600,
141 - color: rightActionButtonTextColor ?? Theme.of(context).colorScheme.onSurface,
142 - decoration: TextDecoration.none,
143 - ),
144 - ),
145 - ),
146 - ),
147 - ],
148 - ),
163 + child: Padding(
164 + padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8),
165 + child: AutoSizeText(
166 + maxLines: 1,
167 + rightActionButtonText,
168 + textAlign: TextAlign.center,
169 + style: TextStyle(fontSize: 16, color: rightButtonStyle.textColor, fontWeight: rightButtonStyle.fontWeight)
170 + ),
171 + ),
172 + )),
173 + ),
174 + ],
175 );
176 }
177
@@ -178,53 +204,53 @@ class BaseAlertDialog extends StatelessWidget {
204 filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
205 child: Container(
206 decoration:
181 - BoxDecoration(color: Theme.of(context).colorScheme.surface.withOpacity(0.8)),
207 + BoxDecoration(color: Theme.of(context).colorScheme.onSurface.withAlpha(25)),
208 child: Center(
183 - child: GestureDetector(
184 - onTap: () => null,
185 - child: Container(
186 - decoration: BoxDecoration(
187 - borderRadius: BorderRadius.circular(30),
188 - color: Theme.of(context).colorScheme.surface,
189 - ),
190 - width: 300,
191 - child: Stack(
192 - clipBehavior: Clip.none,
193 - children: [
194 - if (headerImageUrl != null) headerImage(context, headerImageUrl!),
195 - Column(
196 - mainAxisSize: MainAxisSize.min,
197 - children: <Widget>[
198 - if (headerImageUrl != null) const SizedBox(height: 50),
209 + child: Padding(
210 + padding: const EdgeInsets.all(16.0),
211 + child: GestureDetector(
212 + onTap: () => null,
213 + child: Container(
214 + decoration: BoxDecoration(
215 + borderRadius: BorderRadius.circular(24),
216 + color: Theme.of(context).colorScheme.surface,
217 + ),
218 + child: Padding(
219 + padding: const EdgeInsets.all(24.0),
220 + child: Stack(
221 + clipBehavior: Clip.none,
222 + children: [
223 + if (headerImageUrl != null) headerImage(context, headerImageUrl!),
224 Column(
200 - crossAxisAlignment: CrossAxisAlignment.center,
225 + mainAxisSize: MainAxisSize.min,
226 children: <Widget>[
202 - if (headerText?.isNotEmpty ?? false) headerTitle(context),
203 - titleText != null
204 - ? Padding(
205 - padding: EdgeInsets.fromLTRB(24, 20, 24, 0),
206 - child: title(context),
207 - )
208 - : SizedBox(height: 16),
209 - isDividerExists
210 - ? Padding(
211 - padding: EdgeInsets.only(top: 16, bottom: 8),
212 - child: const HorizontalSectionDivider(),
213 - )
214 - : Offstage(),
215 - Padding(
216 - padding: EdgeInsets.fromLTRB(24, 8, 24, 32),
217 - child: content(context),
218 - )
227 + if (headerImageUrl != null) const SizedBox(height: 50),
228 + Column(
229 + crossAxisAlignment: CrossAxisAlignment.center,
230 + children: <Widget>[
231 + if (headerText?.isNotEmpty ?? false) headerTitle(context),
232 + titleText != null
233 + ? title(context)
234 + : SizedBox(height: 16),
235 + isDividerExists
236 + ? Padding(
237 + padding: EdgeInsets.only(top: 16, bottom: 8),
238 + child: const HorizontalSectionDivider(),
239 + )
240 + : Offstage(),
241 + Padding(
242 + padding: EdgeInsets.symmetric(vertical: 25),
243 + child: content(context),
244 + )
245 + ],
246 + ),
247 + // if (isBottomDividerExists) const HorizontalSectionDivider(),
248 + actionButtons(context)
249 ],
250 ),
221 - if (isBottomDividerExists) const HorizontalSectionDivider(),
222 - ClipRRect(
223 - borderRadius: BorderRadius.all(Radius.circular(30)),
224 - child: actionButtons(context))
251 ],
252 ),
227 - ],
253 + ),
254 ),
255 ),
256 ),