Skip to content

Commit a7eaca9

Browse files
Reverts "Add ability to provide selectableDayPredicate for showDateRangePicker (#150355)" (#154089)
Reverts: flutter/flutter#150355 Initiated by: chingjun Reason for reverting: this is breaking an internal test. Original PR Author: Chuckame Reviewed By: {victorsanni, MitchellGoodwin} This change reverts the following previous change: - Closes #63973 - Now able to provide a `selectableDayPredicate` - No breaking change (same behavior as before if not set) - Reuse the same feature as the DatePicker: non-selectable days are greyed and not clickable - Reuse the same error message as if the user set a wrong date range - Made public `CalendarDateRangePicker`, actually the same for `CalendarDatePicker`, to allow using the range picker outside the `showDateRangePicker` bottom sheet modal ## Examples - Disable days after the next non selectable day when start day has been selected https://github.com/flutter/flutter/assets/16419143/2a2be325-1e2f-470c-8b17-b4ed5b2ad43e - Select a range including non-selectable days <img width="363" alt="image" src="https://github.com/flutter/flutter/assets/16419143/21e32def-46f0-41d6-974f-281a0405e28e">
1 parent 9308a79 commit a7eaca9

File tree

2 files changed

+19
-179
lines changed

2 files changed

+19
-179
lines changed

packages/flutter/lib/src/material/date_picker.dart

Lines changed: 19 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,18 +1012,6 @@ class _DatePickerHeader extends StatelessWidget {
10121012
}
10131013
}
10141014

