From 8679aeb2353933c329463808aefcf086157fce6c Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Mon, 20 Mar 2023 20:09:49 +0200 Subject: [PATCH] Fix `TimePicker` input mode width for 12-hour format (#122868) Fix `TimePicker` input mode width for 12-hour format --- .../flutter/lib/src/material/time_picker.dart | 5 +- .../test/material/time_picker_test.dart | 162 ++++++++++++++++++ 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 403a09b67a5..2ae97c93b17 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -2338,7 +2338,7 @@ class _TimePickerDialogState extends State with RestorationMix break; case TimeOfDayFormat.a_space_h_colon_mm: case TimeOfDayFormat.h_colon_mm_space_a: - timePickerWidth = _kTimePickerMinInputSize.width; + timePickerWidth = _kTimePickerMinInputSize.width - (useMaterial3 ? 32 : 0); break; } return Size(timePickerWidth, _kTimePickerMinInputSize.height); @@ -2383,7 +2383,7 @@ class _TimePickerDialogState extends State with RestorationMix break; case TimeOfDayFormat.a_space_h_colon_mm: case TimeOfDayFormat.h_colon_mm_space_a: - timePickerWidth = _kTimePickerInputSize.width; + timePickerWidth = _kTimePickerInputSize.width - (useMaterial3 ? 32 : 0); break; } timePickerSize = Size(timePickerWidth, _kTimePickerInputSize.height); @@ -2457,7 +2457,6 @@ class _TimePickerDialogState extends State with RestorationMix tapTargetSizeOffset = const Offset(0, -12); break; } - final Size dialogSize = _dialogSize(context, useMaterial3: theme.useMaterial3) + tapTargetSizeOffset; final Size minDialogSize = _minDialogSize(context, useMaterial3: theme.useMaterial3) + tapTargetSizeOffset; return Dialog( diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index c76a3823350..45d2c91ec7d 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -281,6 +281,10 @@ void main() { }); group('Dialog (${materialType.name})', () { + Material getMaterialFromDialog(WidgetTester tester) { + return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first); + } + testWidgets('Widgets have correct label capitalization', (WidgetTester tester) async { await startPicker(tester, (TimeOfDay? time) {}, materialType: materialType); expect(find.text(selectTimeString), findsOneWidget); @@ -313,6 +317,84 @@ void main() { switch (materialType) { case MaterialType.material2: + testWidgets('Dialog size - dial mode', (WidgetTester tester) async { + addTearDown(tester.view.reset); + + const Size timePickerPortraitSize = Size(310, 468); + const Size timePickerLandscapeSize = Size(524, 342); + const Size timePickerLandscapeSizeM2 = Size(508, 300); + const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8); + double width; + double height; + + // portrait + tester.view.physicalSize = const Size(800, 800.5); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate(tester, materialType: materialType); + + width = timePickerPortraitSize.width + padding.horizontal; + height = timePickerPortraitSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + // landscape + tester.view.physicalSize = const Size(800.5, 800); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + materialType: materialType, + ); + + width = timePickerLandscapeSize.width + padding.horizontal; + height = timePickerLandscapeSizeM2.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Dialog size - input mode', (WidgetTester tester) async { + const TimePickerEntryMode entryMode = TimePickerEntryMode.input; + const Size timePickerInputSize = Size(312, 216); + const Size dayPeriodPortraitSize = Size(52, 80); + const EdgeInsets padding = EdgeInsets.fromLTRB(8, 18, 8, 8); + final double height = timePickerInputSize.height + padding.vertical; + double width; + + await mediaQueryBoilerplate( + tester, + entryMode: entryMode, + materialType: materialType, + ); + + width = timePickerInputSize.width + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + entryMode: entryMode, + materialType: materialType, + ); + width = timePickerInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal + 16; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + testWidgets('respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: materialType); @@ -333,6 +415,86 @@ void main() { }); break; case MaterialType.material3: + testWidgets('Dialog size - dial mode', (WidgetTester tester) async { + addTearDown(tester.view.reset); + + const Size timePickerPortraitSize = Size(310, 468); + const Size timePickerLandscapeSize = Size(524, 342); + const EdgeInsets padding = EdgeInsets.all(24.0); + double width; + double height; + + // portrait + tester.view.physicalSize = const Size(800, 800.5); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate(tester, materialType: materialType); + + width = timePickerPortraitSize.width + padding.horizontal; + height = timePickerPortraitSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + // landscape + tester.view.physicalSize = const Size(800.5, 800); + tester.view.devicePixelRatio = 1; + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + materialType: materialType, + ); + + width = timePickerLandscapeSize.width + padding.horizontal; + height = timePickerLandscapeSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Dialog size - input mode', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + const TimePickerEntryMode entryMode = TimePickerEntryMode.input; + const double textScaleFactor = 1.0; + const Size timePickerMinInputSize = Size(312, 216); + const Size dayPeriodPortraitSize = Size(52, 80); + const EdgeInsets padding = EdgeInsets.all(24.0); + final double height = timePickerMinInputSize.height * textScaleFactor + padding.vertical; + double width; + + await mediaQueryBoilerplate( + tester, + entryMode: entryMode, + materialType: materialType, + ); + + width = timePickerMinInputSize.width - (theme.useMaterial3 ? 32 : 0) + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + + await tester.tap(find.text(okString)); // dismiss the dialog + await tester.pumpAndSettle(); + + await mediaQueryBoilerplate( + tester, + alwaysUse24HourFormat: true, + entryMode: entryMode, + materialType: materialType, + ); + + width = timePickerMinInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + testWidgets('respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: materialType);