From 95cdebedae5566ffc730a82c54c120e91ed80c45 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Wed, 21 Feb 2024 10:10:01 +0200 Subject: [PATCH] Add `timeSelectorSeparatorColor` and `timeSelectorSeparatorTextStyle` for Material 3 Time Picker (#143739) fixes [`Time selector separator` in TimePicker is not centered vertically](https://github.com/flutter/flutter/issues/143691) Separator currently `hourMinuteTextStyle` to style itself. This introduces `timeSelectorSeparatorColor` and `timeSelectorSeparatorTextStyle` from Material 3 specs to correctly style the separator. This also adds ability to change separator color without changing `hourMinuteTextColor`. ### Specs for the time selector separator https://m3.material.io/components/time-pickers/specs ![image](https://github.com/flutter/flutter/assets/48603081/0c84f649-545d-441b-adbf-2b9ec872b14c) ### Code sample
expand to view the code sample ```dart import 'package:flutter/material.dart'; void main() { runApp(const App()); } class App extends StatelessWidget { const App({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData( // timePickerTheme: TimePickerThemeData( // hourMinuteTextColor: Colors.amber, // ) ), home: Scaffold( body: Center( child: Builder(builder: (context) { return ElevatedButton( onPressed: () async { await showTimePicker( context: context, initialTime: TimeOfDay.now(), ); }, child: const Text('Pick Time'), ); }), ), ), ); } } ```
| Before | After | | --------------- | --------------- | | | | --- .../lib/time_picker_template.dart | 14 ++++++ .../flutter/lib/src/material/time_picker.dart | 38 +++++++++++---- .../lib/src/material/time_picker_theme.dart | 35 +++++++++++++- .../test/material/time_picker_test.dart | 33 +++++++++++-- .../test/material/time_picker_theme_test.dart | 40 +++++++++++++++- .../test/material/time_picker_test.dart | 48 +++++++++---------- 6 files changed, 170 insertions(+), 38 deletions(-) diff --git a/dev/tools/gen_defaults/lib/time_picker_template.dart b/dev/tools/gen_defaults/lib/time_picker_template.dart index 4d60175f88..741c7f706f 100644 --- a/dev/tools/gen_defaults/lib/time_picker_template.dart +++ b/dev/tools/gen_defaults/lib/time_picker_template.dart @@ -333,6 +333,20 @@ class _${blockName}DefaultsM3 extends _TimePickerDefaults { ShapeBorder get shape { return ${shape("$tokenGroup.container")}; } + + @override + MaterialStateProperty? get timeSelectorSeparatorColor { + // TODO(tahatesser): Update this when tokens are available. + // This is taken from https://m3.material.io/components/time-pickers/specs. + return MaterialStatePropertyAll(_colors.onSurface); + } + + @override + MaterialStateProperty? get timeSelectorSeparatorTextStyle { + // TODO(tahatesser): Update this when tokens are available. + // This is taken from https://m3.material.io/components/time-pickers/specs. + return MaterialStatePropertyAll(_textTheme.displayLarge); + } } '''; } diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index 283726d5aa..7c3efb04e7 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -242,7 +242,7 @@ class _TimePickerHeader extends StatelessWidget { textDirection: TextDirection.ltr, children: [ const Expanded(child: _HourControl()), - _StringFragment(timeOfDayFormat: timeOfDayFormat), + _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat), const Expanded(child: _MinuteControl()), ], ), @@ -278,7 +278,7 @@ class _TimePickerHeader extends StatelessWidget { textDirection: TextDirection.ltr, children: [ const Expanded(child: _HourControl()), - _StringFragment(timeOfDayFormat: timeOfDayFormat), + _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat), const Expanded(child: _MinuteControl()), ], ), @@ -428,12 +428,12 @@ class _HourControl extends StatelessWidget { /// A passive fragment showing a string value. /// /// Used to display the appropriate separator between the input fields. -class _StringFragment extends StatelessWidget { - const _StringFragment({ required this.timeOfDayFormat }); +class _TimeSelectorSeparator extends StatelessWidget { + const _TimeSelectorSeparator({ required this.timeOfDayFormat }); final TimeOfDayFormat timeOfDayFormat; - String _stringFragmentValue(TimeOfDayFormat timeOfDayFormat) { + String _timeSelectorSeparatorValue(TimeOfDayFormat timeOfDayFormat) { switch (timeOfDayFormat) { case TimeOfDayFormat.h_colon_mm_space_a: case TimeOfDayFormat.a_space_h_colon_mm: @@ -455,11 +455,17 @@ class _StringFragment extends StatelessWidget { final Set states = {}; final Color effectiveTextColor = MaterialStateProperty.resolveAs( - timePickerTheme.hourMinuteTextColor ?? defaultTheme.hourMinuteTextColor, + timePickerTheme.timeSelectorSeparatorColor?.resolve(states) + ?? timePickerTheme.hourMinuteTextColor + ?? defaultTheme.timeSelectorSeparatorColor?.resolve(states) + ?? defaultTheme.hourMinuteTextColor, states, ); final TextStyle effectiveStyle = MaterialStateProperty.resolveAs( - timePickerTheme.hourMinuteTextStyle ?? defaultTheme.hourMinuteTextStyle, + timePickerTheme.timeSelectorSeparatorTextStyle?.resolve(states) + ?? timePickerTheme.hourMinuteTextStyle + ?? defaultTheme.timeSelectorSeparatorTextStyle?.resolve(states) + ?? defaultTheme.hourMinuteTextStyle, states, ).copyWith(color: effectiveTextColor); @@ -478,7 +484,7 @@ class _StringFragment extends StatelessWidget { width: timeOfDayFormat == TimeOfDayFormat.frenchCanadian ? 36 : 24, height: height, child: Text( - _stringFragmentValue(timeOfDayFormat), + _timeSelectorSeparatorValue(timeOfDayFormat), style: effectiveStyle, textScaler: TextScaler.noScaling, textAlign: TextAlign.center, @@ -1801,7 +1807,7 @@ class _TimePickerInputState extends State<_TimePickerInput> with RestorationMixi ], ), ), - _StringFragment(timeOfDayFormat: timeOfDayFormat), + _TimeSelectorSeparator(timeOfDayFormat: timeOfDayFormat), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -3655,6 +3661,20 @@ class _TimePickerDefaultsM3 extends _TimePickerDefaults { ShapeBorder get shape { return const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(28.0))); } + + @override + MaterialStateProperty? get timeSelectorSeparatorColor { + // TODO(tahatesser): Update this when tokens are available. + // This is taken from https://m3.material.io/components/time-pickers/specs. + return MaterialStatePropertyAll(_colors.onSurface); + } + + @override + MaterialStateProperty? get timeSelectorSeparatorTextStyle { + // TODO(tahatesser): Update this when tokens are available. + // This is taken from https://m3.material.io/components/time-pickers/specs. + return MaterialStatePropertyAll(_textTheme.displayLarge); + } } // END GENERATED TOKEN PROPERTIES - TimePicker diff --git a/packages/flutter/lib/src/material/time_picker_theme.dart b/packages/flutter/lib/src/material/time_picker_theme.dart index 47cf924964..e9ec5f8bac 100644 --- a/packages/flutter/lib/src/material/time_picker_theme.dart +++ b/packages/flutter/lib/src/material/time_picker_theme.dart @@ -62,6 +62,8 @@ class TimePickerThemeData with Diagnosticable { this.inputDecorationTheme, this.padding, this.shape, + this.timeSelectorSeparatorColor, + this.timeSelectorSeparatorTextStyle, }) : _dayPeriodColor = dayPeriodColor; /// The background color of a time picker. @@ -261,6 +263,25 @@ class TimePickerThemeData with Diagnosticable { /// `RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(4.0)))`. final ShapeBorder? shape; + /// The color of the time selector seperator between the hour and minute controls. + /// + /// if this is null, the time picker defaults to the overall theme's + /// [ColorScheme.onSurface]. + /// + /// If this is null and [ThemeData.useMaterial3] is false, then defaults to the value of + /// [hourMinuteTextColor]. + final MaterialStateProperty? timeSelectorSeparatorColor; + + /// Used to configure the text style for the time selector seperator between the hour + /// and minute controls. + /// + /// If this is null, the time picker defaults to the overall theme's + /// [TextTheme.displayLarge]. + /// + /// If this is null and [ThemeData.useMaterial3] is false, then defaults to the value of + /// [hourMinuteTextStyle]. + final MaterialStateProperty? timeSelectorSeparatorTextStyle; + /// Creates a copy of this object with the given fields replaced with the /// new values. TimePickerThemeData copyWith({ @@ -287,6 +308,8 @@ class TimePickerThemeData with Diagnosticable { InputDecorationTheme? inputDecorationTheme, EdgeInsetsGeometry? padding, ShapeBorder? shape, + MaterialStateProperty? timeSelectorSeparatorColor, + MaterialStateProperty? timeSelectorSeparatorTextStyle, }) { return TimePickerThemeData( backgroundColor: backgroundColor ?? this.backgroundColor, @@ -311,6 +334,8 @@ class TimePickerThemeData with Diagnosticable { inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme, padding: padding ?? this.padding, shape: shape ?? this.shape, + timeSelectorSeparatorColor: timeSelectorSeparatorColor ?? this.timeSelectorSeparatorColor, + timeSelectorSeparatorTextStyle: timeSelectorSeparatorTextStyle ?? this.timeSelectorSeparatorTextStyle, ); } @@ -355,6 +380,8 @@ class TimePickerThemeData with Diagnosticable { inputDecorationTheme: t < 0.5 ? a?.inputDecorationTheme : b?.inputDecorationTheme, padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t), + timeSelectorSeparatorColor: MaterialStateProperty.lerp(a?.timeSelectorSeparatorColor, b?.timeSelectorSeparatorColor, t, Color.lerp), + timeSelectorSeparatorTextStyle: MaterialStateProperty.lerp(a?.timeSelectorSeparatorTextStyle, b?.timeSelectorSeparatorTextStyle, t, TextStyle.lerp), ); } @@ -382,6 +409,8 @@ class TimePickerThemeData with Diagnosticable { inputDecorationTheme, padding, shape, + timeSelectorSeparatorColor, + timeSelectorSeparatorTextStyle, ]); @override @@ -414,7 +443,9 @@ class TimePickerThemeData with Diagnosticable { && other.hourMinuteTextStyle == hourMinuteTextStyle && other.inputDecorationTheme == inputDecorationTheme && other.padding == padding - && other.shape == shape; + && other.shape == shape + && other.timeSelectorSeparatorColor == timeSelectorSeparatorColor + && other.timeSelectorSeparatorTextStyle == timeSelectorSeparatorTextStyle; } @override @@ -442,6 +473,8 @@ class TimePickerThemeData with Diagnosticable { properties.add(DiagnosticsProperty('inputDecorationTheme', inputDecorationTheme, defaultValue: null)); properties.add(DiagnosticsProperty('padding', padding, defaultValue: null)); properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); + properties.add(DiagnosticsProperty>('timeSelectorSeparatorColor', timeSelectorSeparatorColor, defaultValue: null)); + properties.add(DiagnosticsProperty>('timeSelectorSeparatorTextStyle', timeSelectorSeparatorTextStyle, defaultValue: null)); } } diff --git a/packages/flutter/test/material/time_picker_test.dart b/packages/flutter/test/material/time_picker_test.dart index 3453e8586b..9a319e22be 100644 --- a/packages/flutter/test/material/time_picker_test.dart +++ b/packages/flutter/test/material/time_picker_test.dart @@ -1831,7 +1831,7 @@ void main() { final double minuteFieldTop = tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteTextField')).dy; final double separatorTop = - tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment')).dy; + tester.getTopLeft(find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator')).dy; expect(hourFieldTop, separatorTop); expect(minuteFieldTop, separatorTop); }); @@ -1965,6 +1965,32 @@ void main() { }); }); } + + testWidgets('Material3 - Time selector separator default text style', (WidgetTester tester) async { + final ThemeData theme = ThemeData(); + await startPicker( + tester, + (TimeOfDay? value) { }, + theme: theme, + ); + + final RenderParagraph paragraph = tester.renderObject(find.text(':')); + expect(paragraph.text.style!.color, theme.colorScheme.onSurface); + expect(paragraph.text.style!.fontSize, 57.0); + }); + + testWidgets('Material2 - Time selector separator default text style', (WidgetTester tester) async { + final ThemeData theme = ThemeData(useMaterial3: false); + await startPicker( + tester, + (TimeOfDay? value) { }, + theme: theme, + ); + + final RenderParagraph paragraph = tester.renderObject(find.text(':')); + expect(paragraph.text.style!.color, theme.colorScheme.onSurface); + expect(paragraph.text.style!.fontSize, 56.0); + }); } final Finder findDialPaint = find.descendant( @@ -2175,10 +2201,11 @@ Future startPicker( ValueChanged onChanged, { TimePickerEntryMode entryMode = TimePickerEntryMode.dial, String? restorationId, - required MaterialType materialType, + ThemeData? theme, + MaterialType? materialType, }) async { await tester.pumpWidget(MaterialApp( - theme: ThemeData(useMaterial3: materialType == MaterialType.material3), + theme: theme ?? ThemeData(useMaterial3: materialType == MaterialType.material3), restorationScopeId: 'app', locale: const Locale('en', 'US'), home: _TimePickerLauncher( diff --git a/packages/flutter/test/material/time_picker_theme_test.dart b/packages/flutter/test/material/time_picker_theme_test.dart index 18ea4b716f..22ae788eef 100644 --- a/packages/flutter/test/material/time_picker_theme_test.dart +++ b/packages/flutter/test/material/time_picker_theme_test.dart @@ -42,6 +42,8 @@ void main() { expect(timePickerTheme.entryModeIconColor, null); expect(timePickerTheme.padding, null); expect(timePickerTheme.shape, null); + expect(timePickerTheme.timeSelectorSeparatorColor, null); + expect(timePickerTheme.timeSelectorSeparatorTextStyle, null); }); testWidgets('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async { @@ -89,6 +91,8 @@ void main() { shape: RoundedRectangleBorder( side: BorderSide(color: Color(0xfffffff3)), ), + timeSelectorSeparatorColor: MaterialStatePropertyAll(Color(0xfffffff4)), + timeSelectorSeparatorTextStyle: MaterialStatePropertyAll(TextStyle(color: Color(0xfffffff5))), ).debugFillProperties(builder); final List description = builder.properties @@ -118,7 +122,9 @@ void main() { 'hourMinuteTextStyle: TextStyle(inherit: true, color: Color(0xfffffff1))', 'inputDecorationTheme: InputDecorationTheme#ff861(labelStyle: TextStyle(inherit: true, color: Color(0xfffffff2)))', 'padding: EdgeInsets.all(1.0)', - 'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)' + 'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)', + 'timeSelectorSeparatorColor: MaterialStatePropertyAll(Color(0xfffffff4))', + 'timeSelectorSeparatorTextStyle: MaterialStatePropertyAll(TextStyle(inherit: true, color: Color(0xfffffff5)))' ])); }); @@ -798,6 +804,38 @@ void main() { final Material pmMaterial = _textMaterial(tester, 'PM'); expect(pmMaterial.color, Colors.blue); }); + + testWidgets('Time selector separator color uses the timeSelectorSeparatorColor value', (WidgetTester tester) async { + final TimePickerThemeData timePickerTheme = _timePickerTheme().copyWith( + timeSelectorSeparatorColor: const MaterialStatePropertyAll(Color(0xff00ff00)) + ); + final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); + await tester.pumpWidget(_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final RenderParagraph paragraph = tester.renderObject(find.text(':')); + expect(paragraph.text.style!.color, const Color(0xff00ff00)); + }); + + testWidgets('Time selector separator text style uses the timeSelectorSeparatorTextStyle value', (WidgetTester tester) async { + final TimePickerThemeData timePickerTheme = _timePickerTheme().copyWith( + timeSelectorSeparatorTextStyle: const MaterialStatePropertyAll( + TextStyle( + fontSize: 35.0, + fontStyle: FontStyle.italic, + ), + ), + ); + final ThemeData theme = ThemeData(timePickerTheme: timePickerTheme); + await tester.pumpWidget(_TimePickerLauncher(themeData: theme, entryMode: TimePickerEntryMode.input)); + await tester.tap(find.text('X')); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + final RenderParagraph paragraph = tester.renderObject(find.text(':')); + expect(paragraph.text.style!.fontSize, 35.0); + expect(paragraph.text.style!.fontStyle, FontStyle.italic); + }); } final Color _selectedColor = Colors.green[100]!; diff --git a/packages/flutter_localizations/test/material/time_picker_test.dart b/packages/flutter_localizations/test/material/time_picker_test.dart index bed9af8f6a..573a054887 100644 --- a/packages/flutter_localizations/test/material/time_picker_test.dart +++ b/packages/flutter_localizations/test/material/time_picker_test.dart @@ -13,8 +13,8 @@ void main() { tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); - final Finder stringFragmentTextFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), + final Finder timeSelectorSeparatorFinder = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator'), matching: find.byType(Text), ).first; final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourControl'); @@ -33,10 +33,10 @@ void main() { for (final Locale locale in locales) { final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: false); - final Text stringFragmentText = tester.widget(stringFragmentTextFinder); + final Text stringFragmentText = tester.widget(timeSelectorSeparatorFinder); final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; - final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx; + final double stringFragmentLeftOffset = tester.getTopLeft(timeSelectorSeparatorFinder).dx; if (locale == const Locale('en', 'US')) { final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx; @@ -83,8 +83,8 @@ void main() { tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); - final Finder stringFragmentTextFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), + final Finder timeSelectorSeparatorFinder = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator'), matching: find.byType(Text), ).first; final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourControl'); @@ -103,10 +103,10 @@ void main() { for (final Locale locale in locales) { final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: true); - final Text stringFragmentText = tester.widget(stringFragmentTextFinder); + final Text stringFragmentText = tester.widget(timeSelectorSeparatorFinder); final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; - final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx; + final double stringFragmentLeftOffset = tester.getTopLeft(timeSelectorSeparatorFinder).dx; if (locale == const Locale('en', 'US')) { final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx; @@ -153,8 +153,8 @@ void main() { tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); - final Finder stringFragmentTextFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), + final Finder timeSelectorSeparatorFinder = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator'), matching: find.byType(Text), ).first; final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourControl'); @@ -173,11 +173,11 @@ void main() { for (final Locale locale in locales) { final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: false); - final Text stringFragmentText = tester.widget(stringFragmentTextFinder); + final Text stringFragmentText = tester.widget(timeSelectorSeparatorFinder); final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double hourTopOffset = tester.getTopLeft(hourControlFinder).dy; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; - final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx; + final double stringFragmentLeftOffset = tester.getTopLeft(timeSelectorSeparatorFinder).dx; if (locale == const Locale('en', 'US')) { final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx; @@ -228,8 +228,8 @@ void main() { tester.view.devicePixelRatio = 1; addTearDown(tester.view.reset); - final Finder stringFragmentTextFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), + final Finder timeSelectorSeparatorFinder = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator'), matching: find.byType(Text), ).first; final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourControl'); @@ -248,11 +248,11 @@ void main() { for (final Locale locale in locales) { final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale, useMaterial3: true); - final Text stringFragmentText = tester.widget(stringFragmentTextFinder); + final Text stringFragmentText = tester.widget(timeSelectorSeparatorFinder); final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double hourTopOffset = tester.getTopLeft(hourControlFinder).dy; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; - final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx; + final double stringFragmentLeftOffset = tester.getTopLeft(timeSelectorSeparatorFinder).dx; if (locale == const Locale('en', 'US')) { final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx; @@ -301,8 +301,8 @@ void main() { final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourTextField'); final Finder minuteControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteTextField'); final Finder dayPeriodControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'); - final Finder stringFragmentTextFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), + final Finder timeSelectorSeparatorFinder = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator'), matching: find.byType(Text), ).first; @@ -321,10 +321,10 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); - final Text stringFragmentText = tester.widget(stringFragmentTextFinder); + final Text stringFragmentText = tester.widget(timeSelectorSeparatorFinder); final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; - final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx; + final double stringFragmentLeftOffset = tester.getTopLeft(timeSelectorSeparatorFinder).dx; if (locale == const Locale('en', 'US')) { final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx; @@ -369,8 +369,8 @@ void main() { final Finder hourControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_HourTextField'); final Finder minuteControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_MinuteTextField'); final Finder dayPeriodControlFinder = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DayPeriodControl'); - final Finder stringFragmentTextFinder = find.descendant( - of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_StringFragment'), + final Finder timeSelectorSeparatorFinder = find.descendant( + of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TimeSelectorSeparator'), matching: find.byType(Text), ).first; @@ -389,10 +389,10 @@ void main() { await tester.tap(find.text('X')); await tester.pumpAndSettle(const Duration(seconds: 1)); - final Text stringFragmentText = tester.widget(stringFragmentTextFinder); + final Text stringFragmentText = tester.widget(timeSelectorSeparatorFinder); final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; - final double stringFragmentLeftOffset = tester.getTopLeft(stringFragmentTextFinder).dx; + final double stringFragmentLeftOffset = tester.getTopLeft(timeSelectorSeparatorFinder).dx; if (locale == const Locale('en', 'US')) { final double dayPeriodLeftOffset = tester.getTopLeft(dayPeriodControlFinder).dx;