Skip to content

Commit 58da22f

Browse files
committed
feat(BlurredDialog): unify all dialogs as a single shared widget
1 parent 9706f9e commit 58da22f

10 files changed

Lines changed: 213 additions & 172 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import 'package:bb_mobile/core/themes/app_theme.dart';
2+
import 'package:flutter/material.dart';
3+
4+
/// A centered dialog following the same API pattern as [BlurredBottomSheet].
5+
///
6+
/// When the built widget is an [AlertDialog] or [SimpleDialog], it is rendered
7+
/// directly (they already provide their own chrome). Otherwise the widget
8+
/// is wrapped in a themed [Dialog] shell.
9+
class BlurredDialog extends StatelessWidget {
10+
const BlurredDialog({super.key, required this.child});
11+
12+
final Widget child;
13+
14+
/// Show a centered dialog with app-consistent styling.
15+
///
16+
/// [builder] receives the dialog's own [BuildContext], which must be used
17+
/// for `Navigator.of(ctx).pop()` and `ScaffoldMessenger` lookups.
18+
static Future<T?> show<T>({
19+
required BuildContext context,
20+
required WidgetBuilder builder,
21+
bool isDismissible = true,
22+
}) {
23+
return showDialog<T>(
24+
context: context,
25+
barrierDismissible: isDismissible,
26+
barrierColor: context.appColors.surface.withAlpha(100),
27+
builder: (dialogContext) => BlurredDialog(child: builder(dialogContext)),
28+
);
29+
}
30+
31+
@override
32+
Widget build(BuildContext context) {
33+
if (child is AlertDialog || child is SimpleDialog) {
34+
return child;
35+
}
36+
return Dialog(
37+
backgroundColor: context.appColors.background,
38+
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
39+
child: child,
40+
);
41+
}
42+
}

