Unverified Commit 37f348b0 authored by Patrick Lindsay's avatar Patrick Lindsay Committed by GitHub

Added CupertinoDatepicker monthYear mode (flutter#93508) (#125603)

This PR adds a month and year mode to the CupertinoDatePicker. The monthYear mode is the date mode without the day of the month.
![monthYearMode](https://user-images.githubusercontent.com/98486346/234749274-794dce24-28c7-4f48-92ab-5ac46ec069d7.png)

This feature was added at the request of:
[Proposal] CupertinoDatePicker with month and year. #93508

One thing that I was unsure of was the use of the DatePickerDateOrder to determine the monthYear order. It could be considered a workaround since the DatePickerDateOrder is intended to order day, month, and year. This means that a developer could use the DatePickerDateOrder.dmy (day, month, year) or DatePickerDateOrder.mdy (month, day, year) to get the same result. 

At first I intended to add a DatePickerMonthYearOrder enum to the localizations, in addition to a new parameter for the CupertinoDatePicker for monthYearOrder, but I ended up reverting these changes (https://github.com/flutter/flutter/commit/1c61f1084e63fc4f6e394c3621a1ae626fd631a5) because I had not considered the effects of adding values to the localizations.

I decided it may be better to not add an additional parameter (monthYearOrder) that would go mostly unused. I am very open to feedback or ideas on this matter.
parent c1c2513a
......@@ -460,6 +460,27 @@ void main() {
expect(find.text('AM'), findsOneWidget);
});
testWidgets('monthYear picker has expected string', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.monthYear,
onDateTimeChanged: (_) { },
initialDateTime: DateTime(2018, 9),
),
),
),
),
);
expect(find.text('September'), findsOneWidget);
expect(find.text('2018'), findsOneWidget);
});
testWidgets('width of picker in date and time mode is consistent', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
......@@ -587,6 +608,50 @@ void main() {
);
});
testWidgets('width of picker in monthYear mode is consistent', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.monthYear,
onDateTimeChanged: (_) { },
initialDateTime: DateTime(2018),
),
),
),
),
);
// Distance between the first column and the last column.
final double distance =
tester.getCenter(find.text('January')).dx - tester.getCenter(find.text('2018')).dx;
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 800.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.monthYear,
onDateTimeChanged: (_) { },
initialDateTime: DateTime(2018),
),
),
),
),
);
// Distance between the first and the last column should be the same.
expect(
tester.getCenter(find.text('January')).dx - tester.getCenter(find.text('2018')).dx,
distance,
);
});
testWidgets('wheel does not bend outwards', (WidgetTester tester) async {
final Widget dateWidget = CupertinoDatePicker(
......@@ -916,6 +981,65 @@ void main() {
},
);
testWidgets(
'monthYear picker automatically scrolls away from invalid date, '
"and onDateTimeChanged doesn't report these dates",
(WidgetTester tester) async {
late DateTime date;
final DateTime minimum = DateTime(2016, 2);
final DateTime maximum = DateTime(2018, 12);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.monthYear,
minimumDate: minimum,
maximumDate: maximum,
onDateTimeChanged: (DateTime newDate) {
date = newDate;
// Callback doesn't transiently go into invalid dates.
expect(newDate.isAtSameMomentAs(minimum) || newDate.isAfter(minimum), isTrue);
expect(newDate.isAtSameMomentAs(maximum) || newDate.isBefore(maximum), isTrue);
},
initialDateTime: DateTime(2017, 2),
),
),
),
),
);
await tester.drag(find.text('2017'), const Offset(0.0, 100.0), touchSlopY: 0.0, warnIfMissed: false); // see top of file
await tester.pump();
await tester.pumpAndSettle(); // Now the autoscrolling should happen.
expect(
date,
DateTime(2016, 2),
);
await tester.drag(find.text('2016'), const Offset(0.0, -100.0), touchSlopY: 0.0, warnIfMissed: false); // see top of file
await tester.pump(); // Once to trigger the post frame animate call.
await tester.pumpAndSettle();
expect(
date,
DateTime(2018, 12),
);
await tester.drag(find.text('2016'), const Offset(0.0, 32.0), touchSlopY: 0.0, warnIfMissed: false); // see top of file
await tester.pump(); // Once to trigger the post frame animate call.
await tester.pumpAndSettle();
expect(
date,
DateTime(2017, 12),
);
},
);
testWidgets('picker automatically scrolls away from invalid date on day change', (WidgetTester tester) async {
late DateTime date;
await tester.pumpWidget(
......@@ -1273,6 +1397,14 @@ void main() {
);
}
await tester.pumpWidget(buildApp(CupertinoDatePickerMode.monthYear));
if (!skipPerspectiveTextGoldens) {
await expectLater(
find.byType(CupertinoDatePicker),
matchesGoldenFile('date_picker_test.monthyear.initial.png'),
);
}
await tester.pumpWidget(buildApp(CupertinoDatePickerMode.dateAndTime));
if (!skipPerspectiveTextGoldens) {
await expectLater(
......@@ -1322,6 +1454,50 @@ void main() {
);
});
testWidgets('monthYear DatePicker displays the date in correct order', (WidgetTester tester) async {
Widget buildApp(DatePickerDateOrder order) {
return CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
key: ValueKey<DatePickerDateOrder>(order),
dateOrder: order,
mode: CupertinoDatePickerMode.monthYear,
onDateTimeChanged: (DateTime newDate) {},
initialDateTime: DateTime(2018, 1, 14, 10, 30),
),
),
),
);
}
await tester.pumpWidget(buildApp(DatePickerDateOrder.dmy));
expect(
tester.getTopLeft(find.text('January')).dx,
lessThan(tester.getTopLeft(find.text('2018')).dx),
);
await tester.pumpWidget(buildApp(DatePickerDateOrder.mdy));
expect(
tester.getTopLeft(find.text('January')).dx,
lessThan(tester.getTopLeft(find.text('2018')).dx),
);
await tester.pumpWidget(buildApp(DatePickerDateOrder.ydm));
expect(
tester.getTopLeft(find.text('2018')).dx,
lessThan(tester.getTopLeft(find.text('January')).dx),
);
await tester.pumpWidget(buildApp(DatePickerDateOrder.ymd));
expect(
tester.getTopLeft(find.text('2018')).dx,
lessThan(tester.getTopLeft(find.text('January')).dx),
);
});
testWidgets('DatePicker displays hours and minutes correctly in RTL', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment