diff --git a/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart b/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart index ec0fd154b6..a682f7508b 100644 --- a/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart +++ b/examples/api/lib/cupertino/date_picker/cupertino_date_picker.0.dart @@ -81,6 +81,8 @@ class _DatePickerExampleState extends State { initialDateTime: date, mode: CupertinoDatePickerMode.date, use24hFormat: true, + // This shows day of week alongside day of month + showDayOfWeek: true, // This is called when the user changes the date. onDateTimeChanged: (DateTime newDate) { setState(() => date = newDate); diff --git a/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart b/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart index 8638aaa470..04b4bf2af9 100644 --- a/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart +++ b/examples/api/test/cupertino/date_picker/cupertino_date_picker.0_test.dart @@ -18,7 +18,7 @@ void main() { // Drag month, day and year wheels to change the picked date. await tester.drag(find.text('October'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file - await tester.drag(find.text('26'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file + await tester.drag(find.textContaining('26').last, _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file await tester.drag(find.text('2016'), _kRowOffset, touchSlopY: 0, warnIfMissed: false); // see top of file await tester.pump(); diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index d152613729..126002c4b5 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -275,6 +275,7 @@ class CupertinoDatePicker extends StatefulWidget { this.use24hFormat = false, this.dateOrder, this.backgroundColor, + this.showDayOfWeek = false }) : initialDateTime = initialDateTime ?? DateTime.now(), assert( minuteInterval > 0 && 60 % minuteInterval == 0, @@ -384,6 +385,9 @@ class CupertinoDatePicker extends StatefulWidget { /// Defaults to null, which disables background painting entirely. final Color? backgroundColor; + /// Whether to to show day of week alongside day. Defaults to false. + final bool showDayOfWeek; + @override State createState() { // ignore: no_logic_in_create_state, https://github.com/flutter/flutter/issues/70499 // The `time` mode and `dateAndTime` mode of the picker share the time @@ -404,6 +408,7 @@ class CupertinoDatePicker extends StatefulWidget { _PickerColumnType columnType, CupertinoLocalizations localizations, BuildContext context, + bool showDayOfWeek ) { String longestText = ''; @@ -443,10 +448,20 @@ class CupertinoDatePicker extends StatefulWidget { : localizations.postMeridiemAbbreviation; break; case _PickerColumnType.dayOfMonth: + int longestDayOfMonth = 1; for (int i = 1; i <=31; i++) { final String dayOfMonth = localizations.datePickerDayOfMonth(i); if (longestText.length < dayOfMonth.length) { longestText = dayOfMonth; + longestDayOfMonth = i; + } + } + if (showDayOfWeek) { + for (int wd = 1; wd < DateTime.daysPerWeek; wd++) { + final String dayOfMonth = localizations.datePickerDayOfMonth(longestDayOfMonth, wd); + if (longestText.length < dayOfMonth.length) { + longestText = dayOfMonth; + } } } break; @@ -649,7 +664,7 @@ class _CupertinoDatePickerDateTimeState extends State { double _getEstimatedColumnWidth(_PickerColumnType columnType) { if (estimatedColumnWidths[columnType.index] == null) { estimatedColumnWidths[columnType.index] = - CupertinoDatePicker._getColumnWidth(columnType, localizations, context); + CupertinoDatePicker._getColumnWidth(columnType, localizations, context, widget.showDayOfWeek); } return estimatedColumnWidths[columnType.index]!; @@ -1151,9 +1166,9 @@ class _CupertinoDatePickerDateState extends State { } void _refreshEstimatedColumnWidths() { - estimatedColumnWidths[_PickerColumnType.dayOfMonth.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.dayOfMonth, localizations, context); - estimatedColumnWidths[_PickerColumnType.month.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.month, localizations, context); - estimatedColumnWidths[_PickerColumnType.year.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.year, localizations, context); + estimatedColumnWidths[_PickerColumnType.dayOfMonth.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.dayOfMonth, localizations, context, widget.showDayOfWeek); + estimatedColumnWidths[_PickerColumnType.month.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.month, localizations, context, widget.showDayOfWeek); + estimatedColumnWidths[_PickerColumnType.year.index] = CupertinoDatePicker._getColumnWidth(_PickerColumnType.year, localizations, context, widget.showDayOfWeek); } // The DateTime of the last day of a given month in a given year. @@ -1191,10 +1206,11 @@ class _CupertinoDatePickerDateState extends State { selectionOverlay: selectionOverlay, children: List.generate(31, (int index) { final int day = index + 1; + final int? dayOfWeek = widget.showDayOfWeek ? DateTime(selectedYear, selectedMonth, day).weekday : null; return itemPositioningBuilder( context, Text( - localizations.datePickerDayOfMonth(day), + localizations.datePickerDayOfMonth(day, dayOfWeek), style: _themeTextStyle(context, isValid: day <= daysInCurrentMonth), ), ); diff --git a/packages/flutter/lib/src/cupertino/localizations.dart b/packages/flutter/lib/src/cupertino/localizations.dart index 2a68276c40..1dfcdced53 100644 --- a/packages/flutter/lib/src/cupertino/localizations.dart +++ b/packages/flutter/lib/src/cupertino/localizations.dart @@ -82,12 +82,17 @@ abstract class CupertinoLocalizations { /// Day of month that is shown in [CupertinoDatePicker] spinner corresponding /// to the given day index. /// + /// If weekDay is provided then it will also show weekday name alongside the numerical day. + /// /// Examples: datePickerDayOfMonth(1) in: /// /// - US English: 1 /// - Korean: 1일 + /// Examples: datePickerDayOfMonth(1, 1) in: + /// + /// - US English: Mon 1 // The global version uses date symbols data from the intl package. - String datePickerDayOfMonth(int dayIndex); + String datePickerDayOfMonth(int dayIndex, [int? weekDay]); /// The medium-width date format that is shown in [CupertinoDatePicker] /// spinner. Abbreviates month and days of week. @@ -292,7 +297,8 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { /// function, rather than constructing this class directly. const DefaultCupertinoLocalizations(); - static const List _shortWeekdays = [ + /// Short version of days of week. + static const List shortWeekdays = [ 'Mon', 'Tue', 'Wed', @@ -341,7 +347,13 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { String datePickerMonth(int monthIndex) => _months[monthIndex - 1]; @override - String datePickerDayOfMonth(int dayIndex) => dayIndex.toString(); + String datePickerDayOfMonth(int dayIndex, [int? weekDay]) { + if (weekDay != null) { + return ' ${shortWeekdays[weekDay - DateTime.monday]} $dayIndex '; + } + + return dayIndex.toString(); + } @override String datePickerHour(int hour) => hour.toString(); @@ -362,7 +374,7 @@ class DefaultCupertinoLocalizations implements CupertinoLocalizations { @override String datePickerMediumDate(DateTime date) { - return '${_shortWeekdays[date.weekday - DateTime.monday]} ' + return '${shortWeekdays[date.weekday - DateTime.monday]} ' '${_shortMonths[date.month - DateTime.january]} ' '${date.day.toString().padRight(2)}'; } diff --git a/packages/flutter/test/cupertino/date_picker_test.dart b/packages/flutter/test/cupertino/date_picker_test.dart index b7367202d2..918c280c31 100644 --- a/packages/flutter/test/cupertino/date_picker_test.dart +++ b/packages/flutter/test/cupertino/date_picker_test.dart @@ -1664,6 +1664,30 @@ void main() { DateTime(2022, 6, 14, 3, 45), ); }); + + testWidgets('date picker has expected day of week', (WidgetTester tester) async { + await tester.pumpWidget( + CupertinoApp( + home: Center( + child: SizedBox( + height: 400.0, + width: 400.0, + child: CupertinoDatePicker( + mode: CupertinoDatePickerMode.date, + onDateTimeChanged: (_) { }, + initialDateTime: DateTime(2018, 9, 15), + showDayOfWeek: true, + ), + ), + ), + ), + ); + + expect(find.text('September'), findsOneWidget); + expect(find.textContaining('Sat').last, findsOneWidget); + expect(find.textContaining('15').last, findsOneWidget); + expect(find.text('2018'), findsOneWidget); + }); } Widget _buildPicker({ diff --git a/packages/flutter/test/cupertino/localizations_test.dart b/packages/flutter/test/cupertino/localizations_test.dart index cca5b32815..f818890858 100644 --- a/packages/flutter/test/cupertino/localizations_test.dart +++ b/packages/flutter/test/cupertino/localizations_test.dart @@ -12,6 +12,7 @@ void main() { expect(localizations.datePickerYear(2018), isNotNull); expect(localizations.datePickerMonth(1), isNotNull); expect(localizations.datePickerDayOfMonth(1), isNotNull); + expect(localizations.datePickerDayOfMonth(1, 1), isNotNull); expect(localizations.datePickerHour(0), isNotNull); expect(localizations.datePickerHourSemanticsLabel(0), isNotNull); expect(localizations.datePickerMinute(0), isNotNull); diff --git a/packages/flutter_localizations/lib/src/cupertino_localizations.dart b/packages/flutter_localizations/lib/src/cupertino_localizations.dart index 7fec5fe50e..4efbfb671c 100644 --- a/packages/flutter_localizations/lib/src/cupertino_localizations.dart +++ b/packages/flutter_localizations/lib/src/cupertino_localizations.dart @@ -97,7 +97,10 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations { } @override - String datePickerDayOfMonth(int dayIndex) { + String datePickerDayOfMonth(int dayIndex, [int? weekDay]) { + if (weekDay != null) { + return ' ${DefaultCupertinoLocalizations.shortWeekdays[weekDay - DateTime.monday]} $dayIndex '; + } // Year and month doesn't matter since we just want to day formatted. return _dayFormat.format(DateTime.utc(0, 0, dayIndex)); } diff --git a/packages/flutter_localizations/test/cupertino/translations_test.dart b/packages/flutter_localizations/test/cupertino/translations_test.dart index 73d8ec3770..78fcd0263a 100644 --- a/packages/flutter_localizations/test/cupertino/translations_test.dart +++ b/packages/flutter_localizations/test/cupertino/translations_test.dart @@ -38,6 +38,11 @@ void main() { expect(localizations.datePickerDayOfMonth(2), isNotNull); expect(localizations.datePickerDayOfMonth(10), isNotNull); + expect(localizations.datePickerDayOfMonth(0, 1), isNotNull); + expect(localizations.datePickerDayOfMonth(1, 2), isNotNull); + expect(localizations.datePickerDayOfMonth(2, 3), isNotNull); + expect(localizations.datePickerDayOfMonth(10, 4), isNotNull); + expect(localizations.datePickerMediumDate(DateTime(2019, 3, 25)), isNotNull); expect(localizations.datePickerHour(0), isNotNull);