diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d8d057..3ad855e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ ## [2.0.0-beta.3] +✨ New ✨ +* Added support for `startWeekOnMonday` to `MacosDatePicker`. + 🛠️ Fixed 🛠️ * Better UX of the click on the calendar elements in `MacosDatePicker` diff --git a/lib/src/selectors/date_picker.dart b/lib/src/selectors/date_picker.dart index d5145dc4..c00d7f23 100644 --- a/lib/src/selectors/date_picker.dart +++ b/lib/src/selectors/date_picker.dart @@ -44,6 +44,7 @@ class MacosDatePicker extends StatefulWidget { this.style = DatePickerStyle.combined, required this.onDateChanged, this.initialDate, + this.startWeekOnMonday, }); /// The [DatePickerStyle] to use. @@ -59,6 +60,12 @@ class MacosDatePicker extends StatefulWidget { /// Defaults to `DateTime.now()`. final DateTime? initialDate; + /// Allows to change the order of day headers in the graphical Date Picker + /// to Mo, Tu, We, Th, Fr, Sa, Su + /// + /// Defaults to `false` + final bool? startWeekOnMonday; + @override State createState() => _MacosDatePickerState(); } @@ -153,12 +160,23 @@ class _MacosDatePickerState extends State { } // Creates the day headers - Su, Mo, Tu, We, Th, Fr, Sa + // or Mo, Tu, We, Th, Fr, Sa, Su depending on the value of [startWeekOnMonday] List _dayHeaders( TextStyle? headerStyle, MaterialLocalizations localizations, ) { final result = []; - for (int i = localizations.firstDayOfWeekIndex; true; i = (i + 1) % 7) { + + // Hack due to invalid "firstDayOfWeekIndex" implementation in MaterialLocalizations + // issue: https://github.com/flutter/flutter/issues/122274 + // TODO: remove this workaround once the issue is fixed. + // Then, "firstDayOfWeekIndex" can be controlled by passing "localizationsDelegates" and "supportedLocales" to MacosApp + int firstDayOfWeekIndex = localizations.firstDayOfWeekIndex; + if (widget.startWeekOnMonday == true) { + firstDayOfWeekIndex = 1; + } + + for (int i = firstDayOfWeekIndex; result.length < 7; i = (i + 1) % 7) { final weekday = _narrowWeekdays[i]; result.add( ExcludeSemantics( @@ -170,7 +188,6 @@ class _MacosDatePickerState extends State { ), ), ); - if (i == (localizations.firstDayOfWeekIndex - 1) % 7) break; } return result; } @@ -474,9 +491,19 @@ class _MacosDatePickerState extends State { ), localizations, ); + + // Hack due to invalid "firstDayOfWeekIndex" implementation in MaterialLocalizations + // issue: https://github.com/flutter/flutter/issues/122274 + // TODO: remove this workaround once the issue is fixed. + // Then, DateUtils.getDaysInMonth will work as expected when proper "localizationsDelegates" and "supportedLocales" are provided to MacosApp + int fixedDayOffset = dayOffset; + if (widget.startWeekOnMonday == true) { + fixedDayOffset = dayOffset - 1; + } + // 1-based day of month, e.g. 1-31 for January, and 1-29 for February on // a leap year. - int day = -dayOffset; + int day = -fixedDayOffset; final dayItems = []; diff --git a/test/selectors/date_picker_test.dart b/test/selectors/date_picker_test.dart index b0e50b5d..4eb263b2 100644 --- a/test/selectors/date_picker_test.dart +++ b/test/selectors/date_picker_test.dart @@ -308,4 +308,96 @@ void main() { }, ); }); + + testWidgets( + 'Graphical MacosDatePicker with "startWeekOnMonday" set to true shows Monday as the first day of the week', + (tester) async { + await tester.pumpWidget( + MacosApp( + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker( + startWeekOnMonday: true, + initialDate: DateTime.parse('2023-04-01'), + onDateChanged: (date) {}, + ), + ); + }, + ), + ], + ), + ), + ), + ); + + final dayHeadersRow = find.byType(GridView).first; + final dayHeaders = find.descendant( + of: dayHeadersRow, + matching: find.byType(Text), + ); + final firstWeekday = dayHeaders.first; + final firstWeekdayText = (firstWeekday.evaluate().first.widget as Text).data; + await tester.pumpAndSettle(); + + expect(firstWeekdayText, 'Mo'); + + final calendarGrid = find.byType(GridView).last; + final dayOffsetWidgets = find.descendant( + of: calendarGrid, + matching: find.byType(SizedBox), + ); + final dayOffset = dayOffsetWidgets.evaluate().length; + + expect(dayOffset, 5); + }, + ); + + // Regression test due to invalid "firstDayOfWeekIndex" implementation in MaterialLocalizations + // issue: https://github.com/flutter/flutter/issues/122274 + // TODO: remove this once the issue is fixed and test starts failing + testWidgets( + 'Graphical MacosDatePicker still needs "startWeekOnMonday" to show Monday as the first day of the week, even when the locale is set to something other than "en_US"', + (tester) async { + await tester.pumpWidget( + MacosApp( + supportedLocales: const [ + Locale('en', 'PL'), + ], + home: MacosWindow( + child: MacosScaffold( + children: [ + ContentArea( + builder: (context, _) { + return Center( + child: MacosDatePicker( + startWeekOnMonday: true, + initialDate: DateTime.parse('2023-04-01'), + onDateChanged: (date) {}, + ), + ); + }, + ), + ], + ), + ), + ), + ); + + final dayHeadersRow = find.byType(GridView).first; + final dayHeaders = find.descendant( + of: dayHeadersRow, + matching: find.byType(Text), + ); + final firstWeekday = dayHeaders.first; + final firstWeekdayText = (firstWeekday.evaluate().first.widget as Text).data; + await tester.pumpAndSettle(); + + // The result will be 'Tu' if the fix is no longer needed and can be removed + expect(firstWeekdayText, 'Mo'); + }, + ); }