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  ### Code sample <details> <summary>expand to view the code sample</summary> ```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'), ); }), ), ), ); } } ``` </details> | Before | After | | --------------- | --------------- | | <img src="https://github.com/flutter/flutter/assets/48603081/20beeba4-5cc2-49ee-bba8-1c552c0d1e44" /> | <img src="https://github.com/flutter/flutter/assets/48603081/24927187-aff7-4191-930c-bceab6a4b4c2" /> |
This commit is contained in:
parent
f923375654
commit
95cdebedae
@ -333,6 +333,20 @@ class _${blockName}DefaultsM3 extends _TimePickerDefaults {
|
||||
ShapeBorder get shape {
|
||||
return ${shape("$tokenGroup.container")};
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<Color?>? get timeSelectorSeparatorColor {
|
||||
// TODO(tahatesser): Update this when tokens are available.
|
||||
// This is taken from https://m3.material.io/components/time-pickers/specs.
|
||||
return MaterialStatePropertyAll<Color>(_colors.onSurface);
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<TextStyle?>? get timeSelectorSeparatorTextStyle {
|
||||
// TODO(tahatesser): Update this when tokens are available.
|
||||
// This is taken from https://m3.material.io/components/time-pickers/specs.
|
||||
return MaterialStatePropertyAll<TextStyle?>(_textTheme.displayLarge);
|
||||
}
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ class _TimePickerHeader extends StatelessWidget {
|
||||
textDirection: TextDirection.ltr,
|
||||
children: <Widget>[
|
||||
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: <Widget>[
|
||||
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<MaterialState> states = <MaterialState>{};
|
||||
|
||||
final Color effectiveTextColor = MaterialStateProperty.resolveAs<Color>(
|
||||
timePickerTheme.hourMinuteTextColor ?? defaultTheme.hourMinuteTextColor,
|
||||
timePickerTheme.timeSelectorSeparatorColor?.resolve(states)
|
||||
?? timePickerTheme.hourMinuteTextColor
|
||||
?? defaultTheme.timeSelectorSeparatorColor?.resolve(states)
|
||||
?? defaultTheme.hourMinuteTextColor,
|
||||
states,
|
||||
);
|
||||
final TextStyle effectiveStyle = MaterialStateProperty.resolveAs<TextStyle>(
|
||||
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<Color?>? get timeSelectorSeparatorColor {
|
||||
// TODO(tahatesser): Update this when tokens are available.
|
||||
// This is taken from https://m3.material.io/components/time-pickers/specs.
|
||||
return MaterialStatePropertyAll<Color>(_colors.onSurface);
|
||||
}
|
||||
|
||||
@override
|
||||
MaterialStateProperty<TextStyle?>? get timeSelectorSeparatorTextStyle {
|
||||
// TODO(tahatesser): Update this when tokens are available.
|
||||
// This is taken from https://m3.material.io/components/time-pickers/specs.
|
||||
return MaterialStatePropertyAll<TextStyle?>(_textTheme.displayLarge);
|
||||
}
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - TimePicker
|
||||
|
@ -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<Color?>? 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<TextStyle?>? 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<Color?>? timeSelectorSeparatorColor,
|
||||
MaterialStateProperty<TextStyle?>? 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<Color?>(a?.timeSelectorSeparatorColor, b?.timeSelectorSeparatorColor, t, Color.lerp),
|
||||
timeSelectorSeparatorTextStyle: MaterialStateProperty.lerp<TextStyle?>(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', inputDecorationTheme, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('timeSelectorSeparatorColor', timeSelectorSeparatorColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<MaterialStateProperty<TextStyle?>>('timeSelectorSeparatorTextStyle', timeSelectorSeparatorTextStyle, defaultValue: null));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Offset?> startPicker(
|
||||
ValueChanged<TimeOfDay?> 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(
|
||||
|
@ -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>(Color(0xfffffff4)),
|
||||
timeSelectorSeparatorTextStyle: MaterialStatePropertyAll<TextStyle>(TextStyle(color: Color(0xfffffff5))),
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> 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>(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>(
|
||||
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]!;
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user