1015-
/// Signature for predicating enabled dates in date range pickers.
1016-
///
1017-
/// The [selectedStartDay] and [selectedEndDay] are the currently selected start
1018-
/// and end dates of a date range, which conditionally enables or disables each
1019-
/// date in the picker based on the user selection. (Example: in a hostel's room
1020-
/// selection, you are not able to select the end date after the next
1021-
/// non-selectable day).
1022-
///
1023-
/// See [showDateRangePicker], which has a [SelectableDayForRangePredicate]
1024-
/// parameter used to specify allowable days in the date range picker.
1025-
typedef SelectableDayForRangePredicate = bool Function(DateTime day, DateTime? selectedStartDay, DateTime? selectedEndDay);
1026-
10271015
/// Shows a full screen modal dialog containing a Material Design date range
10281016
/// picker.
10291017
///
@@ -1152,8 +1140,11 @@ Future<DateTimeRange?> showDateRangePicker({
11521140
TextInputType keyboardType = TextInputType.datetime,
11531141
final Icon? switchToInputEntryModeIcon,
11541142
final Icon? switchToCalendarEntryModeIcon,
1155-
SelectableDayForRangePredicate? selectableDayPredicate,
11561143
}) async {
1144+
assert(
1145+
initialDateRange == null || !initialDateRange.start.isAfter(initialDateRange.end),
1146+
"initialDateRange's start date must not be after it's end date.",
1147+
);
11571148
initialDateRange = initialDateRange == null ? null : DateUtils.datesOnly(initialDateRange);
11581149
firstDate = DateUtils.dateOnly(firstDate);
11591150
lastDate = DateUtils.dateOnly(lastDate);
@@ -1177,16 +1168,6 @@ Future<DateTimeRange?> showDateRangePicker({
11771168
initialDateRange == null || !initialDateRange.end.isAfter(lastDate),
11781169
"initialDateRange's end date must be on or before lastDate $lastDate.",
11791170
);
1180-
assert(
1181-
initialDateRange == null || selectableDayPredicate == null ||
1182-
selectableDayPredicate(initialDateRange.start, initialDateRange.start, initialDateRange.end),
1183-
"initialDateRange's start date must be selectable.",
1184-
);
1185-
assert(
1186-
initialDateRange == null || selectableDayPredicate == null ||
1187-
selectableDayPredicate(initialDateRange.end, initialDateRange.start, initialDateRange.end),
1188-
"initialDateRange's end date must be selectable.",
1189-
);
11901171
currentDate = DateUtils.dateOnly(currentDate ?? DateTime.now());
11911172
assert(debugCheckHasMaterialLocalizations(context));
11921173

@@ -1195,7 +1176,6 @@ Future<DateTimeRange?> showDateRangePicker({
11951176
firstDate: firstDate,
11961177
lastDate: lastDate,
11971178
currentDate: currentDate,
1198-
selectableDayPredicate: selectableDayPredicate,
11991179
initialEntryMode: initialEntryMode,
12001180
helpText: helpText,
12011181
cancelText: cancelText,
@@ -1304,7 +1284,6 @@ class DateRangePickerDialog extends StatefulWidget {
13041284
this.restorationId,
13051285
this.switchToInputEntryModeIcon,
13061286
this.switchToCalendarEntryModeIcon,
1307-
this.selectableDayPredicate,
13081287
});
13091288

13101289
/// The date range that the date range picker starts with when it opens.
@@ -1433,9 +1412,6 @@ class DateRangePickerDialog extends StatefulWidget {
14331412
/// {@macro flutter.material.date_picker.switchToCalendarEntryModeIcon}
14341413
final Icon? switchToCalendarEntryModeIcon;
14351414

1436-
/// Function to provide full control over which [DateTime] can be selected.
1437-
final SelectableDayForRangePredicate? selectableDayPredicate;
1438-
14391415
@override
14401416
State<DateRangePickerDialog> createState() => _DateRangePickerDialogState();
14411417
}
@@ -1498,14 +1474,18 @@ class _DateRangePickerDialogState extends State<DateRangePickerDialog> with Rest
14981474

14991475
case DatePickerEntryMode.input:
15001476
// Validate the range dates
1501-
if (_selectedStart.value != null && _selectedEnd.value != null && _selectedStart.value!.isAfter(_selectedEnd.value!)) {
1502-
_selectedEnd.value = null;
1503-
}
1504-
if (_selectedStart.value != null && !_isDaySelectable(_selectedStart.value!)) {
1477+
if (_selectedStart.value != null &&
1478+
(_selectedStart.value!.isBefore(widget.firstDate) || _selectedStart.value!.isAfter(widget.lastDate))) {
15051479
_selectedStart.value = null;
15061480
// With no valid start date, having an end date makes no sense for the UI.
15071481
_selectedEnd.value = null;
1508-
} else if (_selectedEnd.value != null && !_isDaySelectable(_selectedEnd.value!)) {
1482+
}
1483+
if (_selectedEnd.value != null &&
1484+
(_selectedEnd.value!.isBefore(widget.firstDate) || _selectedEnd.value!.isAfter(widget.lastDate))) {
1485+
_selectedEnd.value = null;
1486+
}
1487+
// If invalid range (start after end), then just use the start date
1488+
if (_selectedStart.value != null && _selectedEnd.value != null && _selectedStart.value!.isAfter(_selectedEnd.value!)) {
15091489
_selectedEnd.value = null;
15101490
}
15111491
_entryMode.value = DatePickerEntryMode.calendar;
@@ -1517,16 +1497,6 @@ class _DateRangePickerDialogState extends State<DateRangePickerDialog> with Rest
15171497
});
15181498
}
15191499

1520-
bool _isDaySelectable(DateTime day) {
1521-
if (day.isBefore(widget.firstDate) || day.isAfter(widget.lastDate)) {
1522-
return false;
1523-
}
1524-
if (widget.selectableDayPredicate == null) {
1525-
return true;
1526-
}
1527-
return widget.selectableDayPredicate!(day, _selectedStart.value, _selectedEnd.value);
1528-
}
1529-
15301500
void _handleStartDateChanged(DateTime? date) {
15311501
setState(() => _selectedStart.value = date);
15321502
}
@@ -1565,7 +1535,6 @@ class _DateRangePickerDialogState extends State<DateRangePickerDialog> with Rest
15651535
selectedEndDate: _selectedEnd.value,
15661536
firstDate: widget.firstDate,
15671537
lastDate: widget.lastDate,
1568-
selectableDayPredicate: widget.selectableDayPredicate,
15691538
currentDate: widget.currentDate,
15701539
onStartDateChanged: _handleStartDateChanged,
15711540
onEndDateChanged: _handleEndDateChanged,
@@ -1618,7 +1587,6 @@ class _DateRangePickerDialogState extends State<DateRangePickerDialog> with Rest
16181587
initialEndDate: _selectedEnd.value,
16191588
firstDate: widget.firstDate,
16201589
lastDate: widget.lastDate,
1621-
selectableDayPredicate: widget.selectableDayPredicate,
16221590
onStartDateChanged: _handleStartDateChanged,
16231591
onEndDateChanged: _handleEndDateChanged,
16241592
autofocus: true,
@@ -1714,15 +1682,13 @@ class _CalendarRangePickerDialog extends StatelessWidget {
17141682
required this.onCancel,
17151683
required this.confirmText,
17161684
required this.helpText,
1717-
required this.selectableDayPredicate,
17181685
this.entryModeButton,
17191686
});
17201687

