From 99b245faea0107a0d448fe52881a2f1758d481fa Mon Sep 17 00:00:00 2001 From: Massinissa Mouhoub Date: Sun, 30 Aug 2026 23:28:30 +0100 Subject: [PATCH] fix: respect todayBorder color over todayForegroundColor in YearPicker --- .../lib/src/calendar_date_picker.dart | 9 ++- .../lib/src/date_picker_theme.dart | 4 +- ...e_2026_08_30_year_picker_today_border.yaml | 3 + .../test/calendar_date_picker_test.dart | 80 +++++++++++++++++++ 4 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 packages/material_ui/pending_changelogs/change_2026_08_30_year_picker_today_border.yaml diff --git a/packages/material_ui/lib/src/calendar_date_picker.dart b/packages/material_ui/lib/src/calendar_date_picker.dart index 679bf1011570..2d5ae3259cda 100644 --- a/packages/material_ui/lib/src/calendar_date_picker.dart +++ b/packages/material_ui/lib/src/calendar_date_picker.dart @@ -1523,10 +1523,11 @@ class _YearPickerState extends State { BorderSide? borderSide; if (isCurrentYear) { - borderSide = datePickerTheme.todayBorder ?? defaults.todayBorder; - if (borderSide != null) { - borderSide = borderSide.copyWith(color: textColor); - } + final bool hasCustomBorderColor = + datePickerTheme.todayBorder != null && datePickerTheme.todayBorder!.color.opacity != 0.0; + borderSide = hasCustomBorderColor + ? datePickerTheme.todayBorder + : (datePickerTheme.todayBorder ?? defaults.todayBorder)?.copyWith(color: textColor); } final decoration = ShapeDecoration( color: background, diff --git a/packages/material_ui/lib/src/date_picker_theme.dart b/packages/material_ui/lib/src/date_picker_theme.dart index 32e447fa2e53..de408228fd3b 100644 --- a/packages/material_ui/lib/src/date_picker_theme.dart +++ b/packages/material_ui/lib/src/date_picker_theme.dart @@ -285,8 +285,8 @@ class DatePickerThemeData with Diagnosticable { final WidgetStateProperty? todayBackgroundColor; /// Overrides the border used to paint the - /// [DatePickerDialog.currentDate] label in the grid of the date - /// picker. + /// [DatePickerDialog.currentDate] label in both the day grid and the year + /// selector of the date picker. /// /// If the border side's [BorderSide.color] is transparent (has 0 opacity), /// [todayForegroundColor] is used instead. Otherwise, the border's color diff --git a/packages/material_ui/pending_changelogs/change_2026_08_30_year_picker_today_border.yaml b/packages/material_ui/pending_changelogs/change_2026_08_30_year_picker_today_border.yaml new file mode 100644 index 000000000000..3099c2ee2a40 --- /dev/null +++ b/packages/material_ui/pending_changelogs/change_2026_08_30_year_picker_today_border.yaml @@ -0,0 +1,3 @@ +changelog: | + - Fixes `DatePickerThemeData.todayBorder` color being overridden by `todayForegroundColor` in the year selector. +version: patch diff --git a/packages/material_ui/test/calendar_date_picker_test.dart b/packages/material_ui/test/calendar_date_picker_test.dart index 4e99a86b5e99..a382cf382325 100644 --- a/packages/material_ui/test/calendar_date_picker_test.dart +++ b/packages/material_ui/test/calendar_date_picker_test.dart @@ -71,8 +71,10 @@ void main() { DateTime? currentDate, ValueChanged? onChanged, TextDirection textDirection = TextDirection.ltr, + ThemeData? theme, }) { return MaterialApp( + theme: theme, home: Material( child: Directionality( textDirection: textDirection, @@ -2102,6 +2104,84 @@ void main() { }); }); + ShapeDecoration? findYearDecoration(WidgetTester tester, String year) { + final Container container = tester.widget( + find.ancestor(of: find.text(year), matching: find.byType(Container)).first, + ); + + return container.decoration as ShapeDecoration?; + } + + // Regression test for https://github.com/flutter/flutter/issues/189298 + testWidgets('Non-null todayBorder color should be respected over todayBackgroundColor', ( + WidgetTester tester, + ) async { + const Color customBorderColor = Colors.red; + await tester.pumpWidget( + yearPicker( + theme: ThemeData( + datePickerTheme: DatePickerThemeData( + todayBorder: const BorderSide(color: customBorderColor), + todayForegroundColor: WidgetStateProperty.all(Colors.blue), + ), + ), + ), + ); + + // The current year should be painted with custom border color. + final ShapeDecoration? decoration = findYearDecoration(tester, '2016'); + final shape = decoration!.shape as OutlinedBorder; + expect(shape.side.color, customBorderColor); + }); + + // Regression test for https://github.com/flutter/flutter/issues/189298. + testWidgets('Non-null todayBorder color is used even when disabled', (WidgetTester tester) async { + const Color customBorderColor = Colors.red; + await tester.pumpWidget( + yearPicker( + firstDate: DateTime(2018, DateTime.june, 9), + lastDate: DateTime(2030, DateTime.december, 15), + selectedDate: DateTime(2020), + currentDate: DateTime(2016), // Not between first and last date. + theme: ThemeData( + datePickerTheme: DatePickerThemeData( + todayBorder: const BorderSide(color: customBorderColor), + todayForegroundColor: WidgetStateProperty.all(Colors.blue), + ), + ), + ), + ); + + // The current year should be painted with the custom border color, + // not with foreground color opacity applied, even if it's disabled. + final ShapeDecoration? decoration = findYearDecoration(tester, '2016'); + final shape = decoration!.shape as OutlinedBorder; + expect(shape.side.color, customBorderColor); + }); + + // Regression test for https://github.com/flutter/flutter/issues/189298. + testWidgets('Transparent todayBorder should fall back to foreground color', ( + WidgetTester tester, + ) async { + const Color customForegroundColor = Colors.green; + await tester.pumpWidget( + yearPicker( + theme: ThemeData( + datePickerTheme: DatePickerThemeData( + todayBorder: const BorderSide(color: Color(0x00000000)), + todayForegroundColor: WidgetStateProperty.all(customForegroundColor), + ), + ), + ), + ); + + // The current year should use the foreground color since + // todayBorder color is transparent. + final ShapeDecoration? decoration = findYearDecoration(tester, '2016'); + final shape = decoration!.shape as OutlinedBorder; + expect(shape.side.color, customForegroundColor); + }); + group('Calendar Delegate', () { testWidgets('Defaults to Gregorian calendar system', (WidgetTester tester) async { await tester.pumpWidget(