Skip to content

Commit e630dea

Browse files
Panteclaude
andcommitted
Add FDialog.resizeToAvoidInsets opt-out for view inset padding
Closes #1004. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ca02987 commit e630dea

3 files changed

Lines changed: 59 additions & 1 deletion

File tree

forui/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
* Add `ThemeExtension` support via `FColors(extensions: ...)`, `FColors.extension<T>()`, and `FColors.extensions`.
99

1010

11+
### `FDialog`
12+
* Add `FDialog.resizeToAvoidInsets` to opt out of view insets padding.
13+
14+
1115
### `FStyle` & `FThemeData`
1216
* Add `FThemeData.hapticFeedback`.
1317

forui/lib/src/widgets/dialog/dialog.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ class FDialog extends StatefulWidget {
278278
/// The dialog's box constraints. Defaults to `BoxConstraints(minWidth: 280, maxWidth: 560)`.
279279
final BoxConstraints constraints;
280280

281+
/// Whether the dialog should avoid the system's view insets, typically the keyboard. Defaults to true.
282+
///
283+
/// Set this to false to avoid the dialog from becoming overly compressed on web & embedded platforms where the view
284+
/// insets comes from the surrounding host/browser environment.
285+
final bool resizeToAvoidInsets;
286+
281287
/// The builder for the dialog's content.
282288
final Widget Function(BuildContext context, FDialogStyle style) builder;
283289

@@ -322,6 +328,7 @@ class FDialog extends StatefulWidget {
322328
this.animation,
323329
this.semanticsLabel,
324330
this.constraints = const BoxConstraints(minWidth: 280, maxWidth: 560),
331+
this.resizeToAvoidInsets = true,
325332
Widget? image,
326333
Widget? title,
327334
Widget? body,
@@ -359,6 +366,7 @@ class FDialog extends StatefulWidget {
359366
this.animation,
360367
this.semanticsLabel,
361368
this.constraints = const BoxConstraints(minWidth: 280, maxWidth: 560),
369+
this.resizeToAvoidInsets = true,
362370
Widget? image,
363371
Widget? title,
364372
Widget? body,
@@ -391,6 +399,7 @@ class FDialog extends StatefulWidget {
391399
this.animation,
392400
this.semanticsLabel,
393401
this.constraints = const BoxConstraints(minWidth: 280, maxWidth: 560),
402+
this.resizeToAvoidInsets = true,
394403
super.key,
395404
});
396405

@@ -405,6 +414,7 @@ class FDialog extends StatefulWidget {
405414
..add(DiagnosticsProperty('animation', animation))
406415
..add(StringProperty('semanticsLabel', semanticsLabel))
407416
..add(DiagnosticsProperty('constraints', constraints))
417+
..add(FlagProperty('resizeToAvoidInsets', value: resizeToAvoidInsets, ifFalse: 'do not resize for view insets'))
408418
..add(ObjectFlagProperty.has('builder', builder));
409419
}
410420
}
@@ -490,7 +500,9 @@ class _FDialogState extends State<FDialog> {
490500
}
491501

492502
return AnimatedPadding(
493-
padding: MediaQuery.viewInsetsOf(context) + style.insetPadding.resolve(direction),
503+
padding:
504+
(widget.resizeToAvoidInsets ? MediaQuery.viewInsetsOf(context) : EdgeInsets.zero) +
505+
style.insetPadding.resolve(direction),
494506
duration: style.motion.insetDuration,
495507
curve: style.motion.insetCurve,
496508
child: MediaQuery.removeViewInsets(

forui/test/src/widgets/dialog/dialog_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,47 @@ void main() {
140140

141141
expect(tester.takeException(), null);
142142
});
143+
144+
group('resizeToAvoidInsets', () {
145+
// Default style.insetPadding is EdgeInsets.symmetric(horizontal: 40, vertical: 24).
146+
const styleBottomPadding = 24.0;
147+
const viewInsetsBottom = 300.0;
148+
149+
for (final (resize, expectedBottom) in [
150+
(true, viewInsetsBottom + styleBottomPadding),
151+
(false, styleBottomPadding),
152+
]) {
153+
testWidgets('resize=$resize -> bottom padding = $expectedBottom', (tester) async {
154+
await tester.pumpWidget(
155+
TestScaffold(
156+
child: MediaQuery(
157+
data: const MediaQueryData(viewInsets: EdgeInsets.only(bottom: viewInsetsBottom)),
158+
child: FDialog(
159+
resizeToAvoidInsets: resize,
160+
title: const Text('Title'),
161+
body: const Text('Body'),
162+
actions: [FButton(onPress: () {}, child: const Text('OK'))],
163+
),
164+
),
165+
),
166+
);
167+
await tester.pumpAndSettle();
168+
169+
final padding = tester
170+
.widget<AnimatedPadding>(find.byType(AnimatedPadding).first)
171+
.padding
172+
.resolve(TextDirection.ltr);
173+
expect(padding.bottom, expectedBottom);
174+
});
175+
}
176+
177+
testWidgets('default is true across all constructors', (tester) async {
178+
expect(FDialog(actions: const [], title: const Text('x')).resizeToAvoidInsets, true);
179+
expect(FDialog.adaptive(actions: const []).resizeToAvoidInsets, true);
180+
expect(const FDialog.raw(builder: _emptyBuilder).resizeToAvoidInsets, true);
181+
});
182+
});
143183
});
144184
}
185+
186+
Widget _emptyBuilder(BuildContext _, FDialogStyle _) => const SizedBox.shrink();

0 commit comments

Comments
 (0)