expand static method

List<PlexCalendarEvent> expand(
  1. PlexCalendarEvent event, {
  2. required DateTime rangeStart,
  3. required DateTime rangeEnd,
})

Expands event into occurrences whose start date falls on or between rangeStart and rangeEnd (inclusive dates).

Stops at count instances, until (inclusive date), or rangeEnd, whichever comes first. Daily steps interval days; weekly steps interval weeks on the same weekday as PlexCalendarEvent.start.

Occurrence ids are '${event.id}#${yyyyMMdd}'. The master id is stored on PlexCalendarEvent.occurrenceOf. Start/end are shifted by the same duration. Events without a rule are returned unchanged when in range.

Implementation

static List<PlexCalendarEvent> expand(
  PlexCalendarEvent event, {
  required DateTime rangeStart,
  required DateTime rangeEnd,
}) {
  final DateTime from = _dateOnly(rangeStart);
  final DateTime to = _dateOnly(rangeEnd);
  if (to.isBefore(from)) return const <PlexCalendarEvent>[];

  final PlexCalendarRecurrence? rule = event.recurrence;
  if (rule == null || event.occurrenceOf != null) {
    return _inInclusiveDateRange(event.start, from, to)
        ? <PlexCalendarEvent>[event]
        : const <PlexCalendarEvent>[];
  }

  final int step = rule.interval < 1 ? 1 : rule.interval;
  final int? count = rule.count;
  if (count != null && count <= 0) return const <PlexCalendarEvent>[];

  final DateTime? untilDate =
      rule.until == null ? null : _dateOnly(rule.until!);
  final Duration span = event.end == null
      ? Duration.zero
      : event.end!.difference(event.start);

  final List<PlexCalendarEvent> out = <PlexCalendarEvent>[];
  DateTime cursor = event.start;
  int generated = 0;
  int guard = 0;

  while (guard++ < _maxIterations) {
    final DateTime cursorDay = _dateOnly(cursor);
    if (untilDate != null && cursorDay.isAfter(untilDate)) break;
    if (cursorDay.isAfter(to)) break;

    generated++;
    if (count != null && generated > count) break;

    if (!cursorDay.isBefore(from)) {
      out.add(
        PlexCalendarEvent(
          id: '${event.id}#${_yyyyMMdd(cursor)}',
          start: cursor,
          end: event.end == null ? null : cursor.add(span),
          title: event.title,
          color: event.color,
          occurrenceOf: event.occurrenceOf ?? event.id,
        ),
      );
    }

    if (count != null && generated >= count) break;
    cursor = _advance(cursor, rule.frequency, step);
  }

  return out;
}