Skip to content

Commit 1df03cb

Browse files
rklosGroovinChip
andauthored
feat: Added support for startWeekOnMonday to MacosDatePicker (#414)
* feat: Added support for `startWeekOnMonday` to `MacosDatePicker` * Update lib/src/selectors/date_picker.dart --------- Co-authored-by: Reuben Turner <groovinchip@gmail.com>
1 parent 32fa64c commit 1df03cb

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
## [2.0.0-beta.3]
2+
✨ New ✨
3+
* Added support for `startWeekOnMonday` to `MacosDatePicker`.
4+
25
🛠️ Fixed 🛠️
36
* Better UX of the click on the calendar elements in `MacosDatePicker`
47

lib/src/selectors/date_picker.dart

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class MacosDatePicker extends StatefulWidget {
4444
this.style = DatePickerStyle.combined,
4545
required this.onDateChanged,
4646
this.initialDate,
47+
this.startWeekOnMonday,
4748
});
4849

4950
/// The [DatePickerStyle] to use.
@@ -59,6 +60,14 @@ class MacosDatePicker extends StatefulWidget {
5960
/// Defaults to `DateTime.now()`.
6061
final DateTime? initialDate;
6162

63+
/// Allows for changing the order of day headers in the graphical Date Picker
64+
/// to Mo, Tu, We, Th, Fr, Sa, Su.
65+
///
66+
/// This is useful for internationalization purposes, as many countries begin their weeks on Mondays.
67+
///
68+
/// Defaults to `false`.
69+
final bool? startWeekOnMonday;
70+
6271
@override
6372
State<MacosDatePicker> createState() => _MacosDatePickerState();
6473
}
@@ -153,12 +162,23 @@ class _MacosDatePickerState extends State<MacosDatePicker> {
153162
}
154163

155164
// Creates the day headers - Su, Mo, Tu, We, Th, Fr, Sa
165+
// or Mo, Tu, We, Th, Fr, Sa, Su depending on the value of [startWeekOnMonday]
156166
List<Widget> _dayHeaders(
157167
TextStyle? headerStyle,
158168
MaterialLocalizations localizations,
159169
) {
160170
final result = <Widget>[];
161-
for (int i = localizations.firstDayOfWeekIndex; true; i = (i + 1) % 7) {
171+
172+
// Hack due to invalid "firstDayOfWeekIndex" implementation in MaterialLocalizations
173+
// issue: https://github.com/flutter/flutter/issues/122274
174+
// TODO: remove this workaround once the issue is fixed.
175+
// Then, "firstDayOfWeekIndex" can be controlled by passing "localizationsDelegates" and "supportedLocales" to MacosApp
176+
int firstDayOfWeekIndex = localizations.firstDayOfWeekIndex;
177+
if (widget.startWeekOnMonday == true) {
178+
firstDayOfWeekIndex = 1;
179+
}
180+
181+
for (int i = firstDayOfWeekIndex; result.length < 7; i = (i + 1) % 7) {
162182
final weekday = _narrowWeekdays[i];
163183
result.add(
164184
ExcludeSemantics(
@@ -170,7 +190,6 @@ class _MacosDatePickerState extends State<MacosDatePicker> {
170190
),
171191
),
172192
);
173-
if (i == (localizations.firstDayOfWeekIndex - 1) % 7) break;
174193
}
175194
return result;
176195
}
@@ -474,9 +493,19 @@ class _MacosDatePickerState extends State<MacosDatePicker> {
474493
),
475494
localizations,
476495
);
496+
497+
// Hack due to invalid "firstDayOfWeekIndex" implementation in MaterialLocalizations
498+
// issue: https://github.com/flutter/flutter/issues/122274
499+
// TODO: remove this workaround once the issue is fixed.
500+
// Then, DateUtils.getDaysInMonth will work as expected when proper "localizationsDelegates" and "supportedLocales" are provided to MacosApp
501+
int fixedDayOffset = dayOffset;
502+
if (widget.startWeekOnMonday == true) {
503+
fixedDayOffset = dayOffset - 1;
504+
}
505+
477506
// 1-based day of month, e.g. 1-31 for January, and 1-29 for February on
478507
// a leap year.
479-
int day = -dayOffset;
508+
int day = -fixedDayOffset;
480509

481510
final dayItems = <Widget>[];
482511

test/selectors/date_picker_test.dart

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,96 @@ void main() {
308308
},
309309
);
310310
});
311+
312+
testWidgets(
313+
'Graphical MacosDatePicker with "startWeekOnMonday" set to true shows Monday as the first day of the week',
314+
(tester) async {
315+
await tester.pumpWidget(
316+
MacosApp(
317+
home: MacosWindow(
318+
child: MacosScaffold(
319+
children: [
320+
ContentArea(
321+
builder: (context, _) {
322+
return Center(
323+
child: MacosDatePicker(
324+
startWeekOnMonday: true,
325+
initialDate: DateTime.parse('2023-04-01'),
326+
onDateChanged: (date) {},
327+
),
328+
);
329+
},
330+
),
331+
],
332+
),
333+
),
334+
),
335+
);
336+
337+
final dayHeadersRow = find.byType(GridView).first;
338+
final dayHeaders = find.descendant(
339+
of: dayHeadersRow,
340+
matching: find.byType(Text),
341+
);
342+
final firstWeekday = dayHeaders.first;
343+
final firstWeekdayText = (firstWeekday.evaluate().first.widget as Text).data;
344+
await tester.pumpAndSettle();
345+
346+
expect(firstWeekdayText, 'Mo');
347+
348+
final calendarGrid = find.byType(GridView).last;
349+
final dayOffsetWidgets = find.descendant(
350+
of: calendarGrid,
351+
matching: find.byType(SizedBox),
352+
);
353+
final dayOffset = dayOffsetWidgets.evaluate().length;
354+
355+
expect(dayOffset, 5);
356+
},
357+
);
358+
359+
// Regression test due to invalid "firstDayOfWeekIndex" implementation in MaterialLocalizations
360+
// issue: https://github.com/flutter/flutter/issues/122274
361+
// TODO: remove this once the issue is fixed and test starts failing
362+
testWidgets(
363+
'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"',
364+
(tester) async {
365+
await tester.pumpWidget(
366+
MacosApp(
367+
supportedLocales: const [
368+
Locale('en', 'PL'),
369+
],
370+
home: MacosWindow(
371+
child: MacosScaffold(
372+
children: [
373+
ContentArea(
374+
builder: (context, _) {
375+
return Center(
376+
child: MacosDatePicker(
377+
startWeekOnMonday: true,
378+
initialDate: DateTime.parse('2023-04-01'),
379+
onDateChanged: (date) {},
380+
),
381+
);
382+
},
383+
),
384+
],
385+
),
386+
),
387+
),
388+
);
389+
390+
final dayHeadersRow = find.byType(GridView).first;
391+
final dayHeaders = find.descendant(
392+
of: dayHeadersRow,
393+
matching: find.byType(Text),
394+
);
395+
final firstWeekday = dayHeaders.first;
396+
final firstWeekdayText = (firstWeekday.evaluate().first.widget as Text).data;
397+
await tester.pumpAndSettle();
398+
399+
// The result will be 'Tu' if the fix is no longer needed and can be removed
400+
expect(firstWeekdayText, 'Mo');
401+
},
402+
);
311403
}

0 commit comments

Comments
 (0)