iCalendar library in pure Dart to parse, generate and respond to iCal / ics invites. Fully compliant with the iCalendar standard RFC 5545 and compliant to all VEvent functions of iTIP / RFC 5546.
Add this dependency your pubspec.yaml file:
dependencies:
enough_icalendar: ^0.10.0
The latest version or enough_icalendar
is .
Check out the full API documentation at https://pub.dev/documentation/enough_icalendar/latest/
Use enough_icalendar
to parse, generate and respond to iCalendar requests.
import 'package:enough_icalendar/enough_icalendar.dart';
Use VComponent.parse(String)
to parse the specified text.
final text = '''BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:[email protected]
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
RRULE:FREQ=YEARLY
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR''';
final icalendar = VComponent.parse(text) as VCalendar;
print(icalendar.productId); // -//hacksw/handcal//NONSGML v1.0//EN
final event = icalendar.event!;
print(event.summary); // Bastille Day Party
print(event.start); // 1997-06-14 at 17:00
print(event.end); // 1997-07-15 at 03:59:59
print(event.recurrenceRule?.toHumanReadableText()); // Annually
print(event.recurrenceRule
?.toHumanReadableText(languageCode: 'de')); // Jährlich
print(event.organizer?.commonName); // John Doe
print(event.organizer?.email); // [email protected]
print(event.geoLocation?.latitude); // 48.85299
print(event.geoLocation?.longitude); // 2.36885
}
Use VCalendar.createEvent(...)
to create a new invite easily.
Alternatively, for full low-lewel control instantiate VCalendar
yourself and add VComponent
children as you need.
Add any properties to the components to fill it with live.
Call the toString()
method to render your invite.
final invite = VCalendar.createEvent(
organizerEmail: '[email protected]',
attendeeEmails: ['[email protected]', '[email protected]', '[email protected]'],
rsvp: true,
start: DateTime(2021, 07, 21, 10, 00),
end: DateTime(2021, 07, 21, 11, 00),
location: 'Big meeting room',
url: Uri.parse('https://enough.de'),
summary: 'Discussion',
description:
'Let us discuss how to proceed with the enough_icalendar development. It seems that basic functionality is now covered. What\'s next?',
productId: 'enough_icalendar/v1',
);
print(invite);
return invite;
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar/v1
// VERSION:2.0
// METHOD:REQUEST
// BEGIN:VEVENT
// DTSTAMP:20210719T090527
// UID:[email protected]
// DTSTART:20210721T100000
// DTEND:20210721T110000
// ORGANIZER:mailto:[email protected]
// SUMMARY:Discussion
// DESCRIPTION:Let us discuss how to proceed with the enough_icalendar deve
// lopment. It seems that basic functionality is now covered. What's next?
// LOCATION:Big meeting room
// URL:https://enough.de
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// END:VEVENT
// END:VCALENDAR
Attendees can change their participant status with VCalendar.replyWithParticipantStatus(...)
. You either need
to specify the attendeeEmail
or the attendee
parameter. This reply will need to be sent to the organizer.
final reply = invite.replyWithParticipantStatus(ParticipantStatus.accepted,
attendeeEmail: '[email protected]');
print(reply);
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar
// VERSION:2.0
// METHOD:REPLY
// BEGIN:VEVENT
// ORGANIZER:mailto:[email protected]
// UID:[email protected]
// ATTENDEE;PARTSTAT=ACCEPTED:mailto:[email protected]
// DTSTAMP:20210719T093653
// REQUEST-STATUS:2.0;Success
// END:VEVENT
Attendees can delegate their event particpation to others by calling VCalendar.delegate(...)
. Two results are generated,
one iCalendar for the delegatee and another one for the organizer.
final delegationResult = original.delegate(
fromEmail: '[email protected]',
toEmail: '[email protected]',
);
print(delegationResult.requestForDelegatee);
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar/v1
// VERSION:2.0
// METHOD:REQUEST
// BEGIN:VEVENT
// DTSTAMP:20210719T173821
// UID:[email protected]
// DTSTART:20210721T100000
// DTEND:20210721T110000
// ORGANIZER:mailto:[email protected]
// SUMMARY:Discussion
// DESCRIPTION:Let us discuss how to proceed with the enough_icalendar deve
// lopment. It seems that basic functionality is now covered. What's next?
// LOCATION:Big meeting room
// URL:https://enough.de
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:[email protected]":mailto:c
// @example.com
// ATTENDEE;DELEGATED-FROM="mailto:[email protected]";RSVP=TRUE:mailto:e@exampl
// e.com
// END:VEVENT
// END:VCALENDAR
print(delegationResult.replyForOrganizer);
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar
// VERSION:2.0
// METHOD:REPLY
// BEGIN:VEVENT
// ORGANIZER:mailto:[email protected]
// UID:[email protected]
// ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:[email protected]":mailto:c
// @example.com
// DTSTAMP:20210719T173821
// REQUEST-STATUS:2.0;Success
// END:VEVENT
// END:VCALENDAR
Attendees can create counter proposals and organizers can accept or decline such proposals.
Attendees can create counter proposals with VCalendar.counter(...)
:
final counterProposal = invite.counter(
comment: 'This time fits better, also we need some more time.',
start: DateTime(2021, 07, 23, 10, 00),
end: DateTime(2021, 07, 23, 12, 00),
location: 'Carnegie Hall',
);
print(counterProposal);
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar/v1
// VERSION:2.0
// METHOD:COUNTER
// BEGIN:VEVENT
// UID:[email protected]
// ORGANIZER:mailto:[email protected]
// SUMMARY:Discussion
// DESCRIPTION:Let us discuss how to proceed with the enough_icalendar deve
// lopment. It seems that basic functionality is now covered. What's next?
// URL:https://enough.de
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// DTSTAMP:20210719T142550
// COMMENT:This time fits better, also we need some more time.
// LOCATION:Carnegie Hall
// DTSTART:20210723T100000
// DTEND:20210723T120000
// END:VEVENT
// END:VCALENDAR
Organizers can accept a counter proposal with VCalendar.acceptCounter(...)
.
The accepted proposal will have a higher sequence and the status automatically be set to EventStatus.confirmed.
The accepted and update invite is to be sent to all attendees by the organizer.
final accepted = counterProposal.acceptCounter(
comment: 'Accepted this proposed change of date and time');
print(accepted);
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar/v1
// VERSION:2.0
// METHOD:REQUEST
// BEGIN:VEVENT
// UID:[email protected]
// ORGANIZER:mailto:[email protected]
// SUMMARY:Discussion
// DESCRIPTION:Let us discuss how to proceed with the enough_icalendar deve
// lopment. It seems that basic functionality is now covered. What's next?
// URL:https://enough.de
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// LOCATION:Carnegie Hall
// DTSTART:20210723T100000
// DTEND:20210723T120000
// SEQUENCE:1
// DTSTAMP:20210719T143344
// STATUS:CONFIRMED
// COMMENT:Accepted this proposed change of date and time
// END:VEVENT
// END:VCALENDAR
Organizers can decline a counter proposal with VCalendar.declineCounter(...)
. The declined reply is to be sent to the proposing attendee.
final declined = counterProposal.declineCounter(
attendeeEmail: '[email protected]',
comment: 'Sorry, but we have to stick to the original schedule');
print(declined);
// prints this:
//
// BEGIN:VCALENDAR
// PRODID:enough_icalendar/v1
// VERSION:2.0
// METHOD:DECLINECOUNTER
// BEGIN:VEVENT
// UID:[email protected]
// ORGANIZER:mailto:[email protected]
// SUMMARY:Discussion
// DESCRIPTION:Let us discuss how to proceed with the enough_icalendar deve
// lopment. It seems that basic functionality is now covered. What's next?
// URL:https://enough.de
// ATTENDEE;RSVP=TRUE:mailto:[email protected]
// DTSTAMP:20210719T143715
// LOCATION:Carnegie Hall
// DTSTART:20210723T100000
// DTEND:20210723T120000
// COMMENT:Sorry, but we have to stick to the original schedule
// END:VEVENT
// END:VCALENDAR
enough_icalendar
supports all icalendar components and provides easy to access models:
VCALENDAR
VEVENT
VTIMEZONE
with theSTANDARD
andDAYLIGHT
subcomponentsVALARM
VFREEBUSY
VTODO
VJOURNAL
- Fully compliant with the iCalendar standard RFC 5545
- Compliant to all
VEvent
functions of iTIP / RFC 5546.
Please file feature requests and bugs at the issue tracker.
- Use enough_icalendar_export to export calendar invites to the native calendar
- Check out enough_mail_icalendar for handling calendar invites in emails
enough_icalendar
is null-safe.
enough_icalendar
is licensed under the commercial friendly Mozilla Public License 2.0