ICalendar Library to Parse, Generate and Respond To ICal / Ics invites

enough_icalendar

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.

Installation

Add this dependency your pubspec.yaml file:

dependencies:
  enough_icalendar: ^0.8.0

The latest version or enough_icalendar is 

API Documentation

Check out the full API documentation at https://pub.dev/documentation/enough_icalendar/latest/

Usage

Use enough_icalendar to parse, generate and respond to iCalendar requests.

Import

import 'package:enough_icalendar/enough_icalendar.dart';

Parse iCalendar Requests

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:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
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); // john.doe@example.com
  print(event.geoLocation?.latitude); // 48.85299
  print(event.geoLocation?.longitude); // 2.36885
}

Generate an invite

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: 'a@example.com',
    attendeeEmails: ['a@example.com', 'b@example.com', 'c@example.com'],
    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:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // END:VEVENT
  // END:VCALENDAR

Accept or Decline an Invite

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: 'b@example.com');
  print(reply);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar
  // VERSION:2.0
  // METHOD:REPLY
  // BEGIN:VEVENT
  // ORGANIZER:mailto:a@example.com
  // UID:jovSCDXQ3sI5mBuu32@example.com
  // ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
  // DTSTAMP:20210719T093653
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT

Delegate Event Participation

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: 'c@example.com',
    toEmail: 'e@example.com',
  );
  print(delegationResult.requestForDelegatee);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // DTSTAMP:20210719T173821
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // ATTENDEE;DELEGATED-FROM="mailto:c@example.com";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:a@example.com
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // DTSTAMP:20210719T173821
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT
  // END:VCALENDAR

Creating and Reponding to Counter Proposals

Attendees can create counter proposals and organizers can accept or decline such proposals.

Create a Counter 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:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // DTSTAMP:20210719T142550
  // COMMENT:This time fits better, also we need some more time.
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // END:VEVENT
  // END:VCALENDAR

Accept a Counter Proposal

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:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // 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 

Decline a Counter Proposal

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: 'b@example.com',
      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:vmScK-AyJr0NX2nCsW@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:b@example.com
  // DTSTAMP:20210719T143715
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // COMMENT:Sorry, but we have to stick to the original schedule
  // END:VEVENT
  // END:VCALENDAR

Features and bugs

enough_icalendar supports all icalendar components and provides easy to access models:

  • VCALENDAR
  • VEVENT
  • VTIMEZONE with the STANDARD and DAYLIGHT subcomponents
  • VALARM
  • 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.

Related Projects

Null-Safety

enough_icalendar is null-safe.

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add enough_icalendar

With Flutter:

 $ flutter pub add enough_icalendar

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  enough_icalendar: ^0.9.0

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:enough_icalendar/enough_icalendar.dart';

example/enough_icalendar_example.dart

import 'package:enough_icalendar/enough_icalendar.dart';

void main() {
  parse();
  final invite = generate();
  changeParticipantStatus(invite);
  final counterProposal = counter(invite);
  acceptCounter(counterProposal);
  declineCounter(counterProposal);
  cancelEventForAll(invite);
  cancelForAttendee(invite, 'b@example.com');
  delegate(invite);
}

void parse() {
  final text = '''BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
RRULE:FREQ=YEARLY
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR''';
  // As text can contain different elements,
  // VComponent.parse returns the generic VComponent base class.
  // In this case I am sure it's a VCalendar, so I can cast it directly:
  final icalendar = VComponent.parse(text) as VCalendar;
  print(icalendar.productId);
  // I'm sure that this calendar contains an event:
  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); // john.doe@example.com
  print(event.geoLocation?.latitude); // 48.85299
  print(event.geoLocation?.longitude); // 2.36885
}

