diff --git a/packages/flutter/test/material/text_selection_theme_test.dart b/packages/flutter/test/material/text_selection_theme_test.dart index 42a11c12df..7c767b5db1 100644 --- a/packages/flutter/test/material/text_selection_theme_test.dart +++ b/packages/flutter/test/material/text_selection_theme_test.dart @@ -60,12 +60,11 @@ void main() { ]); }); - testWidgetsWithLeakTracking('Empty textSelectionTheme will use defaults', (WidgetTester tester) async { - final ThemeData theme = ThemeData(); - final bool material3 = theme.useMaterial3; - final Color defaultCursorColor = material3 ? theme.colorScheme.primary : const Color(0xff2196f3); - final Color defaultSelectionColor = material3 ? theme.colorScheme.primary.withOpacity(0.40) : const Color(0x662196f3); - final Color defaultSelectionHandleColor = material3 ? theme.colorScheme.primary : const Color(0xff2196f3); + testWidgetsWithLeakTracking('Material2 - Empty textSelectionTheme will use defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); + const Color defaultCursorColor = Color(0xff2196f3); + const Color defaultSelectionColor = Color(0x662196f3); + const Color defaultSelectionHandleColor = Color(0xff2196f3); EditableText.debugDeterministicCursor = true; addTearDown(() { @@ -91,6 +90,67 @@ void main() { // Test the selection handle color. await tester.pumpWidget( MaterialApp( + theme: theme, + home: Material( + child: Builder( + builder: (BuildContext context) { + return materialTextSelectionControls.buildHandle( + context, + TextSelectionHandleType.left, + 10.0, + ); + }, + ), + ), + ), + ); + await tester.pumpAndSettle(); + final RenderBox handle = tester.firstRenderObject(find.byType(CustomPaint)); + expect(handle, paints..path(color: defaultSelectionHandleColor)); + }, + // TODO(polina-c): remove after fixing + // https://github.com/flutter/flutter/issues/130469 + leakTrackingTestConfig: const LeakTrackingTestConfig( + notDisposedAllowList: { + 'ValueNotifier': 1, + 'ValueNotifier<_OverlayEntryWidgetState?>': 2, + 'ValueNotifier': 1, + }, + // TODO(polina-c): investigate notGCed, if it does not disappear after fixing notDisposed. + allowAllNotGCed: true, + )); + + testWidgetsWithLeakTracking('Material3 - Empty textSelectionTheme will use defaults', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: true); + final Color defaultCursorColor = theme.colorScheme.primary; + final Color defaultSelectionColor = theme.colorScheme.primary.withOpacity(0.40); + final Color defaultSelectionHandleColor = theme.colorScheme.primary; + + EditableText.debugDeterministicCursor = true; + addTearDown(() { + EditableText.debugDeterministicCursor = false; + }); + // Test TextField's cursor & selection color. + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Material( + child: TextField(autofocus: true), + ), + ), + ); + await tester.pump(); + await tester.pumpAndSettle(); + + final EditableTextState editableTextState = tester.firstState(find.byType(EditableText)); + final RenderEditable renderEditable = editableTextState.renderEditable; + expect(renderEditable.cursorColor, defaultCursorColor); + expect(renderEditable.selectionColor, defaultSelectionColor); + + // Test the selection handle color. + await tester.pumpWidget( + MaterialApp( + theme: theme, home: Material( child: Builder( builder: (BuildContext context) { diff --git a/packages/flutter/test/material/theme_defaults_test.dart b/packages/flutter/test/material/theme_defaults_test.dart index db8eec4b7e..4f60fc1735 100644 --- a/packages/flutter/test/material/theme_defaults_test.dart +++ b/packages/flutter/test/material/theme_defaults_test.dart @@ -14,9 +14,8 @@ void main() { const ShapeBorder defaultFABShapeM3 = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const EdgeInsets defaultFABPadding = EdgeInsets.zero; - testWidgets('theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { - final ThemeData theme = ThemeData.light(); - final bool material3 = theme.useMaterial3; + testWidgets('Material2 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( theme: theme, @@ -31,21 +30,48 @@ void main() { final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); expect(raw.enabled, true); - expect(raw.textStyle!.color, material3 ? theme.colorScheme.onPrimaryContainer : const Color(0xffffffff)); - expect(raw.fillColor, material3 ? theme.colorScheme.primaryContainer : const Color(0xff2196f3)); + expect(raw.textStyle!.color, const Color(0xffffffff)); + expect(raw.fillColor, const Color(0xff2196f3)); expect(raw.elevation, 6.0); - expect(raw.highlightElevation, material3 ? 6.0 : 12.0); + expect(raw.highlightElevation, 12.0); expect(raw.disabledElevation, 6.0); expect(raw.constraints, defaultFABConstraints); expect(raw.padding, defaultFABPadding); - expect(raw.shape, material3 ? defaultFABShapeM3 : defaultFABShape); + expect(raw.shape, defaultFABShape); expect(raw.animationDuration, defaultButtonDuration); expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); - testWidgets('theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { - final ThemeData theme = ThemeData.light(); - final bool material3 = theme.useMaterial3; + testWidgets('Material3 - theme: ThemeData.light(), enabled: true', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: Center( + child: FloatingActionButton( + onPressed: () { }, // button.enabled == true + child: const Icon(Icons.add), + ), + ), + ), + ); + + final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); + expect(raw.enabled, true); + expect(raw.textStyle!.color, theme.colorScheme.onPrimaryContainer); + expect(raw.fillColor, theme.colorScheme.primaryContainer); + expect(raw.elevation, 6.0); + expect(raw.highlightElevation, 6.0); + expect(raw.disabledElevation, 6.0); + expect(raw.constraints, defaultFABConstraints); + expect(raw.padding, defaultFABPadding); + expect(raw.shape, defaultFABShapeM3); + expect(raw.animationDuration, defaultButtonDuration); + expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); + }); + + testWidgets('Material2 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: false); await tester.pumpWidget( MaterialApp( theme: theme, @@ -60,16 +86,46 @@ void main() { final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); expect(raw.enabled, false); - expect(raw.textStyle!.color, material3 ? theme.colorScheme.onPrimaryContainer : const Color(0xffffffff)); - expect(raw.fillColor, material3 ? theme.colorScheme.primaryContainer : const Color(0xff2196f3)); + expect(raw.textStyle!.color, const Color(0xffffffff)); + expect(raw.fillColor, const Color(0xff2196f3)); // highlightColor, disabled button can't be pressed // splashColor, disabled button doesn't splash expect(raw.elevation, 6.0); - expect(raw.highlightElevation, material3 ? 6.0 : 12.0); + expect(raw.highlightElevation, 12.0); expect(raw.disabledElevation, 6.0); expect(raw.constraints, defaultFABConstraints); expect(raw.padding, defaultFABPadding); - expect(raw.shape, material3 ? defaultFABShapeM3 : defaultFABShape); + expect(raw.shape, defaultFABShape); + expect(raw.animationDuration, defaultButtonDuration); + expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); + }); + + testWidgets('Material3 - theme: ThemeData.light(), enabled: false', (WidgetTester tester) async { + final ThemeData theme = ThemeData.light(useMaterial3: true); + await tester.pumpWidget( + MaterialApp( + theme: theme, + home: const Center( + child: FloatingActionButton( + onPressed: null, // button.enabled == false + child: Icon(Icons.add), + ), + ), + ), + ); + + final RawMaterialButton raw = tester.widget(find.byType(RawMaterialButton)); + expect(raw.enabled, false); + expect(raw.textStyle!.color, theme.colorScheme.onPrimaryContainer); + expect(raw.fillColor, theme.colorScheme.primaryContainer); + // highlightColor, disabled button can't be pressed + // splashColor, disabled button doesn't splash + expect(raw.elevation, 6.0); + expect(raw.highlightElevation, 6.0); + expect(raw.disabledElevation, 6.0); + expect(raw.constraints, defaultFABConstraints); + expect(raw.padding, defaultFABPadding); + expect(raw.shape, defaultFABShapeM3); expect(raw.animationDuration, defaultButtonDuration); expect(raw.materialTapTargetSize, MaterialTapTargetSize.padded); }); diff --git a/packages/flutter/test/material/theme_test.dart b/packages/flutter/test/material/theme_test.dart index 1cbcbca300..63d133a009 100644 --- a/packages/flutter/test/material/theme_test.dart +++ b/packages/flutter/test/material/theme_test.dart @@ -96,8 +96,7 @@ void main() { expect(tester.widget(find.byType(EditableText)).cursorColor, themeCursorColor); }); - testWidgets('Fallback theme', (WidgetTester tester) async { - // For material 2 + testWidgets('Material2 - Fallback theme', (WidgetTester tester) async { late BuildContext capturedContext; await tester.pumpWidget( Theme( @@ -112,8 +111,9 @@ void main() { ); expect(Theme.of(capturedContext), equals(ThemeData.localize(ThemeData.fallback(useMaterial3: false), defaultGeometryTheme))); + }); - // For material 3 + testWidgets('Material3 - Fallback theme', (WidgetTester tester) async { late BuildContext capturedContextM3; await tester.pumpWidget( Theme( @@ -153,9 +153,12 @@ void main() { ); }); - testWidgets('ThemeData with null typography uses proper defaults', (WidgetTester tester) async { + testWidgets('Material2 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { final ThemeData m2Theme = ThemeData(useMaterial3: false); expect(m2Theme.typography, Typography.material2014()); + }); + + testWidgets('Material3 - ThemeData with null typography uses proper defaults', (WidgetTester tester) async { final ThemeData m3Theme = ThemeData(useMaterial3: true); expect(m3Theme.typography, Typography.material2021(colorScheme: m3Theme.colorScheme)); }); @@ -436,7 +439,7 @@ void main() { expect(actualFontSize, kMagicFontSize); }); - testWidgets('Default Theme provides all basic TextStyle properties - M2', (WidgetTester tester) async { + testWidgets('Material2 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { late ThemeData theme; await tester.pumpWidget(Theme( data: ThemeData(useMaterial3: false), @@ -494,7 +497,7 @@ void main() { expect(theme.textTheme.displayLarge!.debugLabel, '(englishLike displayLarge 2014).merge(blackMountainView displayLarge)'); }); - testWidgets('Default Theme provides all basic TextStyle properties - M3', (WidgetTester tester) async { + testWidgets('Material3 - Default Theme provides all basic TextStyle properties', (WidgetTester tester) async { late ThemeData theme; await tester.pumpWidget(Theme( data: ThemeData(useMaterial3: true), @@ -579,9 +582,8 @@ void main() { context = null; }); - testWidgets('Default light theme has defaults', (WidgetTester tester) async { + testWidgets('Material2 - Default light theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData(useMaterial3: false)); - final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData(useMaterial3: true)); expect(themeM2.brightness, Brightness.light); expect(themeM2.primaryColor, Colors.blue); @@ -589,6 +591,10 @@ void main() { expect(themeM2.primaryContrastingColor, Colors.white); expect(themeM2.textTheme.textStyle.fontFamily, '.SF Pro Text'); expect(themeM2.textTheme.textStyle.fontSize, 17.0); + }); + + testWidgets('Material3 - Default light theme has defaults', (WidgetTester tester) async { + final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData(useMaterial3: true)); expect(themeM3.brightness, Brightness.light); expect(themeM3.primaryColor, const Color(0xff6750a4)); @@ -598,9 +604,8 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Dark theme has defaults', (WidgetTester tester) async { + testWidgets('Material2 - Dark theme has defaults', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData.dark(useMaterial3: false)); - final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData.dark(useMaterial3: true)); expect(themeM2.brightness, Brightness.dark); expect(themeM2.primaryColor, Colors.blue); @@ -608,6 +613,10 @@ void main() { expect(themeM2.scaffoldBackgroundColor, Colors.grey[850]); expect(themeM2.textTheme.textStyle.fontFamily, '.SF Pro Text'); expect(themeM2.textTheme.textStyle.fontSize, 17.0); + }); + + testWidgets('Material3 - Dark theme has defaults', (WidgetTester tester) async { + final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData.dark(useMaterial3: true)); expect(themeM3.brightness, Brightness.dark); expect(themeM3.primaryColor, const Color(0xffd0bcff)); @@ -638,7 +647,7 @@ void main() { expect(CupertinoTheme.brightnessOf(context!), Brightness.light); }); - testWidgets('Can override material theme', (WidgetTester tester) async { + testWidgets('Material2 - Can override material theme', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( scaffoldBackgroundColor: CupertinoColors.lightBackgroundGray, @@ -654,7 +663,9 @@ void main() { expect(themeM2.scaffoldBackgroundColor, CupertinoColors.lightBackgroundGray); expect(themeM2.textTheme.textStyle.fontFamily, '.SF Pro Text'); expect(themeM2.textTheme.textStyle.fontSize, 17.0); + }); + testWidgets('Material3 - Can override material theme', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( scaffoldBackgroundColor: CupertinoColors.lightBackgroundGray, @@ -672,7 +683,7 @@ void main() { expect(themeM3.textTheme.textStyle.fontSize, 17.0); }); - testWidgets('Can override properties that are independent of material', (WidgetTester tester) async { + testWidgets('Material2 - Can override properties that are independent of material', (WidgetTester tester) async { final CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( // The bar colors ignore all things material except brightness. @@ -684,7 +695,9 @@ void main() { expect(themeM2.primaryColor, Colors.blue); // MaterialBasedCupertinoThemeData should also function like a normal CupertinoThemeData. expect(themeM2.barBackgroundColor, CupertinoColors.black); + }); + testWidgets('Material3 - Can override properties that are independent of material', (WidgetTester tester) async { final CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( cupertinoOverrideTheme: const CupertinoThemeData( // The bar colors ignore all things material except brightness. @@ -698,7 +711,7 @@ void main() { expect(themeM3.barBackgroundColor, CupertinoColors.black); }); - testWidgets('Changing material theme triggers rebuilds - M2', (WidgetTester tester) async { + testWidgets('Material2 - Changing material theme triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData themeM2 = await testTheme(tester, ThemeData( useMaterial3: false, primarySwatch: Colors.red, @@ -716,7 +729,7 @@ void main() { expect(themeM2.primaryColor, Colors.orange); }); - testWidgets('Changing material theme triggers rebuilds - M3', (WidgetTester tester) async { + testWidgets('Material3 - Changing material theme triggers rebuilds', (WidgetTester tester) async { CupertinoThemeData themeM3 = await testTheme(tester, ThemeData( useMaterial3: true, colorScheme: const ColorScheme.light( @@ -745,8 +758,8 @@ void main() { const Color cupertinoIconColor = Colors.black; await testTheme(tester, ThemeData( - iconTheme: const IconThemeData(color: materialIconColor), - cupertinoOverrideTheme: const CupertinoThemeData(primaryColor: cupertinoIconColor), + iconTheme: const IconThemeData(color: materialIconColor), + cupertinoOverrideTheme: const CupertinoThemeData(primaryColor: cupertinoIconColor), )); expect(buildCount, 1); @@ -807,7 +820,7 @@ void main() { ); testWidgets( - 'Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden - M2', + 'Material2 - Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( useMaterial3: false, @@ -836,7 +849,7 @@ void main() { ); testWidgets( - 'Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden - M3', + 'Material3 - Cupertino overrides do not block derivatives triggering rebuilds when derivatives are not overridden', (WidgetTester tester) async { CupertinoThemeData theme = await testTheme(tester, ThemeData( useMaterial3: true, @@ -869,7 +882,7 @@ void main() { ); testWidgets( - 'copyWith only copies the overrides, not the material or cupertino derivatives - M2', + 'Material2 - copyWith only copies the overrides, not the material or cupertino derivatives', (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: false, @@ -896,7 +909,7 @@ void main() { ); testWidgets( - 'copyWith only copies the overrides, not the material or cupertino derivatives - M3', + 'Material3 - copyWith only copies the overrides, not the material or cupertino derivatives', (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: true, @@ -923,7 +936,7 @@ void main() { ); testWidgets( - "Material themes with no cupertino overrides can also be copyWith'ed - M2", + "Material2 - Material themes with no cupertino overrides can also be copyWith'ed", (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: false, @@ -946,7 +959,7 @@ void main() { ); testWidgets( - "Material themes with no cupertino overrides can also be copyWith'ed - M3", + "Material3 - Material themes with no cupertino overrides can also be copyWith'ed", (WidgetTester tester) async { final CupertinoThemeData originalTheme = await testTheme(tester, ThemeData( useMaterial3: true, diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index b17d2e46d1..1cb1c9a419 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -16,24 +16,216 @@ import '../widgets/semantics_tester.dart'; import 'feedback_tester.dart'; void main() { - for (final MaterialType materialType in MaterialType.values) { - final String selectTimeString; - final String enterTimeString; - final String cancelString; - const String okString = 'OK'; - const String amString = 'AM'; - const String pmString = 'PM'; - switch (materialType) { - case MaterialType.material2: - selectTimeString = 'SELECT TIME'; - enterTimeString = 'ENTER TIME'; - cancelString = 'CANCEL'; - case MaterialType.material3: - selectTimeString = 'Select time'; - enterTimeString = 'Enter time'; - cancelString = 'Cancel'; - } + const String okString = 'OK'; + const String amString = 'AM'; + const String pmString = 'PM'; + Material getMaterialFromDialog(WidgetTester tester) { + return tester.widget(find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first); + } + testWidgets('Material2 - 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.material2); + + 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.material2, + ); + + width = timePickerLandscapeSize.width + padding.horizontal; + height = timePickerLandscapeSizeM2.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material2 - 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.material2, + ); + + 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.material2, + ); + width = timePickerInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal + 16; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material2 - respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material2); + + final List labels00To22 = List.generate(12, (int index) { + return (index * 2).toString().padLeft(2, '0'); + }); + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + // ignore: avoid_dynamic_calls + expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); + + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + // ignore: avoid_dynamic_calls + expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); + }); + + testWidgets('Material3 - 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.material3); + + 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.material3, + ); + + width = timePickerLandscapeSize.width + padding.horizontal; + height = timePickerLandscapeSize.height + padding.vertical; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material3 - 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.material3, + ); + + 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.material3, + ); + + width = timePickerMinInputSize.width - dayPeriodPortraitSize.width - 12 + padding.horizontal; + expect( + tester.getSize(find.byWidget(getMaterialFromDialog(tester))), + Size(width, height), + ); + }); + + testWidgets('Material3 - respects MediaQueryData.alwaysUse24HourFormat == true', (WidgetTester tester) async { + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material3); + + final List labels00To23 = List.generate(24, (int index) { + return index == 0 ? '00' : index.toString(); + }); + final List inner0To23 = List.generate(24, (int index) => index >= 12); + + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + // ignore: avoid_dynamic_calls + expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); + // ignore: avoid_dynamic_calls + expect(primaryLabels.map((dynamic tp) => tp.inner as bool), inner0To23); + + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + // ignore: avoid_dynamic_calls + expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); + // ignore: avoid_dynamic_calls + expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); + }); + + for (final MaterialType materialType in MaterialType.values) { group('Dial (${materialType.name})', () { testWidgets('tap-select an hour', (WidgetTester tester) async { TimeOfDay? result; @@ -280,21 +472,32 @@ 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); - expect(find.text(cancelString), findsOneWidget); + testWidgets('Material2 - Widgets have correct label capitalization', (WidgetTester tester) async { + await startPicker(tester, (TimeOfDay? time) {}, materialType: MaterialType.material2); + expect(find.text('SELECT TIME'), findsOneWidget); + expect(find.text('CANCEL'), findsOneWidget); }); - testWidgets('Widgets have correct label capitalization in input mode', (WidgetTester tester) async { + testWidgets('Material3 - Widgets have correct label capitalization', (WidgetTester tester) async { + await startPicker(tester, (TimeOfDay? time) {}, materialType: MaterialType.material3); + expect(find.text('Select time'), findsOneWidget); + expect(find.text('Cancel'), findsOneWidget); + }); + + testWidgets('Material2 - Widgets have correct label capitalization in input mode', (WidgetTester tester) async { await startPicker(tester, (TimeOfDay? time) {}, - entryMode: TimePickerEntryMode.input, materialType: materialType); - expect(find.text(enterTimeString), findsOneWidget); - expect(find.text(cancelString), findsOneWidget); + entryMode: TimePickerEntryMode.input, materialType: MaterialType.material2 + ); + expect(find.text('ENTER TIME'), findsOneWidget); + expect(find.text('CANCEL'), findsOneWidget); + }); + + testWidgets('Material3 - Widgets have correct label capitalization in input mode', (WidgetTester tester) async { + await startPicker(tester, (TimeOfDay? time) {}, + entryMode: TimePickerEntryMode.input, materialType: MaterialType.material3 + ); + expect(find.text('Enter time'), findsOneWidget); + expect(find.text('Cancel'), findsOneWidget); }); testWidgets('respects MediaQueryData.alwaysUse24HourFormat == false', (WidgetTester tester) async { @@ -314,211 +517,6 @@ void main() { expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels12To11); }); - 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); - - final List labels00To22 = List.generate(12, (int index) { - return (index * 2).toString().padLeft(2, '0'); - }); - final CustomPaint dialPaint = tester.widget(findDialPaint); - final dynamic dialPainter = dialPaint.painter; - // ignore: avoid_dynamic_calls - final List primaryLabels = dialPainter.primaryLabels as List; - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); - - // ignore: avoid_dynamic_calls - final List selectedLabels = dialPainter.selectedLabels as List; - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To22); - }); - 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); - - final List labels00To23 = List.generate(24, (int index) { - return index == 0 ? '00' : index.toString(); - }); - final List inner0To23 = List.generate(24, (int index) => index >= 12); - - final CustomPaint dialPaint = tester.widget(findDialPaint); - final dynamic dialPainter = dialPaint.painter; - // ignore: avoid_dynamic_calls - final List primaryLabels = dialPainter.primaryLabels as List; - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); - // ignore: avoid_dynamic_calls - expect(primaryLabels.map((dynamic tp) => tp.inner as bool), inner0To23); - - // ignore: avoid_dynamic_calls - final List selectedLabels = dialPainter.selectedLabels as List; - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.painter.text.text as String), labels00To23); - // ignore: avoid_dynamic_calls - expect(selectedLabels.map((dynamic tp) => tp.inner as bool), inner0To23); - }); - } - testWidgets('when change orientation, should reflect in render objects', (WidgetTester tester) async { addTearDown(tester.view.reset); @@ -708,10 +706,12 @@ void main() { expect(find.text(helperText), findsOneWidget); }); - testWidgets('OK Cancel button and helpText layout', (WidgetTester tester) async { + testWidgets('Material2 - OK Cancel button and helpText layout', (WidgetTester tester) async { + const String selectTimeString = 'SELECT TIME'; + const String cancelString = 'CANCEL'; Widget buildFrame(TextDirection textDirection) { return MaterialApp( - theme: ThemeData(useMaterial3: materialType == MaterialType.material3), + theme: ThemeData(useMaterial3: false), home: Material( child: Center( child: Builder( @@ -742,21 +742,13 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(); - switch (materialType) { - case MaterialType.material2: - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals( - ParagraphBuilder.shouldDisableRoundingHack ? const Offset(280.5, 165) : const Offset(281, 165), - )); - expect(tester.getBottomRight(find.text(okString)).dx, 644); - expect(tester.getBottomLeft(find.text(okString)).dx, 616); - expect(tester.getBottomRight(find.text(cancelString)).dx, 582); - case MaterialType.material3: - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(138, 129))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(295.0, 149.0))); - expect(tester.getBottomLeft(find.text(okString)).dx, 615.5); - expect(tester.getBottomRight(find.text(cancelString)).dx, 578); - } + expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(154, 155))); + expect(tester.getBottomRight(find.text(selectTimeString)), equals( + ParagraphBuilder.shouldDisableRoundingHack ? const Offset(280.5, 165) : const Offset(281, 165), + )); + expect(tester.getBottomRight(find.text(okString)).dx, 644); + expect(tester.getBottomLeft(find.text(okString)).dx, 616); + expect(tester.getBottomRight(find.text(cancelString)).dx, 582); await tester.tap(find.text(okString)); await tester.pumpAndSettle(); @@ -765,23 +757,72 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(); - switch (materialType) { - case MaterialType.material2: - expect(tester.getTopLeft(find.text(selectTimeString)), equals( - ParagraphBuilder.shouldDisableRoundingHack ? const Offset(519.5, 155) : const Offset(519, 155), - )); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165))); - expect(tester.getBottomLeft(find.text(okString)).dx, 156); - expect(tester.getBottomRight(find.text(okString)).dx, 184); - expect(tester.getBottomLeft(find.text(cancelString)).dx, 218); - case MaterialType.material3: - expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(505.0, 129.0))); - expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(662, 149))); - expect(tester.getBottomLeft(find.text(okString)).dx, 155.5); - expect(tester.getBottomRight(find.text(okString)).dx, 184.5); - expect(tester.getBottomLeft(find.text(cancelString)).dx, 222); + expect(tester.getTopLeft(find.text(selectTimeString)), equals( + ParagraphBuilder.shouldDisableRoundingHack ? const Offset(519.5, 155) : const Offset(519, 155), + )); + expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(646, 165))); + expect(tester.getBottomLeft(find.text(okString)).dx, 156); + expect(tester.getBottomRight(find.text(okString)).dx, 184); + expect(tester.getBottomLeft(find.text(cancelString)).dx, 218); + + await tester.tap(find.text(okString)); + await tester.pumpAndSettle(); + }); + + testWidgets('Material3 - OK Cancel button and helpText layout', (WidgetTester tester) async { + const String selectTimeString = 'Select time'; + const String cancelString = 'Cancel'; + Widget buildFrame(TextDirection textDirection) { + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: Material( + child: Center( + child: Builder( + builder: (BuildContext context) { + return ElevatedButton( + child: const Text('X'), + onPressed: () { + showTimePicker( + context: context, + initialTime: const TimeOfDay(hour: 7, minute: 0), + builder: (BuildContext context, Widget? child) { + return Directionality( + textDirection: textDirection, + child: child!, + ); + }, + ); + }, + ); + }, + ), + ), + ), + ); } + await tester.pumpWidget(buildFrame(TextDirection.ltr)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(138, 129))); + expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(295.0, 149.0))); + expect(tester.getBottomLeft(find.text(okString)).dx, 615.5); + expect(tester.getBottomRight(find.text(cancelString)).dx, 578); + + await tester.tap(find.text(okString)); + await tester.pumpAndSettle(); + + await tester.pumpWidget(buildFrame(TextDirection.rtl)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(); + + expect(tester.getTopLeft(find.text(selectTimeString)), equals(const Offset(505.0, 129.0))); + expect(tester.getBottomRight(find.text(selectTimeString)), equals(const Offset(662, 149))); + expect(tester.getBottomLeft(find.text(okString)).dx, 155.5); + expect(tester.getBottomRight(find.text(okString)).dx, 184.5); + expect(tester.getBottomLeft(find.text(cancelString)).dx, 222); + await tester.tap(find.text(okString)); await tester.pumpAndSettle(); }); @@ -996,9 +1037,9 @@ void main() { semantics.dispose(); }); - testWidgets('provides semantics information for header and footer', (WidgetTester tester) async { + testWidgets('Material2 - provides semantics information for header and footer', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); - await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: materialType); + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material2); expect(semantics, isNot(includesNodeWith(label: ':'))); expect( @@ -1011,7 +1052,32 @@ void main() { hasLength(1), reason: '07 appears once in the header', ); - expect(semantics, includesNodeWith(label: cancelString)); + expect(semantics, includesNodeWith(label: 'CANCEL')); + expect(semantics, includesNodeWith(label: okString)); + + // In 24-hour mode we don't have AM/PM control. + expect(semantics, isNot(includesNodeWith(label: amString))); + expect(semantics, isNot(includesNodeWith(label: pmString))); + + semantics.dispose(); + }); + + testWidgets('Material3 - provides semantics information for header and footer', (WidgetTester tester) async { + final SemanticsTester semantics = SemanticsTester(tester); + await mediaQueryBoilerplate(tester, alwaysUse24HourFormat: true, materialType: MaterialType.material3); + + expect(semantics, isNot(includesNodeWith(label: ':'))); + expect( + semantics.nodesWith(value: 'Select minutes 00'), + hasLength(1), + reason: '00 appears once in the header', + ); + expect( + semantics.nodesWith(value: 'Select hours 07'), + hasLength(1), + reason: '07 appears once in the header', + ); + expect(semantics, includesNodeWith(label: 'Cancel')); expect(semantics, includesNodeWith(label: okString)); // In 24-hour mode we don't have AM/PM control. diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index dd2e557690..2c7ba77af8 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -98,89 +98,64 @@ void main() { ]); }); - testWidgets('Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { - final ThemeData defaultTheme = ThemeData(); - final bool material3 = defaultTheme.useMaterial3; + testWidgets('Material2 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final Material dialogMaterial = _dialogMaterial(tester); expect(dialogMaterial.color, defaultTheme.colorScheme.surface); - expect(dialogMaterial.shape, material3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))) - : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) + expect( + dialogMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), ); final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); expect( dial, - material3 - ? (paints - ..circle(color: defaultTheme.colorScheme.surfaceVariant.withOpacity(0.08)) // Dial background color. - ..circle(color: Color(defaultTheme.colorScheme.primary.value))) - : (paints - ..circle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.08)) // Dial background color. - ..circle(color: Color(defaultTheme.colorScheme.primary.value))), // Dial hand color. + paints + ..circle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.08)) // Dial background color. + ..circle(color: Color(defaultTheme.colorScheme.primary.value)) ); final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - material3 - ? (Typography.material2021().englishLike.displayLarge! - .merge(Typography.material2021().black.displayLarge) - .copyWith(color: defaultTheme.colorScheme.onPrimaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.displayMedium! - .merge(Typography.material2014().black.displayMedium) - .copyWith(color: defaultTheme.colorScheme.primary)), + Typography.material2014().englishLike.displayMedium! + .merge(Typography.material2014().black.displayMedium) + .copyWith(color: defaultTheme.colorScheme.primary) ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - material3 - ? (Typography.material2021().englishLike.displayLarge! - .merge(Typography.material2021().black.displayLarge) - .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.displayMedium! - .merge(Typography.material2014().black.displayMedium) - .copyWith(color: defaultTheme.colorScheme.onSurface)), + Typography.material2014().englishLike.displayMedium! + .merge(Typography.material2014().black.displayMedium) + .copyWith(color: defaultTheme.colorScheme.onSurface), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, - material3 - ? (Typography.material2021().englishLike.titleMedium! - .merge(Typography.material2021().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.onTertiaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.primary)), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .copyWith(color: defaultTheme.colorScheme.primary), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, - material3 - ? (Typography.material2021().englishLike.titleMedium! - .merge(Typography.material2021().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.onTertiaryContainer, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6))), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.6)), ); - final RenderParagraph helperText = _textRenderParagraph(tester, material3 ? 'Select time' : 'SELECT TIME'); + final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME'); expect( helperText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.labelSmall! - .merge(Typography.material2014().black.labelSmall)), + Typography.material2014().englishLike.labelSmall! + .merge(Typography.material2014().black.labelSmall), ); final CustomPaint dialPaint = tester.widget(findDialPaint); @@ -190,44 +165,36 @@ void main() { expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onSurface, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().black.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onSurface)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().black.bodyLarge) + .copyWith(color: defaultTheme.colorScheme.onSurface), ); // ignore: avoid_dynamic_calls final List selectedLabels = dialPainter.selectedLabels as List; expect( // ignore: avoid_dynamic_calls selectedLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onPrimary, decorationColor: defaultTheme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().white.bodyLarge) - .copyWith(color: defaultTheme.colorScheme.onPrimary)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().white.bodyLarge) + .copyWith(color: defaultTheme.colorScheme.onPrimary), ); final Material hourMaterial = _textMaterial(tester, '7'); - expect(hourMaterial.color, material3 ? defaultTheme.colorScheme.primaryContainer : defaultTheme.colorScheme.primary.withOpacity(0.12)); - expect(hourMaterial.shape, material3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) - : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) + expect(hourMaterial.color, defaultTheme.colorScheme.primary.withOpacity(0.12)); + expect( + hourMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), ); final Material minuteMaterial = _textMaterial(tester, '15'); - expect(minuteMaterial.color, material3 ? defaultTheme.colorScheme.surfaceVariant : defaultTheme.colorScheme.onSurface.withOpacity(0.12)); - expect(minuteMaterial.shape, material3 - ? const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) - : const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))) + expect(minuteMaterial.color, defaultTheme.colorScheme.onSurface.withOpacity(0.12)); + expect( + minuteMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0))), ); final Material amMaterial = _textMaterial(tester, 'AM'); - expect(amMaterial.color, material3 ? defaultTheme.colorScheme.tertiaryContainer : defaultTheme.colorScheme.primary.withOpacity(0.12)); + expect(amMaterial.color, defaultTheme.colorScheme.primary.withOpacity(0.12)); final Material pmMaterial = _textMaterial(tester, 'PM'); expect(pmMaterial.color, Colors.transparent); @@ -239,61 +206,245 @@ void main() { final Material dayPeriodMaterial = _dayPeriodMaterial(tester); expect( dayPeriodMaterial.shape, - material3 - ? RoundedRectangleBorder( - borderRadius: const BorderRadius.all(Radius.circular(8.0)), - side: BorderSide(color: defaultTheme.colorScheme.outline), - ) : RoundedRectangleBorder( - borderRadius: const BorderRadius.all(Radius.circular(4.0)), - side: BorderSide(color: expectedBorderColor), - ), + RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(4.0)), + side: BorderSide(color: expectedBorderColor), + ), ); final Container dayPeriodDivider = _dayPeriodDivider(tester); expect( dayPeriodDivider.decoration, - material3 - ? BoxDecoration(border: Border(left: BorderSide(color: defaultTheme.colorScheme.outline))) - : BoxDecoration(border: Border(left: BorderSide(color: expectedBorderColor))), + BoxDecoration(border: Border(left: BorderSide(color: expectedBorderColor))), ); final IconButton entryModeIconButton = _entryModeIconButton(tester); expect( entryModeIconButton.color, - material3 ? null : defaultTheme.colorScheme.onSurface.withOpacity(0.6), + defaultTheme.colorScheme.onSurface.withOpacity(0.6), ); }); + testWidgets('Material3 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: true); + await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); - testWidgets('Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { - final ThemeData defaultTheme = ThemeData(); - final bool material3 = defaultTheme.useMaterial3; + final Material dialogMaterial = _dialogMaterial(tester); + expect(dialogMaterial.color, defaultTheme.colorScheme.surface); + expect( + dialogMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))), + ); + + final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); + expect( + dial, + paints + ..circle(color: defaultTheme.colorScheme.surfaceVariant.withOpacity(0.08)) // Dial background color. + ..circle(color: Color(defaultTheme.colorScheme.primary.value)), // Dial hand color. + ); + + final RenderParagraph hourText = _textRenderParagraph(tester, '7'); + expect( + hourText.text.style, + Typography.material2021().englishLike.displayLarge! + .merge(Typography.material2021().black.displayLarge) + .copyWith( + color: defaultTheme.colorScheme.onPrimaryContainer, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); + expect( + minuteText.text.style, + Typography.material2021().englishLike.displayLarge! + .merge(Typography.material2021().black.displayLarge) + .copyWith( + color: defaultTheme.colorScheme.onSurface, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); + expect( + amText.text.style, + Typography.material2021().englishLike.titleMedium! + .merge(Typography.material2021().black.titleMedium) + .copyWith( + color: defaultTheme.colorScheme.onTertiaryContainer, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); + expect( + pmText.text.style, + Typography.material2021().englishLike.titleMedium! + .merge(Typography.material2021().black.titleMedium) + .copyWith( + color: defaultTheme.colorScheme.onTertiaryContainer, + decorationColor: defaultTheme.colorScheme.onSurface + ) + ); + + final RenderParagraph helperText = _textRenderParagraph(tester, 'Select time'); + expect( + helperText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .copyWith( + color: defaultTheme.colorScheme.onSurface, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + expect( + // ignore: avoid_dynamic_calls + primaryLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith( + color: defaultTheme.colorScheme.onSurface, + decorationColor: defaultTheme.colorScheme.onSurface + ), + ); + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + expect( + // ignore: avoid_dynamic_calls + selectedLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith( + color: defaultTheme.colorScheme.onPrimary, + decorationColor: defaultTheme.colorScheme.onSurface, + ), + ); + + final Material hourMaterial = _textMaterial(tester, '7'); + expect(hourMaterial.color, defaultTheme.colorScheme.primaryContainer); + expect( + hourMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))) + ); + + final Material minuteMaterial = _textMaterial(tester, '15'); + expect(minuteMaterial.color, defaultTheme.colorScheme.surfaceVariant); + expect( + minuteMaterial.shape, + const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))), + ); + + final Material amMaterial = _textMaterial(tester, 'AM'); + expect(amMaterial.color, defaultTheme.colorScheme.tertiaryContainer); + + final Material pmMaterial = _textMaterial(tester, 'PM'); + expect(pmMaterial.color, Colors.transparent); + + final Material dayPeriodMaterial = _dayPeriodMaterial(tester); + expect( + dayPeriodMaterial.shape, + RoundedRectangleBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + side: BorderSide(color: defaultTheme.colorScheme.outline), + ), + ); + + final Container dayPeriodDivider = _dayPeriodDivider(tester); + expect( + dayPeriodDivider.decoration, + BoxDecoration(border: Border(left: BorderSide(color: defaultTheme.colorScheme.outline))), + ); + + final IconButton entryModeIconButton = _entryModeIconButton(tester); + expect(entryModeIconButton.color, null); + }); + + testWidgets('Material2 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); final InputDecoration hourDecoration = _textField(tester, '7').decoration!; expect(hourDecoration.filled, true); - expect(hourDecoration.fillColor, material3 - ? defaultTheme.colorScheme.surfaceVariant - : MaterialStateColor.resolveWith((Set states) => defaultTheme.colorScheme.onSurface.withOpacity(0.12))); - expect(hourDecoration.enabledBorder, material3 ? const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: Colors.transparent)) : const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent))); - expect(hourDecoration.errorBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); - expect(hourDecoration.focusedBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2))); - expect(hourDecoration.focusedErrorBorder, material3 ? OutlineInputBorder(borderRadius: const BorderRadius.all(Radius.circular(8.0)), borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)) : OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2))); + expect( + hourDecoration.fillColor, + MaterialStateColor.resolveWith((Set states) => + defaultTheme.colorScheme.onSurface.withOpacity(0.12)) + ); + expect( + hourDecoration.enabledBorder, + const OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)) + ); + expect( + hourDecoration.errorBorder, + OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2)) + ); + expect( + hourDecoration.focusedBorder, + OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2)) + ); + expect( + hourDecoration.focusedErrorBorder, + OutlineInputBorder(borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2)) + ); expect( hourDecoration.hintStyle, - material3 - ? TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)) - : (Typography.material2014().englishLike.displayMedium! - .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)))), + Typography.material2014().englishLike.displayMedium! + .merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36))) ); }); - testWidgets('Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { + testWidgets('Material3 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async { + final ThemeData defaultTheme = ThemeData(useMaterial3: true); + await tester.pumpWidget(_TimePickerLauncher(themeData: defaultTheme, entryMode: TimePickerEntryMode.input)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final InputDecoration hourDecoration = _textField(tester, '7').decoration!; + expect(hourDecoration.filled, true); + expect(hourDecoration.fillColor, defaultTheme.colorScheme.surfaceVariant); + expect( + hourDecoration.enabledBorder, + const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: Colors.transparent)), + ); + expect( + hourDecoration.errorBorder, + OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)), + ); + expect( + hourDecoration.focusedBorder, + OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: defaultTheme.colorScheme.primary, width: 2.0)), + ); + expect( + hourDecoration.focusedErrorBorder, + OutlineInputBorder( + borderRadius: const BorderRadius.all(Radius.circular(8.0)), + borderSide: BorderSide(color: defaultTheme.colorScheme.error, width: 2.0)), + ); + expect( + hourDecoration.hintStyle, + TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)) + ); + }); + + testWidgets('Material2 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(); - final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); - final bool material3 = theme.useMaterial3; + final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: false); await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); @@ -313,69 +464,45 @@ void main() { final RenderParagraph hourText = _textRenderParagraph(tester, '7'); expect( hourText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.bodyMedium! - .merge(Typography.material2014().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _selectedColor)), + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _selectedColor), ); final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); expect( minuteText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.bodyMedium! - .merge(Typography.material2014().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _unselectedColor)), + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _unselectedColor), ); final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); expect( amText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .merge(timePickerTheme.dayPeriodTextStyle) - .copyWith(color: _selectedColor)), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .merge(timePickerTheme.dayPeriodTextStyle) + .copyWith(color: _selectedColor), ); final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); expect( pmText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.hourMinuteTextStyle) - .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f))) - : (Typography.material2014().englishLike.titleMedium! - .merge(Typography.material2014().black.titleMedium) - .merge(timePickerTheme.dayPeriodTextStyle) - .copyWith(color: _unselectedColor)), + Typography.material2014().englishLike.titleMedium! + .merge(Typography.material2014().black.titleMedium) + .merge(timePickerTheme.dayPeriodTextStyle) + .copyWith(color: _unselectedColor), ); - final RenderParagraph helperText = _textRenderParagraph(tester, material3 ? 'Select time' : 'SELECT TIME'); + final RenderParagraph helperText = _textRenderParagraph(tester, 'SELECT TIME'); expect( helperText.text.style, - material3 - ? (Typography.material2021().englishLike.bodyMedium! - .merge(Typography.material2021().black.bodyMedium) - .merge(timePickerTheme.helpTextStyle).copyWith(color: theme.colorScheme.onSurface, decorationColor: theme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyMedium! - .merge(Typography.material2014().black.bodyMedium) - .merge(timePickerTheme.helpTextStyle)), + Typography.material2014().englishLike.bodyMedium! + .merge(Typography.material2014().black.bodyMedium) + .merge(timePickerTheme.helpTextStyle), ); final CustomPaint dialPaint = tester.widget(findDialPaint); @@ -385,26 +512,18 @@ void main() { expect( // ignore: avoid_dynamic_calls primaryLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: _unselectedColor, decorationColor: theme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().black.bodyLarge) - .copyWith(color: _unselectedColor)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().black.bodyLarge) + .copyWith(color: _unselectedColor), ); // ignore: avoid_dynamic_calls final List selectedLabels = dialPainter.selectedLabels as List; expect( // ignore: avoid_dynamic_calls selectedLabels.first.painter.text.style, - material3 - ? (Typography.material2021().englishLike.bodyLarge! - .merge(Typography.material2021().black.bodyLarge) - .copyWith(color: _selectedColor, decorationColor: theme.colorScheme.onSurface)) - : (Typography.material2014().englishLike.bodyLarge! - .merge(Typography.material2014().white.bodyLarge) - .copyWith(color: _selectedColor)), + Typography.material2014().englishLike.bodyLarge! + .merge(Typography.material2014().white.bodyLarge) + .copyWith(color: _selectedColor), ); final Material hourMaterial = _textMaterial(tester, '7'); @@ -436,10 +555,127 @@ void main() { final IconButton entryModeIconButton = _entryModeIconButton(tester); expect( entryModeIconButton.color, - material3 ? null : timePickerTheme.entryModeIconColor, + timePickerTheme.entryModeIconColor, ); }); + testWidgets('Material3 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async { + final TimePickerThemeData timePickerTheme = _timePickerTheme(); + final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme, useMaterial3: true); + await tester.pumpWidget(_TimePickerLauncher(themeData: theme)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final Material dialogMaterial = _dialogMaterial(tester); + expect(dialogMaterial.color, timePickerTheme.backgroundColor); + expect(dialogMaterial.shape, timePickerTheme.shape); + + final RenderBox dial = tester.firstRenderObject(find.byType(CustomPaint)); + expect( + dial, + paints + ..circle(color: Color(timePickerTheme.dialBackgroundColor!.value)) // Dial background color. + ..circle(color: Color(timePickerTheme.dialHandColor!.value)), // Dial hand color. + ); + + final RenderParagraph hourText = _textRenderParagraph(tester, '7'); + expect( + hourText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph minuteText = _textRenderParagraph(tester, '15'); + expect( + minuteText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph amText = _textRenderParagraph(tester, 'AM'); + expect( + amText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _selectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph pmText = _textRenderParagraph(tester, 'PM'); + expect( + pmText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.hourMinuteTextStyle) + .copyWith(color: _unselectedColor, decorationColor: const Color(0xff1c1b1f)), + ); + + final RenderParagraph helperText = _textRenderParagraph(tester, 'Select time'); + expect( + helperText.text.style, + Typography.material2021().englishLike.bodyMedium! + .merge(Typography.material2021().black.bodyMedium) + .merge(timePickerTheme.helpTextStyle).copyWith( + color: theme.colorScheme.onSurface, + decorationColor: theme.colorScheme.onSurface + ), + ); + + final CustomPaint dialPaint = tester.widget(findDialPaint); + final dynamic dialPainter = dialPaint.painter; + // ignore: avoid_dynamic_calls + final List primaryLabels = dialPainter.primaryLabels as List; + expect( + // ignore: avoid_dynamic_calls + primaryLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith(color: _unselectedColor, decorationColor: theme.colorScheme.onSurface), + ); + // ignore: avoid_dynamic_calls + final List selectedLabels = dialPainter.selectedLabels as List; + expect( + // ignore: avoid_dynamic_calls + selectedLabels.first.painter.text.style, + Typography.material2021().englishLike.bodyLarge! + .merge(Typography.material2021().black.bodyLarge) + .copyWith(color: _selectedColor, decorationColor: theme.colorScheme.onSurface), + ); + + final Material hourMaterial = _textMaterial(tester, '7'); + expect(hourMaterial.color, _selectedColor); + expect(hourMaterial.shape, timePickerTheme.hourMinuteShape); + + final Material minuteMaterial = _textMaterial(tester, '15'); + expect(minuteMaterial.color, _unselectedColor); + expect(minuteMaterial.shape, timePickerTheme.hourMinuteShape); + + final Material amMaterial = _textMaterial(tester, 'AM'); + expect(amMaterial.color, _selectedColor); + + final Material pmMaterial = _textMaterial(tester, 'PM'); + expect(pmMaterial.color, _unselectedColor); + + final Material dayPeriodMaterial = _dayPeriodMaterial(tester); + expect( + dayPeriodMaterial.shape, + timePickerTheme.dayPeriodShape!.copyWith(side: timePickerTheme.dayPeriodBorderSide), + ); + + final Container dayPeriodDivider = _dayPeriodDivider(tester); + expect( + dayPeriodDivider.decoration, + BoxDecoration(border: Border(left: timePickerTheme.dayPeriodBorderSide!)), + ); + + final IconButton entryModeIconButton = _entryModeIconButton(tester); + expect(entryModeIconButton.color, null); + }); + testWidgets('Time picker uses values from TimePickerThemeData with InputDecorationTheme - input mode', (WidgetTester tester) async { final TimePickerThemeData timePickerTheme = _timePickerTheme(includeInputDecoration: true); final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme);