Skip to content

Commit a290a7f

Browse files
committed
feat: sub header style with DatePickerTheme
- Add properties to DatePickerThemeData: - `toggleButtonTextStyle` allow customization on _DatePickerModeToggleButton TextStyle; - `subHeaderForegroundColor` allow changing the color of both button and Icons with consistency; - Compatible with existing code by the use of defaults; - Adjust test to cover new properties Ref #163866 Ref #160591
1 parent fd168e1 commit a290a7f

File tree

4 files changed

+153
-12
lines changed

4 files changed

+153
-12
lines changed

dev/tools/gen_defaults/lib/date_picker_template.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ class _${blockName}DefaultsM3 extends DatePickerThemeData {
6262
@override
6363
Color? get backgroundColor => ${componentColor("md.comp.date-picker.modal.container")};
6464
65+
@override
66+
Color? get subHeaderForegroundColor => ${componentColor("md.comp.date-picker.modal.weekdays.label-text")}.withOpacity(0.60);
67+
68+
@override
69+
TextStyle? get toggleButtonTextStyle => ${textStyle("md.comp.date-picker.modal.range-selection.month.subhead")}?.apply(
70+
color: subHeaderForegroundColor,
71+
);
72+
6573
@override
6674
ButtonStyle get cancelButtonStyle {
6775
return TextButton.styleFrom();

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import 'package:flutter/rendering.dart';
1313
import 'package:flutter/services.dart';
1414
import 'package:flutter/widgets.dart';
1515

16-
import 'color_scheme.dart';
1716
import 'date.dart';
1817
import 'date_picker_theme.dart';
1918
import 'debug.dart';
@@ -24,7 +23,6 @@ import 'ink_decoration.dart';
2423
import 'ink_well.dart';
2524
import 'material_localizations.dart';
2625
import 'material_state.dart';
27-
import 'text_theme.dart';
2826
import 'theme.dart';
2927

3028
const Duration _monthScrollDuration = Duration(milliseconds: 200);
@@ -450,9 +448,16 @@ class _DatePickerModeToggleButtonState extends State<_DatePickerModeToggleButton
450448

451449
@override
452450
Widget build(BuildContext context) {
453-
final ColorScheme colorScheme = Theme.of(context).colorScheme;
454-
final TextTheme textTheme = Theme.of(context).textTheme;
455-
final Color controlColor = colorScheme.onSurface.withOpacity(0.60);
451+
final DatePickerThemeData datePickerTheme = DatePickerTheme.of(context);
452+
final DatePickerThemeData defaults = DatePickerTheme.defaults(context);
453+
final TextStyle? buttonTextStyle =
454+
datePickerTheme.toggleButtonTextStyle ?? defaults.toggleButtonTextStyle;
455+
final Color? subHeaderForegroundColor =
456+
datePickerTheme.subHeaderForegroundColor ?? defaults.subHeaderForegroundColor;
457+
final Color? buttonTextColor =
458+
datePickerTheme.toggleButtonTextStyle?.color ??
459+
datePickerTheme.subHeaderForegroundColor ??
460+
defaults.toggleButtonTextStyle?.color;
456461

457462
return SizedBox(
458463
height: _subHeaderHeight,
@@ -477,12 +482,12 @@ class _DatePickerModeToggleButtonState extends State<_DatePickerModeToggleButton
477482
child: Text(
478483
widget.title,
479484
overflow: TextOverflow.ellipsis,
480-
style: textTheme.titleSmall?.copyWith(color: controlColor),
485+
style: buttonTextStyle?.apply(color: buttonTextColor),
481486
),
482487
),
483488
RotationTransition(
484489
turns: _controller,
485-
child: Icon(Icons.arrow_drop_down, color: controlColor),
490+
child: Icon(Icons.arrow_drop_down, color: subHeaderForegroundColor),
486491
),
487492
],
488493
),
@@ -826,7 +831,9 @@ class _MonthPickerState extends State<_MonthPicker> {
826831

827832
@override
828833
Widget build(BuildContext context) {
829-
final Color controlColor = Theme.of(context).colorScheme.onSurface.withOpacity(0.60);
834+
final Color? subHeaderForegroundColor =
835+
DatePickerTheme.of(context).subHeaderForegroundColor ??
836+
DatePickerTheme.defaults(context).subHeaderForegroundColor;
830837

831838
return Semantics(
832839
container: true,
@@ -842,13 +849,13 @@ class _MonthPickerState extends State<_MonthPicker> {
842849
const Spacer(),
843850
IconButton(
844851
icon: const Icon(Icons.chevron_left),
845-
color: controlColor,
852+
color: subHeaderForegroundColor,
846853
tooltip: _isDisplayingFirstMonth ? null : _localizations.previousMonthTooltip,
847854
onPressed: _isDisplayingFirstMonth ? null : _handlePreviousMonth,
848855
),
849856
IconButton(
850857
icon: const Icon(Icons.chevron_right),
851-
color: controlColor,
858+
color: subHeaderForegroundColor,
852859
tooltip: _isDisplayingLastMonth ? null : _localizations.nextMonthTooltip,
853860
onPressed: _isDisplayingLastMonth ? null : _handleNextMonth,
854861
),

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

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ class DatePickerThemeData with Diagnosticable {
8484
this.cancelButtonStyle,
8585
this.confirmButtonStyle,
8686
this.locale,
87+
this.toggleButtonTextStyle,
88+
this.subHeaderForegroundColor,
8789
});
8890

8991
/// Overrides the default value of [Dialog.backgroundColor].
@@ -360,6 +362,16 @@ class DatePickerThemeData with Diagnosticable {
360362
/// picker. It defaults to the ambient locale provided by [Localizations].
361363
final Locale? locale;
362364

365+
/// Overrides the default text style used for the text of toggle mode button
366+
///
367+
/// If no [TextStyle.color] is given, [subHeaderForegroundColor] will be used.
368+
final TextStyle? toggleButtonTextStyle;
369+
370+
/// Overrides the default color used for text labels and icons of sub header foreground.
371+
///
372+
/// This is used in [TextStyle.color] property of [toggleButtonTextStyle] if no color is given.
373+
final Color? subHeaderForegroundColor;
374+
363375
/// Creates a copy of this object with the given fields replaced with the
364376
/// new values.
365377
DatePickerThemeData copyWith({
@@ -401,6 +413,8 @@ class DatePickerThemeData with Diagnosticable {
401413
ButtonStyle? cancelButtonStyle,
402414
ButtonStyle? confirmButtonStyle,
403415
Locale? locale,
416+
TextStyle? toggleButtonTextStyle,
417+
Color? subHeaderForegroundColor,
404418
}) {
405419
return DatePickerThemeData(
406420
backgroundColor: backgroundColor ?? this.backgroundColor,
@@ -445,6 +459,8 @@ class DatePickerThemeData with Diagnosticable {
445459
cancelButtonStyle: cancelButtonStyle ?? this.cancelButtonStyle,
446460
confirmButtonStyle: confirmButtonStyle ?? this.confirmButtonStyle,
447461
locale: locale ?? this.locale,
462+
toggleButtonTextStyle: toggleButtonTextStyle ?? this.toggleButtonTextStyle,
463+
subHeaderForegroundColor: subHeaderForegroundColor ?? this.subHeaderForegroundColor,
448464
);
449465
}
450466

@@ -570,6 +586,12 @@ class DatePickerThemeData with Diagnosticable {
570586
cancelButtonStyle: ButtonStyle.lerp(a?.cancelButtonStyle, b?.cancelButtonStyle, t),
571587
confirmButtonStyle: ButtonStyle.lerp(a?.confirmButtonStyle, b?.confirmButtonStyle, t),
572588
locale: t < 0.5 ? a?.locale : b?.locale,
589+
toggleButtonTextStyle: TextStyle.lerp(a?.toggleButtonTextStyle, b?.toggleButtonTextStyle, t),
590+
subHeaderForegroundColor: Color.lerp(
591+
a?.subHeaderForegroundColor,
592+
b?.subHeaderForegroundColor,
593+
t,
594+
),
573595
);
574596
}
575597

@@ -623,6 +645,8 @@ class DatePickerThemeData with Diagnosticable {
623645
cancelButtonStyle,
624646
confirmButtonStyle,
625647
locale,
648+
toggleButtonTextStyle,
649+
subHeaderForegroundColor,
626650
]);
627651

628652
@override
@@ -668,7 +692,9 @@ class DatePickerThemeData with Diagnosticable {
668692
other.inputDecorationTheme == inputDecorationTheme &&
669693
other.cancelButtonStyle == cancelButtonStyle &&
670694
other.confirmButtonStyle == confirmButtonStyle &&
671-
other.locale == locale;
695+
other.locale == locale &&
696+
other.toggleButtonTextStyle == toggleButtonTextStyle &&
697+
other.subHeaderForegroundColor == subHeaderForegroundColor;
672698
}
673699

674700
@override
@@ -842,6 +868,16 @@ class DatePickerThemeData with Diagnosticable {
842868
),
843869
);
844870
properties.add(DiagnosticsProperty<Locale>('locale', locale, defaultValue: null));
871+
properties.add(
872+
DiagnosticsProperty<TextStyle>(
873+
'toggleButtonTextStyle',
874+
toggleButtonTextStyle,
875+
defaultValue: null,
876+
),
877+
);
878+
properties.add(
879+
ColorProperty('subHeaderForegroundColor', subHeaderForegroundColor, defaultValue: null),
880+
);
845881
}
846882
}
847883

@@ -957,6 +993,13 @@ class _DatePickerDefaultsM2 extends DatePickerThemeData {
957993
@override
958994
Color? get headerBackgroundColor => _isDark ? _colors.surface : _colors.primary;
959995

996+
@override
997+
Color? get subHeaderForegroundColor => _colors.onSurface.withOpacity(0.60);
998+
999+
@override
1000+
TextStyle? get toggleButtonTextStyle =>
1001+
_textTheme.titleSmall?.apply(color: subHeaderForegroundColor);
1002+
9601003
@override
9611004
ButtonStyle get cancelButtonStyle {
9621005
return TextButton.styleFrom();
@@ -1101,7 +1144,6 @@ class _DatePickerDefaultsM2 extends DatePickerThemeData {
11011144
return null;
11021145
});
11031146
}
1104-
11051147
// BEGIN GENERATED TOKEN PROPERTIES - DatePicker
11061148

11071149
// Do not edit by hand. The code between the "BEGIN GENERATED" and
@@ -1130,6 +1172,14 @@ class _DatePickerDefaultsM3 extends DatePickerThemeData {
11301172
@override
11311173
Color? get backgroundColor => _colors.surfaceContainerHigh;
11321174

1175+
@override
1176+
Color? get subHeaderForegroundColor => _colors.onSurface.withOpacity(0.60);
1177+
1178+
@override
1179+
TextStyle? get toggleButtonTextStyle => _textTheme.titleSmall?.apply(
1180+
color: subHeaderForegroundColor,
1181+
);
1182+
11331183
@override
11341184
ButtonStyle get cancelButtonStyle {
11351185
return TextButton.styleFrom();

packages/flutter/test/material/date_picker_theme_test.dart

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ void main() {
5555
foregroundColor: MaterialStatePropertyAll<Color>(Color(0xffffff7f)),
5656
),
5757
locale: Locale('en'),
58+
subHeaderForegroundColor: Color(0xffffff8f),
59+
toggleButtonTextStyle: TextStyle(fontSize: 13),
5860
);
5961

6062
Material findDialogMaterial(WidgetTester tester) {
@@ -140,6 +142,8 @@ void main() {
140142
expect(theme.cancelButtonStyle, null);
141143
expect(theme.confirmButtonStyle, null);
142144
expect(theme.locale, null);
145+
expect(theme.subHeaderForegroundColor, null);
146+
expect(theme.toggleButtonTextStyle, null);
143147
});
144148

145149
testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
@@ -295,6 +299,11 @@ void main() {
295299
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
296300
);
297301
expect(m3.locale, null);
302+
expect(m3.subHeaderForegroundColor, colorScheme.onSurface.withOpacity(0.60));
303+
expect(
304+
m3.toggleButtonTextStyle,
305+
textTheme.titleSmall?.apply(color: m3.subHeaderForegroundColor),
306+
);
298307
});
299308

300309
testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
@@ -449,6 +458,11 @@ void main() {
449458
equalsIgnoringHashCodes(TextButton.styleFrom().toString()),
450459
);
451460
expect(m2.locale, null);
461+
expect(m2.subHeaderForegroundColor, colorScheme.onSurface.withOpacity(0.60));
462+
expect(
463+
m2.toggleButtonTextStyle,
464+
textTheme.titleSmall?.apply(color: m2.subHeaderForegroundColor),
465+
);
452466
});
453467