VCalendar generate() {
  // You can generate invites using this convenience method.
  // Take full control by creating VCalendar, VEvent, VTodo, etc yourself.
  final invite = VCalendar.createEvent(
    organizerEmail: 'a@example.com',
    attendeeEmails: ['a@example.com', 'b@example.com', 'c@example.com'],
    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('\nGenerated invite:');
  print(invite);
  return invite;
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // DTSTAMP:20210719T090527
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // END:VEVENT
  // END:VCALENDAR
}

void changeParticipantStatus(VCalendar invite) {
  final reply = invite.replyWithParticipantStatus(ParticipantStatus.accepted,
      attendeeEmail: 'b@example.com');
  print('\nAccepted by attendee b@example.com:');
  print(reply);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar
  // VERSION:2.0
  // METHOD:REPLY
  // BEGIN:VEVENT
  // ORGANIZER:mailto:a@example.com
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
  // DTSTAMP:20210719T093653
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT
}

void delegate(VCalendar invite) {
  final delegationResult = invite.delegate(
    fromEmail: 'c@example.com',
    toEmail: 'e@example.com',
  );
  print('\nRequest for delegatee:');
  print(delegationResult.requestForDelegatee);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // DTSTAMP:20210719T173821
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // ATTENDEE;DELEGATED-FROM="mailto:c@example.com";RSVP=TRUE:mailto:e@exampl
  //  e.com
  // END:VEVENT
  // END:VCALENDAR

  print('\nReply for organizer:');
  print(delegationResult.replyForOrganizer);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar
  // VERSION:2.0
  // METHOD:REPLY
  // BEGIN:VEVENT
  // ORGANIZER:mailto:a@example.com
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // DTSTAMP:20210719T173821
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT
  // END:VCALENDAR
}

VCalendar counter(VCalendar invite) {
  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('\nCounter proposal:');
  print(counterProposal);
  return counterProposal;
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:COUNTER
  // BEGIN:VEVENT
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // DTSTAMP:20210719T142550
  // COMMENT:This time fits better, also we need some more time.
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // END:VEVENT
  // END:VCALENDAR
}

void acceptCounter(VCalendar counterProposal) {
  // An organizer can accept a counter proposal.
  // The updated invite is then sent to all attendees.
  final accepted = counterProposal.acceptCounter(
      comment: 'Accepted this proposed change of date and time');
  // The accepted proposal will have a higher sequence and the status automatically be set to EventStatus.confirmed.
  print('\nAccepted counter proposal:');
  print(accepted);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // 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
}

void declineCounter(VCalendar counterProposal) {
  // An organizer can decline a counter proposal.
  // The declined notice is then sent to the proposing attendee.
  final declined = counterProposal.declineCounter(
      attendeeEmail: 'b@example.com',
      comment: 'Sorry, but we have to stick to the original schedule');
  print('\Declined counter proposal:');
  print(declined);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:DECLINECOUNTER
  // BEGIN:VEVENT
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:b@example.com
  // DTSTAMP:20210719T143715
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // COMMENT:Sorry, but we have to stick to the original schedule
  // END:VEVENT
  // END:VCALENDAR
}

void cancelEventForAll(VCalendar invite) {
  // An organizer can cancel the event completely:
  final cancelled =
      invite.cancelEvent(comment: 'Sorry, let\'s skip this completely');
  print('\nCancelled event:');
  print(cancelled);
  // prints this:
  //
  // METHOD:CANCEL
  // BEGIN:VEVENT
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // SEQUENCE:1
  // DTSTAMP:20210719T145004
  // STATUS:CANCELLED
  // COMMENT:Sorry, let's skip this completely
  // END:VEVENT
  // END:VCALENDAR
}

void cancelForAttendee(VCalendar invite, String cancelledAttendeeEmail) {
  // An organizer can cancel an event for specific attendees:
  final cancelChanges = invite.cancelEventForAttendees(
    cancelledAttendeeEmails: [cancelledAttendeeEmail],
    comment: 'You\'re off the hook, enjoy!',
  );
  print('\nChanges for cancelled attendees:');
  print(cancelChanges.requestForCancelledAttendees);
  // prints the following:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:CANCEL
  // BEGIN:VEVENT
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:b@example.com
  // SEQUENCE:1
  // DTSTAMP:20210719T162910
  // COMMENT:You're off the hook, enjoy!
  // END:VEVENT
  // END:VCALENDAR

  print('\nChanges for the group:');
  print(cancelChanges.requestUpdateForGroup);

  // prints the following:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // BEGIN:VEVENT
  // DTSTAMP:20210719T162910
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=FALSE;ROLE=NON-PARTICIPANT:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // END:VEVENT
  // END:VCALENDAR
} 

Download Details:

Author: Enough-Software

Source Code: https://github.com/Enough-Software/enough_icalendar

#flutter  #android  #ios 

What is GEEK

Buddha Community

ICalendar Library to Parse, Generate and Respond To ICal / Ics invites

amelia jones

1591340335

How To Take Help Of Referencing Generator

APA Referencing Generator

Many students use APA style as the key citation style in their assignment in university or college. Although, many people find it quite difficult to write the reference of the source. You ought to miss the names and dates of authors. Hence, APA referencing generator is important for reducing the burden of students. They can now feel quite easy to do the assignments on time.

The functioning of APA referencing generator

If you are struggling hard to write the APA referencing then you can take the help of APA referencing generator. It will create an excellent list. You are required to enter the information about the source. Just ensure that the text is credible and original. If you will copy references then it is a copyright violation.

You can use a referencing generator in just a click. It will generate the right references for all the sources. You are required to organize in alphabetical order. The generator will make sure that you will get good grades.

How to use APA referencing generator?

Select what is required to be cited such as journal, book, film, and others. You can choose the type of required citations list and enter all the required fields. The fields are dates, author name, title, editor name, and editions, name of publishers, chapter number, page numbers, and title of journals. You can click for reference to be generated and you will get the desired result.

Chicago Referencing Generator

Do you require the citation style? You can rely on Chicago Referencing Generator and will ensure that you will get the right citation in just a click. The generator is created to provide solutions to students to cite their research paper in Chicago style. It has proved to be the quickest and best citation generator on the market. The generator helps to sort the homework issues in few seconds. It also saves a lot of time and energy.

This tool helps researchers, professional writers, and students to manage and generate text citation essays. It will help to write Chicago style in a fast and easy way. It also provides details and directions for formatting and cites resources.

So, you must stop wasting the time and can go for Chicago Referencing Generator or APA referencing generator. These citation generators will help to solve the problem of citation issues. You can easily create citations by using endnotes and footnotes.

So, you can generate bibliographies, references, in-text citations, and title pages. These are fully automatic referencing style. You are just required to enter certain details about the citation and you will get the citation in the proper and required format.

So, if you are feeling any problem in doing assignment then you can take the help of assignment help.
If you require help for Assignment then livewebtutors is the right place for you. If you see our prices, you will observe that they are actually very affordable. Also, you can always expect a discount. Our team is capable and versatile enough to offer you exactly what you need, the best services for the prices you can afford.

read more:- Are you struggling to write a bibliography? Use Harvard referencing generator

#apa referencing generator #harvard referencing generator #chicago referencing generator #mla referencing generator #deakin referencing generator #oxford referencing generator

ICalendar Library to Parse, Generate and Respond To ICal / Ics invites

enough_icalendar

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.

Installation

Add this dependency your pubspec.yaml file:

dependencies:
  enough_icalendar: ^0.8.0

The latest version or enough_icalendar is 

API Documentation

Check out the full API documentation at https://pub.dev/documentation/enough_icalendar/latest/

Usage

Use enough_icalendar to parse, generate and respond to iCalendar requests.

Import

import 'package:enough_icalendar/enough_icalendar.dart';

Parse iCalendar Requests

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:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
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); // john.doe@example.com
  print(event.geoLocation?.latitude); // 48.85299
  print(event.geoLocation?.longitude); // 2.36885
}