17211688
final DateTime? selectedStartDate;
17221689
final DateTime? selectedEndDate;
17231690
final DateTime firstDate;
17241691
final DateTime lastDate;
1725-
final SelectableDayForRangePredicate? selectableDayPredicate;
17261692
final DateTime? currentDate;
17271693
final ValueChanged<DateTime> onStartDateChanged;
17281694
final ValueChanged<DateTime?> onEndDateChanged;
@@ -1847,7 +1813,6 @@ class _CalendarRangePickerDialog extends StatelessWidget {
18471813
currentDate: currentDate,
18481814
onStartDateChanged: onStartDateChanged,
18491815
onEndDateChanged: onEndDateChanged,
1850-
selectableDayPredicate: selectableDayPredicate,
18511816
),
18521817
),
18531818
);
@@ -1873,7 +1838,6 @@ class _CalendarDateRangePicker extends StatefulWidget {
18731838
DateTime? initialEndDate,
18741839
required DateTime firstDate,
18751840
required DateTime lastDate,
1876-
required this.selectableDayPredicate,
18771841
DateTime? currentDate,
18781842
required this.onStartDateChanged,
18791843
required this.onEndDateChanged,
@@ -1904,9 +1868,6 @@ class _CalendarDateRangePicker extends StatefulWidget {
19041868
/// The latest allowable [DateTime] that the user can select.
19051869
final DateTime lastDate;
19061870

1907-
/// Function to provide full control over which [DateTime] can be selected.
1908-
final SelectableDayForRangePredicate? selectableDayPredicate;
1909-
19101871
/// The [DateTime] representing today. It will be highlighted in the day grid.
19111872
final DateTime currentDate;
19121873

@@ -1917,7 +1878,7 @@ class _CalendarDateRangePicker extends StatefulWidget {
19171878
final ValueChanged<DateTime?>? onEndDateChanged;
19181879

19191880
@override
1920-
State<_CalendarDateRangePicker> createState() => _CalendarDateRangePickerState();
1881+
_CalendarDateRangePickerState createState() => _CalendarDateRangePickerState();
19211882
}
19221883

19231884
class _CalendarDateRangePickerState extends State<_CalendarDateRangePicker> {
@@ -2020,7 +1981,6 @@ class _CalendarDateRangePickerState extends State<_CalendarDateRangePicker> {
20201981
lastDate: widget.lastDate,
20211982
displayedMonth: month,
20221983
onChanged: _updateSelection,
2023-
selectableDayPredicate: widget.selectableDayPredicate,
20241984
);
20251985
}
20261986

@@ -2409,7 +2369,6 @@ class _MonthItem extends StatefulWidget {
24092369
required this.firstDate,
24102370
required this.lastDate,
24112371
required this.displayedMonth,
2412-
required this.selectableDayPredicate,
24132372
}) : assert(!firstDate.isAfter(lastDate)),
24142373
assert(selectedDateStart == null || !selectedDateStart.isBefore(firstDate)),
24152374
assert(selectedDateEnd == null || !selectedDateEnd.isBefore(firstDate)),
@@ -2442,8 +2401,6 @@ class _MonthItem extends StatefulWidget {
24422401
/// The month whose days are displayed by this picker.
24432402
final DateTime displayedMonth;
24442403

2445-
final SelectableDayForRangePredicate? selectableDayPredicate;
2446-
24472404
@override
24482405
_MonthItemState createState() => _MonthItemState();
24492406
}
@@ -2509,10 +2466,7 @@ class _MonthItemState extends State<_MonthItem> {
25092466
Widget _buildDayItem(BuildContext context, DateTime dayToBuild, int firstDayOffset, int daysInMonth) {
25102467
final int day = dayToBuild.day;
25112468

2512-
final bool isDisabled = dayToBuild.isAfter(widget.lastDate) ||
2513-
dayToBuild.isBefore(widget.firstDate) ||
2514-
widget.selectableDayPredicate != null &&
2515-
!widget.selectableDayPredicate!(dayToBuild, widget.selectedDateStart, widget.selectedDateEnd);
2469+
final bool isDisabled = dayToBuild.isAfter(widget.lastDate) || dayToBuild.isBefore(widget.firstDate);
25162470
final bool isRangeSelected = widget.selectedDateStart != null && widget.selectedDateEnd != null;
25172471
final bool isSelectedDayStart = widget.selectedDateStart != null && dayToBuild.isAtSameMomentAs(widget.selectedDateStart!);
25182472
final bool isSelectedDayEnd = widget.selectedDateEnd != null && dayToBuild.isAtSameMomentAs(widget.selectedDateEnd!);
@@ -2754,7 +2708,7 @@ class _DayItemState extends State<_DayItem> {
27542708
if (widget.isSelectedDayStart || widget.isSelectedDayEnd) {
27552709
// The selected start and end dates gets a circle background
27562710
// highlight, and a contrasting text color.
2757-
itemStyle = itemStyle?.apply(color: dayForegroundColor);
2711+
itemStyle = textTheme.bodyMedium?.apply(color: dayForegroundColor);
27582712
decoration = BoxDecoration(
27592713
color: dayBackgroundColor,
27602714
shape: BoxShape.circle,
@@ -2777,15 +2731,12 @@ class _DayItemState extends State<_DayItem> {
27772731
style: _HighlightPainterStyle.highlightAll,
27782732
textDirection: textDirection,
27792733
);
2780-
if (widget.isDisabled) {
2781-
itemStyle = itemStyle?.apply(color: colorScheme.onSurface.withOpacity(0.38));
2782-
}
27832734
} else if (widget.isDisabled) {
2784-
itemStyle = itemStyle?.apply(color: colorScheme.onSurface.withOpacity(0.38));
2735+
itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.onSurface.withOpacity(0.38));
27852736
} else if (widget.isToday) {
27862737
// The current day gets a different text color and a circle stroke
27872738
// border.
2788-
itemStyle = itemStyle?.apply(color: colorScheme.primary);
2739+
itemStyle = textTheme.bodyMedium?.apply(color: colorScheme.primary);
27892740
decoration = BoxDecoration(
27902741
border: Border.all(color: colorScheme.primary),
27912742
shape: BoxShape.circle,
@@ -3071,7 +3022,6 @@ class _InputDateRangePicker extends StatefulWidget {
30713022
required DateTime lastDate,
30723023
required this.onStartDateChanged,
30733024
required this.onEndDateChanged,
3074-
required this.selectableDayPredicate,
30753025
this.helpText,
30763026
this.errorFormatText,
30773027
this.errorInvalidText,
@@ -3145,8 +3095,6 @@ class _InputDateRangePicker extends StatefulWidget {
31453095
/// {@macro flutter.material.datePickerDialog}
31463096
final TextInputType keyboardType;
31473097

3148-
final SelectableDayForRangePredicate? selectableDayPredicate;
3149-
31503098
@override
31513099
_InputDateRangePickerState createState() => _InputDateRangePickerState();
31523100
}
@@ -3226,22 +3174,12 @@ class _InputDateRangePickerState extends State<_InputDateRangePicker> {
32263174
String? _validateDate(DateTime? date) {
32273175
if (date == null) {
32283176
return widget.errorFormatText ?? MaterialLocalizations.of(context).invalidDateFormatLabel;
3229-
} else if (!_isDaySelectable(date)) {
3177+
} else if (date.isBefore(widget.firstDate) || date.isAfter(widget.lastDate)) {
32303178
return widget.errorInvalidText ?? MaterialLocalizations.of(context).dateOutOfRangeLabel;
32313179
}
32323180
return null;
32333181
}
32343182

3235-
bool _isDaySelectable(DateTime day) {
3236-
if (day.isBefore(widget.firstDate) || day.isAfter(widget.lastDate)) {
3237-
return false;
3238-
}
3239-
if (widget.selectableDayPredicate == null) {
3240-
return true;
3241-
}
3242-
return widget.selectableDayPredicate!(day, _startDate, _endDate);
3243-
}
3244-
32453183
void _updateController(TextEditingController controller, String text, bool selectText) {
32463184
TextEditingValue textEditingValue = controller.value.copyWith(text: text);
32473185
if (selectText) {

0 commit comments

Comments
 (0)