454468
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
@@ -516,6 +530,8 @@ void main() {
516530
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(${const Color(0xffffff6f)}))',
517531
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: WidgetStatePropertyAll(${const Color(0xffffff7f)}))',
518532
'locale: en',
533+
'toggleButtonTextStyle: TextStyle(inherit: true, size: 13.0)',
534+
'subHeaderForegroundColor: ${const Color(0xffffff8f)}',
519535
]),
520536
);
521537
});
@@ -588,6 +604,13 @@ void main() {
588604
);
589605
expect(day24Shape.side.width, datePickerTheme.todayBorder?.width);
590606

607+
// Test the toggle mode button
608+
final Text january2023 = tester.widget<Text>(find.text('January 2023'));
609+
expect(january2023.style?.fontSize, datePickerTheme.toggleButtonTextStyle?.fontSize);
610+
expect(january2023.style?.color, datePickerTheme.subHeaderForegroundColor);
611+
final Icon arrowIcon = tester.widget<Icon>(find.byIcon(Icons.arrow_drop_down));
612+
expect(arrowIcon.color, datePickerTheme.subHeaderForegroundColor);
613+
591614
// Test the day overlay color.
592615
final RenderObject inkFeatures = tester.allRenderObjects.firstWhere(
593616
(RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures',
@@ -1206,4 +1229,57 @@ void main() {
12061229
);
12071230
}
12081231
});
1232+
1233+
testWidgets('Toggle button uses DatePickerTheme.toggleButtonTextStyle.color when it is defined', (
1234+
WidgetTester tester,
1235+
) async {
1236+
const Color toggleButtonTextColor = Color(0xff00ff00);
1237+
const Color subHeaderForegroundColor = Color(0xffff0000);
1238+
1239+
await tester.pumpWidget(
1240+
MaterialApp(
1241+
theme: ThemeData(
1242+
datePickerTheme: const DatePickerThemeData(
1243+
toggleButtonTextStyle: TextStyle(color: toggleButtonTextColor),
1244+
subHeaderForegroundColor: subHeaderForegroundColor,
1245+
),
1246+
),
1247+
home: DatePickerDialog(
1248+
initialDate: DateTime(2023, DateTime.january, 25),
1249+
firstDate: DateTime(2022),
1250+
lastDate: DateTime(2024, DateTime.december, 31),
1251+
currentDate: DateTime(2023, DateTime.january, 24),
1252+
),
1253+
),
1254+
);
1255+
1256+
final Text toggleButtonText = tester.widget(find.text('January 2023'));
1257+
expect(toggleButtonText.style?.color, toggleButtonTextColor);
1258+
});
1259+
1260+
testWidgets('Toggle button uses DatePickerTheme.subHeaderForegroundColor when DatePickerTheme.toggleButtonTextStyle.color is not defined', (
1261+
WidgetTester tester,
1262+
) async {
1263+
const Color subHeaderForegroundColor = Color(0xffff0000);
1264+
1265+
await tester.pumpWidget(
1266+
MaterialApp(
1267+
theme: ThemeData(
1268+
datePickerTheme: const DatePickerThemeData(
1269+
toggleButtonTextStyle: TextStyle(),
1270+
subHeaderForegroundColor: subHeaderForegroundColor,
1271+
),
1272+
),
1273+
home: DatePickerDialog(
1274+
initialDate: DateTime(2023, DateTime.january, 25),
1275+
firstDate: DateTime(2022),
1276+
lastDate: DateTime(2024, DateTime.december, 31),
1277+
currentDate: DateTime(2023, DateTime.january, 24),
1278+
),
1279+
),
1280+
);
1281+
1282+
final Text toggleButtonText = tester.widget(find.text('January 2023'));
1283+
expect(toggleButtonText.style?.color, subHeaderForegroundColor);
1284+
});
12091285
}

0 commit comments

Comments
 (0)