Generate an invite

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: 'a@example.com',
    attendeeEmails: ['a@example.com', 'b@example.com', 'c@example.com'],
    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:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // END:VEVENT
  // END:VCALENDAR

Accept or Decline an Invite

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: 'b@example.com');
  print(reply);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar
  // VERSION:2.0
  // METHOD:REPLY
  // BEGIN:VEVENT
  // ORGANIZER:mailto:a@example.com
  // UID:jovSCDXQ3sI5mBuu32@example.com
  // ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
  // DTSTAMP:20210719T093653
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT

Delegate Event Participation

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: 'c@example.com',
    toEmail: 'e@example.com',
  );
  print(delegationResult.requestForDelegatee);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // DTSTAMP:20210719T173821
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // ATTENDEE;DELEGATED-FROM="mailto:c@example.com";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:a@example.com
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // DTSTAMP:20210719T173821
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT
  // END:VCALENDAR

Creating and Reponding to Counter Proposals

Attendees can create counter proposals and organizers can accept or decline such proposals.

Create a Counter 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:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // DTSTAMP:20210719T142550
  // COMMENT:This time fits better, also we need some more time.
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // END:VEVENT
  // END:VCALENDAR

Accept a Counter Proposal

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:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // 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 

Decline a Counter Proposal

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: 'b@example.com',
      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:vmScK-AyJr0NX2nCsW@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:b@example.com
  // DTSTAMP:20210719T143715
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // COMMENT:Sorry, but we have to stick to the original schedule
  // END:VEVENT
  // END:VCALENDAR

