Prevent underlying page from stealing focus from ResponsiveDialog.

This commit is contained in:
Dain Nilsson 2023-06-19 14:04:58 +02:00
parent 7f1963d310
commit e42f7e4e67
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
2 changed files with 82 additions and 70 deletions

View File

@ -32,17 +32,16 @@ Future<T?> showBlurDialog<T>({
required BuildContext context,
required Widget Function(BuildContext) builder,
RouteSettings? routeSettings,
}) async {
const transitionDelay = Duration(milliseconds: 150);
final result = await showGeneralDialog<T>(
}) async =>
await showGeneralDialog<T>(
context: context,
barrierDismissible: true,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
pageBuilder: (ctx, anim1, anim2) => builder(ctx),
transitionDuration: transitionDelay,
transitionDuration: const Duration(milliseconds: 150),
transitionBuilder: (ctx, anim1, anim2, child) => BackdropFilter(
filter:
ImageFilter.blur(sigmaX: 20 * anim1.value, sigmaY: 20 * anim1.value),
filter: ImageFilter.blur(
sigmaX: 20 * anim1.value, sigmaY: 20 * anim1.value),
child: FadeTransition(
opacity: anim1,
child: child,
@ -50,9 +49,3 @@ Future<T?> showBlurDialog<T>({
),
routeSettings: routeSettings,
);
// Make sure we wait for the dialog to fade out before returning the result.
// This is needed for subsequent dialogs with autofocus.
await Future.delayed(transitionDelay);
return result;
}

View File

@ -39,14 +39,15 @@ class ResponsiveDialog extends StatefulWidget {
class _ResponsiveDialogState extends State<ResponsiveDialog> {
final Key _childKey = GlobalKey();
final _focus = FocusScopeNode();
@override
Widget build(BuildContext context) =>
LayoutBuilder(builder: ((context, constraints) {
final l10n = AppLocalizations.of(context)!;
if (constraints.maxWidth < 540) {
// Fullscreen
return Scaffold(
void dispose() {
super.dispose();
_focus.dispose();
}
Widget _buildFullscreen(BuildContext context) => Scaffold(
appBar: AppBar(
title: widget.title,
actions: widget.actions,
@ -60,12 +61,13 @@ class _ResponsiveDialogState extends State<ResponsiveDialog> {
: null),
),
body: SingleChildScrollView(
child: SafeArea(
child: Container(key: _childKey, child: widget.child)),
child:
SafeArea(child: Container(key: _childKey, child: widget.child)),
),
);
} else {
// Dialog
Widget _buildDialog(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final cancelText = widget.onCancel == null && widget.actions.isEmpty
? l10n.s_close
: l10n.s_cancel;
@ -90,5 +92,22 @@ class _ResponsiveDialogState extends State<ResponsiveDialog> {
],
);
}
@override
Widget build(BuildContext context) =>
LayoutBuilder(builder: ((context, constraints) {
// This keeps the focus in the dialog, even if the underlying page changes.
return FocusScope(
node: _focus,
autofocus: true,
onFocusChange: (focused) {
if (!focused) {
_focus.requestFocus();
}
},
child: constraints.maxWidth < 540
? _buildFullscreen(context)
: _buildDialog(context),
);
}));
}