Skip to content

Commit d7a3a68

Browse files
authored
Fix cancelButtonStyle & confirmButtonStyle properties from TimePickerTheme aren't working (#132843)
fixes [`TimePickerThemeData` action buttons styles aren't working](flutter/flutter#132760) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @OverRide Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, timePickerTheme: TimePickerThemeData( cancelButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4)), side: BorderSide(color: Colors.red), ), backgroundColor: Colors.white, foregroundColor: Colors.red, elevation: 3, shadowColor: Colors.red, ), confirmButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4)), ), backgroundColor: Colors.green[700], foregroundColor: Colors.white, elevation: 3, shadowColor: Colors.green[700], ), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @OverRide Widget build(BuildContext context) { return Scaffold( body: Center( child: TimePickerDialog(initialTime: TimeOfDay.now()), ), ); } } ``` </details> ### Before (action buttons don't use the style from the `TimePickerTheme`) ![Screenshot 2023-08-18 at 14 57 37](https://github.com/flutter/flutter/assets/48603081/c95160e2-76a2-4bb5-84e0-3731fce19c0b) ### After (action buttons use the style from the `TimePickerTheme`) ![Screenshot 2023-08-18 at 14 57 18](https://github.com/flutter/flutter/assets/48603081/422d348a-bee2-4696-8d9a-5fce56191aaa)
1 parent 336d60d commit d7a3a68

File tree

3 files changed

+114
-44
lines changed

3 files changed

+114
-44
lines changed

packages/flutter/lib/src/material/time_picker.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,13 +2384,15 @@ class _TimePickerDialogState extends State<TimePickerDialog> with RestorationMix
23842384
overflowAlignment: OverflowBarAlignment.end,
23852385
children: <Widget>[
23862386
TextButton(
2387+
style: pickerTheme.cancelButtonStyle ?? defaultTheme.cancelButtonStyle,
23872388
onPressed: _handleCancel,
23882389
child: Text(widget.cancelText ??
23892390
(theme.useMaterial3
23902391
? localizations.cancelButtonLabel
23912392
: localizations.cancelButtonLabel.toUpperCase())),
23922393
),
23932394
TextButton(
2395+
style: pickerTheme.confirmButtonStyle ?? defaultTheme.confirmButtonStyle,
23942396
onPressed: _handleOk,
23952397
child: Text(widget.confirmText ?? localizations.okButtonLabel),
23962398
),

packages/flutter/lib/src/material/time_picker_theme.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class TimePickerThemeData with Diagnosticable {
7272
/// The style of the cancel button of a [TimePickerDialog].
7373
final ButtonStyle? cancelButtonStyle;
7474

75-
/// The style of the conform (OK) button of a [TimePickerDialog].
75+
/// The style of the confirm (OK) button of a [TimePickerDialog].
7676
final ButtonStyle? confirmButtonStyle;
7777

7878
/// The color and weight of the day period's outline.

packages/flutter/test/material/time_picker_theme_test.dart

Lines changed: 111 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,28 @@ void main() {
2020
test('TimePickerThemeData null fields by default', () {
2121
const TimePickerThemeData timePickerTheme = TimePickerThemeData();
2222
expect(timePickerTheme.backgroundColor, null);
23-
expect(timePickerTheme.hourMinuteTextColor, null);
24-
expect(timePickerTheme.hourMinuteColor, null);
25-
expect(timePickerTheme.dayPeriodTextColor, null);
23+
expect(timePickerTheme.cancelButtonStyle, null);
24+
expect(timePickerTheme.confirmButtonStyle, null);
25+
expect(timePickerTheme.dayPeriodBorderSide, null);
2626
expect(timePickerTheme.dayPeriodColor, null);
27-
expect(timePickerTheme.dialHandColor, null);
27+
expect(timePickerTheme.dayPeriodShape, null);
28+
expect(timePickerTheme.dayPeriodTextColor, null);
29+
expect(timePickerTheme.dayPeriodTextStyle, null);
2830
expect(timePickerTheme.dialBackgroundColor, null);
31+
expect(timePickerTheme.dialHandColor, null);
2932
expect(timePickerTheme.dialTextColor, null);
33+
expect(timePickerTheme.dialTextStyle, null);
34+
expect(timePickerTheme.elevation, null);
3035
expect(timePickerTheme.entryModeIconColor, null);
31-
expect(timePickerTheme.hourMinuteTextStyle, null);
32-
expect(timePickerTheme.dayPeriodTextStyle, null);
3336
expect(timePickerTheme.helpTextStyle, null);
34-
expect(timePickerTheme.shape, null);
37+
expect(timePickerTheme.hourMinuteColor, null);
3538
expect(timePickerTheme.hourMinuteShape, null);
36-
expect(timePickerTheme.dayPeriodShape, null);
37-
expect(timePickerTheme.dayPeriodBorderSide, null);
39+
expect(timePickerTheme.hourMinuteTextColor, null);
40+
expect(timePickerTheme.hourMinuteTextStyle, null);
3841
expect(timePickerTheme.inputDecorationTheme, null);
42+
expect(timePickerTheme.entryModeIconColor, null);
43+
expect(timePickerTheme.padding, null);
44+
expect(timePickerTheme.shape, null);
3945
});
4046

4147
testWidgets('Default TimePickerThemeData debugFillProperties', (WidgetTester tester) async {
@@ -53,47 +59,67 @@ void main() {
5359
testWidgets('TimePickerThemeData implements debugFillProperties', (WidgetTester tester) async {
5460
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
5561
const TimePickerThemeData(
56-
backgroundColor: Color(0xFFFFFFFF),
57-
hourMinuteTextColor: Color(0xFFFFFFFF),
58-
hourMinuteColor: Color(0xFFFFFFFF),
59-
dayPeriodTextColor: Color(0xFFFFFFFF),
60-
dayPeriodColor: Color(0xFFFFFFFF),
61-
dialHandColor: Color(0xFFFFFFFF),
62-
dialBackgroundColor: Color(0xFFFFFFFF),
63-
dialTextColor: Color(0xFFFFFFFF),
64-
entryModeIconColor: Color(0xFFFFFFFF),
65-
hourMinuteTextStyle: TextStyle(),
66-
dayPeriodTextStyle: TextStyle(),
67-
helpTextStyle: TextStyle(),
68-
shape: RoundedRectangleBorder(),
69-
hourMinuteShape: RoundedRectangleBorder(),
70-
dayPeriodShape: RoundedRectangleBorder(),
71-
dayPeriodBorderSide: BorderSide(),
62+
backgroundColor: Color(0xfffffff0),
63+
cancelButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff1))),
64+
confirmButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll<Color>(Color(0xfffffff2))),
65+
dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3)),
66+
dayPeriodColor: Color(0xfffffff4),
67+
dayPeriodShape: RoundedRectangleBorder(
68+
side: BorderSide(color: Color(0xfffffff5)),
69+
),
70+
dayPeriodTextColor: Color(0xfffffff6),
71+
dayPeriodTextStyle: TextStyle(color: Color(0xfffffff7)),
72+
dialBackgroundColor: Color(0xfffffff8),
73+
dialHandColor: Color(0xfffffff9),
74+
dialTextColor: Color(0xfffffffa),
75+
dialTextStyle: TextStyle(color: Color(0xfffffffb)),
76+
elevation: 1.0,
77+
entryModeIconColor: Color(0xfffffffc),
78+
helpTextStyle: TextStyle(color: Color(0xfffffffd)),
79+
hourMinuteColor: Color(0xfffffffe),
80+
hourMinuteShape: RoundedRectangleBorder(
81+
side: BorderSide(color: Color(0xffffffff)),
82+
),
83+
hourMinuteTextColor: Color(0xfffffff0),
84+
hourMinuteTextStyle: TextStyle(color: Color(0xfffffff1)),
85+
inputDecorationTheme: InputDecorationTheme(
86+
labelStyle: TextStyle(color: Color(0xfffffff2)),
87+
),
88+
padding: EdgeInsets.all(1.0),
89+
shape: RoundedRectangleBorder(
90+
side: BorderSide(color: Color(0xfffffff3)),
91+
),
7292
).debugFillProperties(builder);
7393

7494
final List<String> description = builder.properties
7595
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
7696
.map((DiagnosticsNode node) => node.toString())
7797
.toList();
7898

79-
expect(description, <String>[
80-
'backgroundColor: Color(0xffffffff)',
81-
'dayPeriodBorderSide: BorderSide',
82-
'dayPeriodColor: Color(0xffffffff)',
83-
'dayPeriodShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)',
84-
'dayPeriodTextColor: Color(0xffffffff)',
85-
'dayPeriodTextStyle: TextStyle(<all styles inherited>)',
86-
'dialBackgroundColor: Color(0xffffffff)',
87-
'dialHandColor: Color(0xffffffff)',
88-
'dialTextColor: Color(0xffffffff)',
89-
'entryModeIconColor: Color(0xffffffff)',
90-
'helpTextStyle: TextStyle(<all styles inherited>)',
91-
'hourMinuteColor: Color(0xffffffff)',
92-
'hourMinuteShape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)',
93-
'hourMinuteTextColor: Color(0xffffffff)',
94-
'hourMinuteTextStyle: TextStyle(<all styles inherited>)',
95-
'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.zero)'
96-
]);
99+
expect(description, equalsIgnoringHashCodes(<String>[
100+
'backgroundColor: Color(0xfffffff0)',
101+
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff1)))',
102+
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xfffffff2)))',
103+
'dayPeriodBorderSide: BorderSide(color: Color(0xfffffff3))',
104+
'dayPeriodColor: Color(0xfffffff4)',
105+
'dayPeriodShape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff5)), BorderRadius.zero)',
106+
'dayPeriodTextColor: Color(0xfffffff6)',
107+
'dayPeriodTextStyle: TextStyle(inherit: true, color: Color(0xfffffff7))',
108+
'dialBackgroundColor: Color(0xfffffff8)',
109+
'dialHandColor: Color(0xfffffff9)',
110+
'dialTextColor: Color(0xfffffffa)',
111+
'dialTextStyle: TextStyle(inherit: true, color: Color(0xfffffffb))',
112+
'elevation: 1.0',
113+
'entryModeIconColor: Color(0xfffffffc)',
114+
'helpTextStyle: TextStyle(inherit: true, color: Color(0xfffffffd))',
115+
'hourMinuteColor: Color(0xfffffffe)',
116+
'hourMinuteShape: RoundedRectangleBorder(BorderSide(color: Color(0xffffffff)), BorderRadius.zero)',
117+
'hourMinuteTextColor: Color(0xfffffff0)',
118+
'hourMinuteTextStyle: TextStyle(inherit: true, color: Color(0xfffffff1))',
119+
'inputDecorationTheme: InputDecorationTheme#ff861(labelStyle: TextStyle(inherit: true, color: Color(0xfffffff2)))',
120+
'padding: EdgeInsets.all(1.0)',
121+
'shape: RoundedRectangleBorder(BorderSide(color: Color(0xfffffff3)), BorderRadius.zero)'
122+
]));
97123
});
98124

