From 28b5cc3825922222afceaaa9a5eadffc5c280664 Mon Sep 17 00:00:00 2001 From: "Edman P. Anjos" Date: Tue, 5 Nov 2019 11:50:30 +0100 Subject: [PATCH] Pad CupertinoAlertDialog with MediaQuery viewInsets (#42967) Fixes #42049. --- .../flutter/lib/src/cupertino/dialog.dart | 53 +++++++++++++------ packages/flutter/lib/src/material/dialog.dart | 4 ++ .../flutter/test/cupertino/dialog_test.dart | 40 ++++++++++++-- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/dialog.dart b/packages/flutter/lib/src/cupertino/dialog.dart index 98bc2e20be..0a85eeee4a 100644 --- a/packages/flutter/lib/src/cupertino/dialog.dart +++ b/packages/flutter/lib/src/cupertino/dialog.dart @@ -129,6 +129,8 @@ class CupertinoAlertDialog extends StatelessWidget { this.actions = const [], this.scrollController, this.actionScrollController, + this.insetAnimationDuration = const Duration(milliseconds: 100), + this.insetAnimationCurve = Curves.decelerate, }) : assert(actions != null), super(key: key); @@ -173,6 +175,12 @@ class CupertinoAlertDialog extends StatelessWidget { /// section when it is long. final ScrollController actionScrollController; + /// {@macro flutter.material.dialog.insetAnimationDuration} + final Duration insetAnimationDuration; + + /// {@macro flutter.material.dialog.insetAnimationCurve} + final Curve insetAnimationCurve; + Widget _buildContent(BuildContext context) { final List children = [ if (title != null || content != null) @@ -224,22 +232,35 @@ class CupertinoAlertDialog extends StatelessWidget { ), child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - return Center( - child: Container( - margin: const EdgeInsets.symmetric(vertical: _kEdgePadding), - width: isInAccessibilityMode - ? _kAccessibilityCupertinoDialogWidth - : _kCupertinoDialogWidth, - child: CupertinoPopupSurface( - isSurfacePainted: false, - child: Semantics( - namesRoute: true, - scopesRoute: true, - explicitChildNodes: true, - label: localizations.alertDialogLabel, - child: _CupertinoDialogRenderWidget( - contentSection: _buildContent(context), - actionsSection: _buildActions(), + return AnimatedPadding( + padding: MediaQuery.of(context).viewInsets + + const EdgeInsets.symmetric(horizontal: 40.0, vertical: 24.0), + duration: insetAnimationDuration, + curve: insetAnimationCurve, + child: MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: Container( + margin: const EdgeInsets.symmetric(vertical: _kEdgePadding), + width: isInAccessibilityMode + ? _kAccessibilityCupertinoDialogWidth + : _kCupertinoDialogWidth, + child: CupertinoPopupSurface( + isSurfacePainted: false, + child: Semantics( + namesRoute: true, + scopesRoute: true, + explicitChildNodes: true, + label: localizations.alertDialogLabel, + child: _CupertinoDialogRenderWidget( + contentSection: _buildContent(context), + actionsSection: _buildActions(), + ), + ), ), ), ), diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 493794431d..ad8fa247b8 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -65,16 +65,20 @@ class Dialog extends StatelessWidget { /// {@macro flutter.material.material.elevation} final double elevation; + /// {@template flutter.material.dialog.insetAnimationDuration} /// The duration of the animation to show when the system keyboard intrudes /// into the space that the dialog is placed in. /// /// Defaults to 100 milliseconds. + /// {@endtemplate} final Duration insetAnimationDuration; + /// {@template flutter.material.dialog.insetAnimationCurve} /// The curve to use for the animation shown when the system keyboard intrudes /// into the space that the dialog is placed in. /// /// Defaults to [Curves.decelerate]. + /// {@endtemplate} final Curve insetAnimationCurve; /// {@template flutter.material.dialog.shape} diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart index 002771cbb1..366c383eae 100644 --- a/packages/flutter/test/cupertino/dialog_test.dart +++ b/packages/flutter/test/cupertino/dialog_test.dart @@ -251,7 +251,7 @@ void main() { tester.getSize( find.byType(ClipRRect) ), - equals(const Size(310.0, 560.0)), + equals(const Size(310.0, 560.0 - 24.0 * 2)), ); // Check sizes/locations of the text. The text is large so these 2 buttons are stacked. @@ -259,7 +259,7 @@ void main() { // regular font. However, when using the test font, "Cancel" becomes 2 lines which // is why the height we're verifying for "Cancel" is larger than "OK". expect(tester.getSize(find.text('The Title')), equals(const Size(270.0, 162.0))); - expect(tester.getTopLeft(find.text('The Title')), equals(const Offset(265.0, 80.0))); + expect(tester.getTopLeft(find.text('The Title')), equals(const Offset(265.0, 80.0 + 24.0))); expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'Cancel')), equals(const Size(310.0, 148.0))); expect(tester.getSize(find.widgetWithText(CupertinoDialogAction, 'OK')), equals(const Size(310.0, 98.0))); }); @@ -300,10 +300,12 @@ void main() { await tester.pump(); const double topAndBottomMargin = 40.0; + const double topAndBottomPadding = 24.0 * 2; + const double leftAndRightPadding = 40.0 * 2; final Finder modalFinder = find.byType(ClipRRect); expect( tester.getSize(modalFinder), - equals(const Size(200.0, 100.0 - topAndBottomMargin)), + equals(const Size(200.0 - leftAndRightPadding, 100.0 - topAndBottomMargin - topAndBottomPadding)), ); }); @@ -645,7 +647,7 @@ void main() { // should be in a scrollable area equal to half the dialog height. expect( actionsSectionBox.size.height, - 280.0, + 280.0 - 24.0, ); }); @@ -1053,6 +1055,36 @@ void main() { expect(find.byKey(const Key('option_2')), findsOneWidget); expect(find.byKey(const Key('option_3')), findsNothing); }); + + testWidgets('Dialog widget insets by MediaQuery viewInsets', (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: MediaQuery( + data: MediaQueryData(viewInsets: EdgeInsets.zero), + child: CupertinoAlertDialog(content: Placeholder(fallbackHeight: 200.0)), + ), + ), + ); + + final Rect placeholderRectWithoutInsets = tester.getRect(find.byType(Placeholder)); + + await tester.pumpWidget( + const MaterialApp( + home: MediaQuery( + data: MediaQueryData(viewInsets: EdgeInsets.fromLTRB(40.0, 30.0, 20.0, 10.0)), + child: CupertinoAlertDialog(content: Placeholder(fallbackHeight: 200.0)), + ), + ), + ); + + // no change yet because padding is animated + expect(tester.getRect(find.byType(Placeholder)), placeholderRectWithoutInsets); + + await tester.pump(const Duration(seconds: 1)); + + // once animation settles the dialog is padded by the new viewInsets + expect(tester.getRect(find.byType(Placeholder)), placeholderRectWithoutInsets.translate(10, 10)); + }); } RenderBox findActionButtonRenderBoxByTitle(WidgetTester tester, String title) {