Events topic

Events

This is part of the kalender documentation.

The event model, and how to attach your own data to it. For where tiles are placed on screen, see Layout. For what they look like, see Appearance.

Custom Events

KalenderEvent is not generic. Attach custom data (title, color, description, and so on) by extending KalenderEvent directly.

class Event extends KalenderEvent {
  final String title;
  final String? description;
  final Color? color;

  Event({
    super.id,
    required super.start,
    required super.end,
    required this.title,
    this.description,
    this.color,
    super.interaction,
    super.multiDayRule,
    super.isAllDay,
  });

  // Rebuilds the fields this class adds. The calendar restores the rest.
  @override
  Event copyWithData({required DateTime start, required DateTime end}) {
    return Event(
      start: start,
      end: end,
      title: title,
      description: description,
      color: color,
    );
  }

  // A copy method of your own. It is not an override, so it takes whatever
  // parameters suit you. carryOver keeps the copy's identity and rule.
  Event copyWith({DateTime? start, DateTime? end, String? title, String? description, Color? color}) {
    return carryOver(
      Event(
        start: start ?? this.start,
        end: end ?? this.end,
        title: title ?? this.title,
        description: description ?? this.description,
        color: color ?? this.color,
      ),
    );
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return super == other &&
        other is Event &&
        other.title == title &&
        other.description == description &&
        other.color == color;
  }

  @override
  int get hashCode => Object.hash(super.hashCode, title, description, color);
}

Note

If you don't override == and hashCode, the calendar cannot detect changes to your custom fields and tiles will not update when those values change (e.g. via eventsController.updateEvent(...)). Always override both whenever you add fields to your KalenderEvent subclass.

The copy contract

The calendar calls withDateTimeRange on every drag and resize. It calls your copyWithData, then restores the id, interaction, multiDayRule and isAllDay that KalenderEvent holds, which is why copyWithData lists only your own fields. Call carryOver from a copy method of your own to get the same. A subclass with no copyWithData is flagged by the analyzer, since it is @mustBeOverridden.

Updating events

Use eventsController.updateEvent() to replace an existing event with an updated copy:

final original = eventsController.byId(someId)! as Event;
final updated = original.copyWith(title: 'Updated Title', color: Colors.red);
eventsController.updateEvent(event: original, updatedEvent: updated);

layoutEquals

Only override layoutEquals when a custom property changes the size or position of the tile, for example a flag that makes a tile render taller. It is not for content-only changes like color or title. The default implementation compares id, dateTimeRange, interaction, multiDayRule and isAllDay, which is sufficient for most cases.

Accessing custom fields in tile builders

Cast the event to your subclass:

TileComponents(
  tileBuilder: (context, event, tileRange) {
    final myEvent = event as Event;
    return Container(
      color: myEvent.color ?? Colors.blue,
      child: Text(myEvent.title),
    );
  },
)

Returning your subclass on event creation

Return your subclass from onEventCreate in KalenderView.callbacks:

KalenderCallbacks(
  onEventCreate: (event) => Event(
    start: event.start,
    end: event.end,
    title: 'New Event',
    color: Colors.blue,
  ),
  onEventCreated: (event) => eventsController.addEvent(event),
)

Multi-day and all-day events

A MultiDayRule decides whether an event renders in the multi-day header lane or in the day timeline. The rule is set on the view configuration (see Shared options) and defaults to counting events of 24 hours or longer as multi-day.

An event that is all-day by nature rather than by duration says so directly, and no rule is consulted:

KalenderEvent(start: range.start, end: range.end, isAllDay: true)

This puts it in the header lane whatever its duration. The date range is left alone, so an app wanting midnight to midnight supplies it. isAllDay defaults to false, where the rules below apply.

A single event can override the calendar's rule:

KalenderEvent(
  start: range.start,
  end: range.end,
  multiDayRule: const MultiDayRule.calendarDays(),
)

spansMultipleDays returns whether an event counts as multi-day, applying the same rules the calendar does:

event.spansMultipleDays(location: location, defaultRule: viewConfiguration.multiDayRule)

The event's own multiDayRule takes precedence when set. Otherwise defaultRule applies. Pass the calendar's location so that rules measuring calendar days, such as MultiDayRule.calendarDays, place midnight in the right timezone.

Classes

DefaultEventsController Events
The default EventsController for managing KalenderEvents.
DefaultEventStore Events
The default class for storing KalenderEvents.
EventsController Events
The EventsController is used to manage KalenderEvents.
EventStore Events
A class that maps KalenderEvents to dates.
KalenderEvent Events
Base class for events displayed in the calendar.
MultiDayRule Events
Decides whether an event belongs in the multi-day header lane rather than the day timeline.

Constants

kDefaultMultiDayRule → const MultiDayRule Events
The rule a calendar uses when nothing overrides it: 24 hours or longer.

Typedefs

DateToEventIds = Map<String, Set<String>> Events
Maps a date key from DefaultEventStore.toKey to the ids of the events on that date.
EventIdToEvent = Map<String, KalenderEvent> Events
Maps an event id to its KalenderEvent.
LocationDateIdMap = Map<String, DateToEventIds> Events
Maps a timezone location name to its DateToEventIds.
UpdatedEvent = (KalenderEvent, KalenderEvent) Events