99125
testWidgets('Material2 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async {
@@ -221,6 +247,12 @@ void main() {
221247
entryModeIconButton.color,
222248
defaultTheme.colorScheme.onSurface.withOpacity(0.6),
223249
);
250+
251+
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL');
252+
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
253+
254+
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
255+
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
224256
});
225257

226258
testWidgets('Material3 - Passing no TimePickerThemeData uses defaults', (WidgetTester tester) async {
@@ -363,6 +395,12 @@ void main() {
363395

364396
final IconButton entryModeIconButton = _entryModeIconButton(tester);
365397
expect(entryModeIconButton.color, null);
398+
399+
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel');
400+
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
401+
402+
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
403+
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
366404
});
367405

368406
testWidgets('Material2 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async {
@@ -399,6 +437,12 @@ void main() {
399437
Typography.material2014().englishLike.displayMedium!
400438
.merge(defaultTheme.textTheme.displayMedium!.copyWith(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36)))
401439
);
440+
441+
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL');
442+
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
443+
444+
final ButtonStyle confirmButtonStyle= _actionButtonStyle(tester, 'OK');
445+
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
402446
});
403447

404448
testWidgets('Material3 - Passing no TimePickerThemeData uses defaults - input mode', (WidgetTester tester) async {
@@ -438,6 +482,12 @@ void main() {
438482
hourDecoration.hintStyle,
439483
TextStyle(color: defaultTheme.colorScheme.onSurface.withOpacity(0.36))
440484
);
485+
486+
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel');
487+
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
488+
489+
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
490+
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
441491
});
442492

