showAllowedDatesPicker function

Future<DateTime?> showAllowedDatesPicker({
  1. required BuildContext context,
  2. required List<DateTime> allowedDates,
  3. DateTime? initialDate,
  4. DateTime? firstDate,
  5. DateTime? lastDate,
  6. Locale? locale,
  7. String? helpText,
  8. String? cancelText,
  9. String? confirmText,
  10. TextDirection? textDirection,
})

Shows a date picker where ONLY dates in allowedDates are selectable.

  • If initialDate is not allowed, picks the nearest allowed date.
  • firstDate/lastDate default to the min/max from allowedDates (and are clamped to include them).

Implementation

Future<DateTime?> showAllowedDatesPicker({
  required BuildContext context,
  required List<DateTime> allowedDates,
  DateTime? initialDate,
  DateTime? firstDate,
  DateTime? lastDate,
  Locale? locale,
  String? helpText,
  String? cancelText,
  String? confirmText,
  TextDirection? textDirection,
}) async {
  if (allowedDates.isEmpty) return null;

  // Normalize, unique, sort
  final normalized = {
    for (final d in allowedDates) _dateOnly(d),
  }.toList()
    ..sort();

  final allowedSet = normalized.toSet();
  final minAllowed = normalized.first;
  final maxAllowed = normalized.last;

  final first = firstDate != null ? _dateOnly(firstDate) : minAllowed;
  final last = lastDate != null ? _dateOnly(lastDate) : maxAllowed;

  // Ensure bounds include the allowed range
  final boundFirst = first.isBefore(minAllowed) ? first : minAllowed;
  final boundLast = last.isAfter(maxAllowed) ? last : maxAllowed;

  // Choose initial
  DateTime init = _dateOnly(initialDate ?? DateTime.now());
  if (!allowedSet.contains(init)) {
    final nearest = _nearestAllowed(init, allowedSet);
    if (nearest == null) return null;
    init = nearest;
  }
  init = _clamp(init, boundFirst, boundLast);

  Widget builder(BuildContext ctx, Widget? child) {
    if (child == null) return Container();
    if (textDirection != null) {
      return Directionality(textDirection: textDirection, child: child);
    }
    return child;
  }

  return showDatePicker(
    context: context,
    initialDate: init,
    firstDate: boundFirst,
    lastDate: boundLast,
    helpText: helpText,
    cancelText: cancelText,
    confirmText: confirmText,
    locale: locale,
    selectableDayPredicate: (day) => allowedSet.contains(_dateOnly(day)),
    builder: builder,
  );
}