Features and bugs

enough_icalendar supports all icalendar components and provides easy to access models:

  • VCALENDAR
  • VEVENT
  • VTIMEZONE with the STANDARD and DAYLIGHT subcomponents
  • VALARM
  • 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.

Related Projects

Null-Safety

enough_icalendar is null-safe.

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add enough_icalendar

With Flutter:

 $ flutter pub add enough_icalendar

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  enough_icalendar: ^0.9.0

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:enough_icalendar/enough_icalendar.dart';

example/enough_icalendar_example.dart

import 'package:enough_icalendar/enough_icalendar.dart';

void main() {
  parse();
  final invite = generate();
  changeParticipantStatus(invite);
  final counterProposal = counter(invite);
  acceptCounter(counterProposal);
  declineCounter(counterProposal);
  cancelEventForAll(invite);
  cancelForAttendee(invite, 'b@example.com');
  delegate(invite);
}

void parse() {
  final text = '''BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
RRULE:FREQ=YEARLY
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR''';
  // As text can contain different elements,
  // VComponent.parse returns the generic VComponent base class.
  // In this case I am sure it's a VCalendar, so I can cast it directly:
  final icalendar = VComponent.parse(text) as VCalendar;
  print(icalendar.productId);
  // I'm sure that this calendar contains an event:
  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); // john.doe@example.com
  print(event.geoLocation?.latitude); // 48.85299
  print(event.geoLocation?.longitude); // 2.36885
}