443493
testWidgets('Material2 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async {
@@ -555,6 +605,12 @@ void main() {
555605
entryModeIconButton.color,
556606
timePickerTheme.entryModeIconColor,
557607
);
608+
609+
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'CANCEL');
610+
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.cancelButtonStyle.toString()));
611+
612+
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
613+
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString()));
558614
});
559615

560616
testWidgets('Material3 - Time picker uses values from TimePickerThemeData', (WidgetTester tester) async {
@@ -672,6 +728,12 @@ void main() {
672728

673729
final IconButton entryModeIconButton = _entryModeIconButton(tester);
674730
expect(entryModeIconButton.color, null);
731+
732+
final ButtonStyle cancelButtonStyle = _actionButtonStyle(tester, 'Cancel');
733+
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.cancelButtonStyle.toString()));
734+
735+
final ButtonStyle confirmButtonStyle = _actionButtonStyle(tester, 'OK');
736+
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(timePickerTheme.confirmButtonStyle.toString()));
675737
});
676738

677739
testWidgets('Time picker uses values from TimePickerThemeData with InputDecorationTheme - input mode', (WidgetTester tester) async {
@@ -713,6 +775,8 @@ TimePickerThemeData _timePickerTheme({bool includeInputDecoration = false}) {
713775
final MaterialStateColor materialStateColor = MaterialStateColor.resolveWith(getColor);
714776
return TimePickerThemeData(
715777
backgroundColor: Colors.orange,
778+
cancelButtonStyle: TextButton.styleFrom(primary: Colors.red),
779+
confirmButtonStyle: TextButton.styleFrom(primary: Colors.green),
716780
hourMinuteTextColor: materialStateColor,
717781
hourMinuteColor: materialStateColor,
718782
dayPeriodTextColor: materialStateColor,
@@ -807,3 +871,7 @@ final Finder findDialPaint = find.descendant(
807871
of: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_Dial'),
808872
matching: find.byWidgetPredicate((Widget w) => w is CustomPaint),
809873
);
874+
875+
ButtonStyle _actionButtonStyle(WidgetTester tester, String text) {
876+
return tester.widget<TextButton>(find.widgetWithText(TextButton, text)).style!;
877+
}

0 commit comments

Comments
 (0)