Grey out non-selectable days in CupertinoDatePicker (#136181)

This PR changes the text color of non-selectable days in the CupertinoDatePicker to match non-selectable months and years.

Current:
![Screenshot_1696829290](https://github.com/flutter/flutter/assets/147121557/209fee88-9efc-4b92-803a-453ecc6a7c16)

New:
![Screenshot_1696830232](https://github.com/flutter/flutter/assets/147121557/ecd11266-4c22-49cc-9bb5-2df39d10cf79)

Fixes #136179
This commit is contained in:
Shaun Byrne 2024-02-06 10:19:17 +10:30 committed by GitHub
parent 81dcba5fb3
commit c21fbabc2b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 164 additions and 1 deletions

View file

@ -1236,11 +1236,18 @@ class _CupertinoDatePickerDateState extends State<CupertinoDatePicker> {
children: List<Widget>.generate(31, (int index) {
final int day = index + 1;
final int? dayOfWeek = widget.showDayOfWeek ? DateTime(selectedYear, selectedMonth, day).weekday : null;
final bool isInvalidDay = (day > daysInCurrentMonth)
|| (widget.minimumDate?.year == selectedYear &&
widget.minimumDate!.month == selectedMonth &&
widget.minimumDate!.day > day)
|| (widget.maximumDate?.year == selectedYear &&
widget.maximumDate!.month == selectedMonth &&
widget.maximumDate!.day < day);
return itemPositioningBuilder(
context,
Text(
localizations.datePickerDayOfMonth(day, dayOfWeek),
style: _themeTextStyle(context, isValid: day <= daysInCurrentMonth),
style: _themeTextStyle(context, isValid: !isInvalidDay),
),
);
}),

View file

@ -745,6 +745,162 @@ void main() {
}
});
testWidgets(
'non-selectable dates are greyed out, '
'when minimum date is unconstrained',
(WidgetTester tester) async {
final DateTime maximum = DateTime(2018, 6, 15);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
maximumDate: maximum,
onDateTimeChanged: (_) {},
initialDateTime: DateTime(2018, 6, 15),
),
),
),
),
);
// unconstrained bounds are not affected.
expect(
tester.widget<Text>(find.text('14')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
// the selected day is not affected.
expect(
tester.widget<Text>(find.text('15')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
// out of bounds and should be greyed out.
expect(
tester.widget<Text>(find.text('16')).style!.color,
isSameColorAs(CupertinoColors.inactiveGray.color),
);
},
);
testWidgets(
'non-selectable dates are greyed out, '
'when maximum date is unconstrained',
(WidgetTester tester) async {
final DateTime minimum = DateTime(2018, 6, 15);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
minimumDate: minimum,
onDateTimeChanged: (_) {},
initialDateTime: DateTime(2018, 6, 15),
),
),
),
),
);
// out of bounds and should be greyed out.
expect(
tester.widget<Text>(find.text('14')).style!.color,
isSameColorAs(CupertinoColors.inactiveGray.color),
);
// the selected day is not affected.
expect(
tester.widget<Text>(find.text('15')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
// unconstrained bounds are not affected.
expect(
tester.widget<Text>(find.text('16')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
},
);
testWidgets(
'non-selectable dates are greyed out, '
'months should be taken into account when greying out days',
(WidgetTester tester) async {
final DateTime minimum = DateTime(2018, 5, 15);
final DateTime maximum = DateTime(2018, 7, 15);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
minimumDate: minimum,
maximumDate: maximum,
onDateTimeChanged: (_) {},
initialDateTime: DateTime(2018, 6, 15),
),
),
),
),
);
// days of a different min/max month are not affected.
expect(
tester.widget<Text>(find.text('14')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
expect(
tester.widget<Text>(find.text('16')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
},
);
testWidgets(
'non-selectable dates are greyed out, '
'years should be taken into account when greying out days',
(WidgetTester tester) async {
final DateTime minimum = DateTime(2017, 6, 15);
final DateTime maximum = DateTime(2019, 6, 15);
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: SizedBox(
height: 400.0,
width: 400.0,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
minimumDate: minimum,
maximumDate: maximum,
onDateTimeChanged: (_) {},
initialDateTime: DateTime(2018, 6, 15),
),
),
),
),
);
// days of a different min/max year are not affected.
expect(
tester.widget<Text>(find.text('14')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
expect(
tester.widget<Text>(find.text('16')).style!.color,
isNot(isSameColorAs(CupertinoColors.inactiveGray.color)),
);
},
);
testWidgets('picker automatically scrolls away from invalid date on month change', (WidgetTester tester) async {
late DateTime date;
await tester.pumpWidget(