VCalendar generate() {
  // You can generate invites using this convenience method.
  // Take full control by creating VCalendar, VEvent, VTodo, etc yourself.
  final invite = VCalendar.createEvent(
    organizerEmail: 'a@example.com',
    attendeeEmails: ['a@example.com', 'b@example.com', 'c@example.com'],
    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('\nGenerated invite:');
  print(invite);
  return invite;
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // DTSTAMP:20210719T090527
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // END:VEVENT
  // END:VCALENDAR
}

void changeParticipantStatus(VCalendar invite) {
  final reply = invite.replyWithParticipantStatus(ParticipantStatus.accepted,
      attendeeEmail: 'b@example.com');
  print('\nAccepted by attendee b@example.com:');
  print(reply);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar
  // VERSION:2.0
  // METHOD:REPLY
  // BEGIN:VEVENT
  // ORGANIZER:mailto:a@example.com
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ATTENDEE;PARTSTAT=ACCEPTED:mailto:b@example.com
  // DTSTAMP:20210719T093653
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT
}

void delegate(VCalendar invite) {
  final delegationResult = invite.delegate(
    fromEmail: 'c@example.com',
    toEmail: 'e@example.com',
  );
  print('\nRequest for delegatee:');
  print(delegationResult.requestForDelegatee);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // DTSTAMP:20210719T173821
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // ATTENDEE;DELEGATED-FROM="mailto:c@example.com";RSVP=TRUE:mailto:e@exampl
  //  e.com
  // END:VEVENT
  // END:VCALENDAR

  print('\nReply for organizer:');
  print(delegationResult.replyForOrganizer);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar
  // VERSION:2.0
  // METHOD:REPLY
  // BEGIN:VEVENT
  // ORGANIZER:mailto:a@example.com
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ATTENDEE;PARTSTAT=DELEGATED;DELEGATED-TO="mailto:e@example.com":mailto:c
  //  @example.com
  // DTSTAMP:20210719T173821
  // REQUEST-STATUS:2.0;Success
  // END:VEVENT
  // END:VCALENDAR
}

VCalendar counter(VCalendar invite) {
  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('\nCounter proposal:');
  print(counterProposal);
  return counterProposal;
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:COUNTER
  // BEGIN:VEVENT
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // DTSTAMP:20210719T142550
  // COMMENT:This time fits better, also we need some more time.
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // END:VEVENT
  // END:VCALENDAR
}

void acceptCounter(VCalendar counterProposal) {
  // An organizer can accept a counter proposal.
  // The updated invite is then sent to all attendees.
  final accepted = counterProposal.acceptCounter(
      comment: 'Accepted this proposed change of date and time');
  // The accepted proposal will have a higher sequence and the status automatically be set to EventStatus.confirmed.
  print('\nAccepted counter proposal:');
  print(accepted);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:REQUEST
  // BEGIN:VEVENT
  // UID:RQPhszGcPqYFR4fRUT@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // 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
}

void declineCounter(VCalendar counterProposal) {
  // An organizer can decline a counter proposal.
  // The declined notice is then sent to the proposing attendee.
  final declined = counterProposal.declineCounter(
      attendeeEmail: 'b@example.com',
      comment: 'Sorry, but we have to stick to the original schedule');
  print('\Declined counter proposal:');
  print(declined);
  // prints this:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:DECLINECOUNTER
  // BEGIN:VEVENT
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // ORGANIZER:mailto:a@example.com
  // 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:b@example.com
  // DTSTAMP:20210719T143715
  // LOCATION:Carnegie Hall
  // DTSTART:20210723T100000
  // DTEND:20210723T120000
  // COMMENT:Sorry, but we have to stick to the original schedule
  // END:VEVENT
  // END:VCALENDAR
}

void cancelEventForAll(VCalendar invite) {
  // An organizer can cancel the event completely:
  final cancelled =
      invite.cancelEvent(comment: 'Sorry, let\'s skip this completely');
  print('\nCancelled event:');
  print(cancelled);
  // prints this:
  //
  // METHOD:CANCEL
  // BEGIN:VEVENT
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=TRUE:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // SEQUENCE:1
  // DTSTAMP:20210719T145004
  // STATUS:CANCELLED
  // COMMENT:Sorry, let's skip this completely
  // END:VEVENT
  // END:VCALENDAR
}

void cancelForAttendee(VCalendar invite, String cancelledAttendeeEmail) {
  // An organizer can cancel an event for specific attendees:
  final cancelChanges = invite.cancelEventForAttendees(
    cancelledAttendeeEmails: [cancelledAttendeeEmail],
    comment: 'You\'re off the hook, enjoy!',
  );
  print('\nChanges for cancelled attendees:');
  print(cancelChanges.requestForCancelledAttendees);
  // prints the following:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // METHOD:CANCEL
  // BEGIN:VEVENT
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:b@example.com
  // SEQUENCE:1
  // DTSTAMP:20210719T162910
  // COMMENT:You're off the hook, enjoy!
  // END:VEVENT
  // END:VCALENDAR

  print('\nChanges for the group:');
  print(cancelChanges.requestUpdateForGroup);

  // prints the following:
  //
  // BEGIN:VCALENDAR
  // PRODID:enough_icalendar/v1
  // VERSION:2.0
  // BEGIN:VEVENT
  // DTSTAMP:20210719T162910
  // UID:vmScK-AyJr0NX2nCsW@example.com
  // DTSTART:20210721T100000
  // DTEND:20210721T110000
  // ORGANIZER:mailto:a@example.com
  // 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:a@example.com
  // ATTENDEE;RSVP=FALSE;ROLE=NON-PARTICIPANT:mailto:b@example.com
  // ATTENDEE;RSVP=TRUE:mailto:c@example.com
  // END:VEVENT
  // END:VCALENDAR
} 

Download Details:

Author: Enough-Software

Source Code: https://github.com/Enough-Software/enough_icalendar

#flutter  #android  #ios 

How To Create User-Generated Content? [A Simple Guide To Grow Your Brand]

This is image title

In this digital world, online businesses aspire to catch the attention of users in a modern and smarter way. To achieve it, they need to traverse through new approaches. Here comes to spotlight is the user-generated content or UGC.

What is user-generated content?
“ It is the content by users for users.”

Generally, the UGC is the unbiased content created and published by the brand users, social media followers, fans, and influencers that highlight their experiences with the products or services. User-generated content has superseded other marketing trends and fallen into the advertising feeds of brands. Today, more than 86 percent of companies use user-generated content as part of their marketing strategy.

In this article, we have explained the ten best ideas to create wonderful user-generated content for your brand. Let’s start without any further ado.

  1. Content From Social Media Platforms
    In the year 2020, there are 3.81 million people actively using social media around the globe. That is the reason social media content matters. Whenever users look at the content on social media that is posted by an individual, then they may be influenced by their content. Perhaps, it can be used to gain more customers or followers on your social media platforms.

This is image title

Generally, social media platforms help the brand to generate content for your users. Any user content that promotes your brand on the social media platform is the user-generated content for your business. When users create and share content on social media, they get 28% higher engagement than a standard company post.

Furthermore, you can embed your social media feed on your website also. you can use the Social Stream Designer WordPress plugin that will integrate various social media feeds from different social media platforms like Facebook, Twitter, Instagram, and many more. With this plugin, you can create a responsive wall on your WordPress website or blog in a few minutes. In addition to this, the plugin also provides more than 40 customization options to make your social stream feeds more attractive.

  1. Consumer Survey
    The customer survey provides powerful insights you need to make a better decision for your business. Moreover, it is great user-generated content that is useful for identifying unhappy consumers and those who like your product or service.

In general, surveys can be used to figure out attitudes, reactions, to evaluate customer satisfaction, estimate their opinions about different problems. Another benefit of customer surveys is that collecting outcomes can be quick. Within a few minutes, you can design and load a customer feedback survey and send it to your customers for their response. From the customer survey data, you can find your strengths, weaknesses, and get the right way to improve them to gain more customers.

  1. Run Contests
    A contest is a wonderful way to increase awareness about a product or service. Contest not just helps you to enhance the volume of user-generated content submissions, but they also help increase their quality. However, when you create a contest, it is important to keep things as simple as possible.

Additionally, it is the best way to convert your brand leads to valuable customers. The key to running a successful contest is to make sure that the reward is fair enough to motivate your participation. If the product is relevant to your participant, then chances are they were looking for it in the first place, and giving it to them for free just made you move forward ahead of your competitors. They will most likely purchase more if your product or service satisfies them.

Furthermore, running contests also improve the customer-brand relationship and allows more people to participate in it. It will drive a real result for your online business. If your WordPress website has Google Analytics, then track contest page visits, referral traffic, other website traffic, and many more.

  1. Review And Testimonials
    Customer reviews are a popular user-generated content strategy. One research found that around 68% of customers must see at least four reviews before trusting a brand. And, approximately 40 percent of consumers will stop using a business after they read negative reviews.

The business reviews help your consumers to make a buying decision without any hurdle. While you may decide to remove all the negative reviews about your business, those are still valuable user-generated content that provides honest opinions from real users. Customer feedback can help you with what needs to be improved with your products or services. This thing is not only beneficial to the next customer but your business as a whole.

This is image title

Reviews are powerful as the platform they are built upon. That is the reason it is important to gather reviews from third-party review websites like Google review, Facebook review, and many more, or direct reviews on a website. It is the most vital form of feedback that can help brands grow globally and motivate audience interactions.

However, you can also invite your customers to share their unique or successful testimonials. It is a great way to display your products while inspiring others to purchase from your website.

  1. Video Content
    A great video is a video that is enjoyed by visitors. These different types of videos, such as 360-degree product videos, product demo videos, animated videos, and corporate videos. The Facebook study has demonstrated that users spend 3x more time watching live videos than normal videos. With the live video, you can get more user-created content.

Moreover, Instagram videos create around 3x more comments rather than Instagram photo posts. Instagram videos generally include short videos posted by real customers on Instagram with the tag of a particular brand. Brands can repost the stories as user-generated content to engage more audiences and create valid promotions on social media.

Similarly, imagine you are browsing a YouTube channel, and you look at a brand being supported by some authentic customers through a small video. So, it will catch your attention. With the videos, they can tell you about the branded products, especially the unboxing videos displaying all the inside products and how well it works for them. That type of video is enough to create a sense of desire in the consumers.

Continue Reading

#how to get more user generated content #importance of user generated content #user generated content #user generated content advantages #user generated content best practices #user generated content pros and cons

sendy patel

sendy patel

1617086469

Online secure password generator

Create a secure password using our generator tool. Help prevent a security threat by getting a strong password today on hackthestuff.com.

#password #strong password generator #password generator #password generator tool #random generator tool #google generator tool

anita maity

anita maity

1619614811

Random Password Generator Using JavaScript, HTML & CSS

Random Password Generator is a program that automatically generates a password randomly. Those generated passwords are mix with numbers, alphabets, symbols, and punctuations. This type of program helps the user to create a strong password.

Step By Step Tutorial :https://cutt.ly/ZbiDeyL

#password generator #random password generator #python password generator #random password generator javascript #html #javascript