lib/core/widgets/inputs/copy_input.dart

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:bb_mobile/core/themes/app_theme.dart';
2+
import 'package:bb_mobile/core/widgets/dialog/blurred_dialog.dart';
23
import 'package:bb_mobile/core/widgets/loading/loading_line_content.dart';
34
import 'package:bb_mobile/core/widgets/snackbar_utils.dart';
45
import 'package:flutter/material.dart';
@@ -101,53 +102,52 @@ class CopyInput extends StatelessWidget {
101102

102103
void _onShowValueModal(BuildContext context, {required bool canCopy}) {
103104
final theme = context.theme;
104-
showDialog(
105+
BlurredDialog.show(
105106
context: context,
106-
builder:
107-
(context) => AlertDialog(
108-
backgroundColor: context.appColors.surface,
109-
title:
110-
modalTitle != null
111-
? Text(
112-
modalTitle!,
113-
style: theme.textTheme.headlineMedium?.copyWith(
114-
fontSize: 20,
115-
fontWeight: .w700,
116-
),
117-
textAlign: .center,
118-
)
119-
: null,
107+
builder: (dialogContext) => AlertDialog(
108+
backgroundColor: context.appColors.surface,
109+
title:
110+
modalTitle != null
111+
? Text(
112+
modalTitle!,
113+
style: theme.textTheme.headlineMedium?.copyWith(
114+
fontSize: 20,
115+
fontWeight: .w700,
116+
),
117+
textAlign: .center,
118+
)
119+
: null,
120120

121-
content: SingleChildScrollView(
122-
child: SelectableText(
123-
modalContent ?? text,
124-
style: theme.textTheme.bodyLarge?.copyWith(fontSize: 18),
121+
content: SingleChildScrollView(
122+
child: SelectableText(
123+
modalContent ?? text,
124+
style: theme.textTheme.bodyLarge?.copyWith(fontSize: 18),
125+
),
126+
),
127+
actions: [
128+
if (canCopy)
129+
TextButton(
130+
style: TextButton.styleFrom(
131+
foregroundColor: context.appColors.secondary,
132+
textStyle: theme.textTheme.bodyLarge,
125133
),
134+
onPressed: () {
135+
Clipboard.setData(
136+
ClipboardData(text: clipboardText ?? text),
137+
);
138+
},
139+
child: Text('Copy', style: theme.textTheme.bodyLarge),
126140
),
127-
actions: [
128-
if (canCopy)
129-
TextButton(
130-
style: TextButton.styleFrom(
131-
foregroundColor: context.appColors.secondary,
132-
textStyle: theme.textTheme.bodyLarge,
133-
),
134-
onPressed: () {
135-
Clipboard.setData(
136-
ClipboardData(text: clipboardText ?? text),
137-
);
138-
},
139-
child: Text('Copy', style: theme.textTheme.bodyLarge),
140-
),
141-
TextButton(
142-
style: TextButton.styleFrom(
143-
foregroundColor: context.appColors.primary,
144-
textStyle: theme.textTheme.bodyLarge,
145-
),
146-
onPressed: () => Navigator.of(context).pop(),
147-
child: Text('Close', style: theme.textTheme.bodyLarge),
148-
),
149-
],
141+
TextButton(
142+
style: TextButton.styleFrom(
143+
foregroundColor: context.appColors.primary,
144+
textStyle: theme.textTheme.bodyLarge,
145+
),
146+
onPressed: () => Navigator.of(dialogContext).pop(),
147+
child: Text('Close', style: theme.textTheme.bodyLarge),
150148
),
149+
],
150+
),
151151
);
152152
}
153153
}

lib/features/all_seed_view/ui/all_seed_view_screen.dart

Lines changed: 69 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:bb_mobile/core/mixins/privacy_screen.dart';
22
import 'package:bb_mobile/core/seed/domain/entity/seed.dart';
33
import 'package:bb_mobile/core/themes/app_theme.dart';
4+
import 'package:bb_mobile/core/widgets/dialog/blurred_dialog.dart';
45
import 'package:bb_mobile/core/utils/build_context_x.dart';
56
import 'package:bb_mobile/core/widgets/buttons/button.dart';
67
import 'package:bb_mobile/core/widgets/loading/fading_linear_progress.dart';
@@ -160,108 +161,104 @@ class AllSeedViewScreen extends StatelessWidget with PrivacyScreen {
160161
}
161162

162163
Future<void> _showWarningDialog(BuildContext context) {
163-
return showDialog<void>(
164+
return BlurredDialog.show<void>(
164165
context: context,
165-
barrierDismissible: false,
166-
builder: (BuildContext dialogContext) {
167-
return AlertDialog(
168-
backgroundColor: context.appColors.surface,
169-
title: Text(
170-
context.loc.allSeedViewSecurityWarningTitle,
171-
style: context.font.headlineSmall?.copyWith(
166+
isDismissible: false,
167+
builder: (dialogContext) => AlertDialog(
168+
backgroundColor: context.appColors.surface,
169+
title: Text(
170+
context.loc.allSeedViewSecurityWarningTitle,
171+
style: context.font.headlineSmall?.copyWith(
172+
color: context.appColors.onSurface,
173+
),
174+
),
175+
content: SingleChildScrollView(
176+
child: Text(
177+
context.loc.allSeedViewSecurityWarningMessage,
178+
style: context.font.bodyMedium?.copyWith(
172179
color: context.appColors.onSurface,
173180
),
174181
),
175-
content: SingleChildScrollView(
182+
),
183+
actions: [
184+
TextButton(
185+
onPressed: () => Navigator.of(dialogContext).pop(),
176186
child: Text(
177-
context.loc.allSeedViewSecurityWarningMessage,
187+
context.loc.cancel,
178188
style: context.font.bodyMedium?.copyWith(
179189
color: context.appColors.onSurface,
180190
),
181191
),
182192
),
183-
actions: [
184-
TextButton(
185-
onPressed: () => Navigator.of(dialogContext).pop(),
186-
child: Text(
187-
context.loc.cancel,
188-
style: context.font.bodyMedium?.copyWith(
189-
color: context.appColors.onSurface,
190-
),
191-
),
192-
),
193-
TextButton(
194-
onPressed: () {
195-
Navigator.of(dialogContext).pop();
196-
context.read<AllSeedViewCubit>().showSeeds();
197-
},
198-
child: Text(
199-
context.loc.allSeedViewIUnderstandButton,
200-
style: context.font.bodyMedium?.copyWith(
201-
color: context.appColors.primary,
202-
fontWeight: .bold,
203-
),
193+
TextButton(
194+
onPressed: () {
195+
Navigator.of(dialogContext).pop();
196+
context.read<AllSeedViewCubit>().showSeeds();
197+
},
198+
child: Text(
199+
context.loc.allSeedViewIUnderstandButton,
200+
style: context.font.bodyMedium?.copyWith(
201+
color: context.appColors.primary,
202+
fontWeight: .bold,
204203
),
205204
),
206-
],
207-
);
208-
},
205+
),
206+
],
207+
),
209208
);
210209
}
211210

212211
Future<void> _showDeleteWarningDialog(
213212
BuildContext context,
214213
MnemonicSeed seed,
215214
) {
216-
return showDialog<void>(
215+
return BlurredDialog.show<void>(
217216
context: context,
218-
barrierDismissible: false,
219-
builder: (BuildContext dialogContext) {
220-
return AlertDialog(
221-
backgroundColor: context.appColors.surface,
222-
title: Text(
223-
context.loc.allSeedViewDeleteWarningTitle,
224-
style: context.font.headlineSmall?.copyWith(
225-
color: context.appColors.error,
226-
fontWeight: .bold,
217+
isDismissible: false,
218+
builder: (dialogContext) => AlertDialog(
219+
backgroundColor: context.appColors.surface,
220+
title: Text(
221+
context.loc.allSeedViewDeleteWarningTitle,
222+
style: context.font.headlineSmall?.copyWith(
223+
color: context.appColors.error,
224+
fontWeight: .bold,
225+
),
226+
),
227+
content: SingleChildScrollView(
228+
child: Text(
229+
context.loc.allSeedViewDeleteWarningMessage,
230+
style: context.font.bodyMedium?.copyWith(
231+
color: context.appColors.onSurface,
227232
),
228233
),
229-
content: SingleChildScrollView(
234+
),
235+
actions: [
236+
TextButton(
237+
onPressed: () => Navigator.of(dialogContext).pop(),
230238
child: Text(
231-
context.loc.allSeedViewDeleteWarningMessage,
239+
context.loc.cancel,
232240
style: context.font.bodyMedium?.copyWith(
233241
color: context.appColors.onSurface,
234242
),
235243
),
236244
),
237-
actions: [
238-
TextButton(
239-
onPressed: () => Navigator.of(dialogContext).pop(),
240-
child: Text(
241-
context.loc.cancel,
242-
style: context.font.bodyMedium?.copyWith(
243-
color: context.appColors.onSurface,
244-
),
245-
),
246-
),
247-
TextButton(
248-
onPressed: () {
249-
Navigator.of(dialogContext).pop();
250-
context.read<AllSeedViewCubit>().deleteSeed(
251-
seed.masterFingerprint,
252-
);
253-
},
254-
child: Text(
255-
context.loc.delete,
256-
style: context.font.bodyMedium?.copyWith(
257-
color: context.appColors.error,
258-
fontWeight: .bold,
259-
),
245+
TextButton(
246+
onPressed: () {
247+
Navigator.of(dialogContext).pop();
248+
context.read<AllSeedViewCubit>().deleteSeed(
249+
seed.masterFingerprint,
250+
);
251+
},
252+
child: Text(
253+
context.loc.delete,
254+
style: context.font.bodyMedium?.copyWith(
255+
color: context.appColors.error,
256+
fontWeight: .bold,
260257
),
261258
),
262-
],
263-
);
264-
},
259+
),
260+
],
261+
),
265262
);
266263
}
267264

lib/features/electrum_settings/frameworks/ui/widgets/delete_custom_server_dialog.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:bb_mobile/core/themes/app_theme.dart';
22
import 'package:bb_mobile/core/utils/build_context_x.dart';
33
import 'package:bb_mobile/core/widgets/buttons/button.dart';
4+
import 'package:bb_mobile/core/widgets/dialog/blurred_dialog.dart';
45
import 'package:flutter/material.dart';
56
import 'package:gap/gap.dart';
67

@@ -10,10 +11,9 @@ class DeleteCustomServerDialog {
1011
String serverUrl,
1112
bool isLastCustomServer,
1213
) {
13-
return showDialog<bool>(
14+
return BlurredDialog.show<bool>(
1415
context: context,
15-
builder:
16-
(BuildContext dialogContext) => AlertDialog(
16+
builder: (dialogContext) => AlertDialog(
1717
backgroundColor: context.appColors.surfaceContainer,
1818
title: Text(context.loc.electrumDeleteServerTitle),
1919
content: Column(

lib/features/exchange/ui/screens/exchange_auth_screen.dart

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:convert';
22
import 'dart:io';
33

44
import 'package:bb_mobile/core/settings/domain/settings_entity.dart';
5+
import 'package:bb_mobile/core/widgets/dialog/blurred_dialog.dart';
56
import 'package:bb_mobile/core/utils/build_context_x.dart';
67
import 'package:bb_mobile/core/utils/constants.dart';
78
import 'package:bb_mobile/core/utils/logger.dart';
@@ -267,21 +268,20 @@ class _ExchangeAuthScreenState extends State<ExchangeAuthScreen> {
267268
await _controller.reload();
268269

269270
if (!mounted) return;
270-
await showDialog(
271+
await BlurredDialog.show(
271272
context: context,
272-
builder:
273-
(context) => AlertDialog(
274-
title: Text(context.loc.exchangeAuthLoginFailedTitle),
275-
content: Text(
276-
context.loc.exchangeAuthLoginFailedMessage,
277-
),
278-
actions: [
279-
TextButton(
280-
onPressed: () => Navigator.of(context).pop(),
281-
child: Text(context.loc.exchangeAuthLoginFailedOkButton),
282-
),
283-
],
273+
builder: (dialogContext) => AlertDialog(
274+
title: Text(context.loc.exchangeAuthLoginFailedTitle),
275+
content: Text(
276+
context.loc.exchangeAuthLoginFailedMessage,
277+
),
278+
actions: [
279+
TextButton(
280+
onPressed: () => Navigator.of(dialogContext).pop(),
281+
child: Text(context.loc.exchangeAuthLoginFailedOkButton),
284282
),
283+
],
284+
),
285285
);
286286
}
287287

0 commit comments

Comments
 (0)