Skip to content

Commit 8166790

Browse files
Merge pull request #458 from QueryaHub/issue/446-app-dialog-escape
fix(ui): Escape dismisses showAppDialog (#446)
2 parents e46d527 + 07ac20e commit 8166790

2 files changed

Lines changed: 47 additions & 1 deletion

File tree

‎lib/shared/widgets/app_dialog.dart‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,18 @@ import 'package:querya_desktop/core/motion/querya_spring.dart';
1010
///
1111
/// Use instead of [showDialog] so every overlay has consistent blur.
1212
/// Enter: fade + slight slide; exit uses [QueryaMotion.exit] via reverseCurve.
13+
///
14+
/// When [barrierDismissible] is true (default), Escape and backdrop tap dismiss.
15+
/// Escape is handled by the modal route; backdrop tap by [_BlurredDialogScaffold]
16+
/// (the route barrier stays transparent under the frosted layer).
1317
Future<T?> showAppDialog<T>({
1418
required BuildContext context,
1519
required WidgetBuilder builder,
1620
bool barrierDismissible = true,
1721
}) {
1822
return showGeneralDialog<T>(
1923
context: context,
20-
barrierDismissible: false,
24+
barrierDismissible: barrierDismissible,
2125
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
2226
barrierColor: Colors.transparent,
2327
transitionDuration: context.motionDuration(QueryaMotion.standard),

‎test/shared/app_dialog_test.dart‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:ui' show ImageFilter;
22

33
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
45
import 'package:flutter_test/flutter_test.dart';
56
import 'package:querya_desktop/core/motion/querya_motion.dart';
67
import 'package:querya_desktop/core/motion/querya_motion_scope.dart';
@@ -70,6 +71,47 @@ void main() {
7071
await future;
7172
});
7273

74+
testWidgets('barrierDismissible true closes dialog on Escape', (tester) async {
75+
final ctx = await pumpHost(tester);
76+
var completed = false;
77+
78+
final future = showAppDialog<void>(
79+
context: ctx,
80+
barrierDismissible: true,
81+
builder: (c) => const AlertDialog(title: Text('Escapable')),
82+
).whenComplete(() => completed = true);
83+
84+
await tester.pumpAndSettle();
85+
expect(find.text('Escapable'), findsOneWidget);
86+
87+
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
88+
await tester.pumpAndSettle();
89+
90+
expect(find.text('Escapable'), findsNothing);
91+
expect(completed, isTrue);
92+
await future;
93+
});
94+
95+
testWidgets('barrierDismissible false ignores Escape', (tester) async {
96+
final ctx = await pumpHost(tester);
97+
98+
final future = showAppDialog<void>(
99+
context: ctx,
100+
barrierDismissible: false,
101+
builder: (c) => const AlertDialog(title: Text('No escape')),
102+
);
103+
104+
await tester.pumpAndSettle();
105+
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
106+
await tester.pumpAndSettle();
107+
108+
expect(find.text('No escape'), findsOneWidget);
109+
110+
Navigator.of(ctx, rootNavigator: true).pop();
111+
await tester.pumpAndSettle();
112+
await future;
113+
});
114+
73115
testWidgets('showAppDialog uses fade-slide (not scale) with BackdropFilter',
74116
(tester) async {
75117
final ctx = await pumpHost(tester);

0 commit comments

Comments
 (0)