device_calendar_plus_ios 0.11.0
device_calendar_plus_ios: ^0.11.0 copied to clipboard
iOS implementation of the device_calendar_plus plugin.
0.11.0 - 2026-10-19 #
Added #
- Event reads report the organizer from
EKEvent.organizer(#236).
Fixed #
- An iCloud source titled with the account's email (
user@me.com,@icloud.com,@mac.com) is now recognised:listSourcesreports it can create calendars, andcreateCalendarwithout a source uses it. Thanks @eikob (#233). An iCloud+ custom-domain title still isn't recognised, since EventKit gives no other way to tell iCloud from Google. updateRecurringwiththisAndFollowingthat makes an all-day series timed lost the new series' last occurrence across a DST change, and west of UTC left the split occurrence on the original series too. It now splits first and makes the new series timed in a second save (#232).updateRecurringwiththisAndFollowingthat clears the rule from a series' first occurrence now edits the series in place and keeps its ID.
0.10.0 - 2026-10-18 #
Changed #
- Breaking: implements the platform interface's new
android:/ios:options.CreateCalendarOptionsIosmoves to the platform interface asCalendarOptionsIos. Android-only options are ignored, and anupdateEventorupdateRecurringcall whose only change is Android-only writes nothing (#70).
0.9.2 - 2026-10-14 #
Fixed #
updateEventwithisAllDay: falseand new dates on one occurrence of an all-day series saves in two steps too — the other changes first, which detaches the occurrence, then the timed flip with the dates. EventKit's iCloud store persisted the hours as UTC wall clock when the detach and the flip happened in one save: a 09:00–10:00 occurrence in Los Angeles read back as 02:00–03:00, though the savedEKEventreported 16:00 UTC and its zone right up to the commit. The reverse of #210's flip; the local store, and so the simulator, got the one-step save right (#212). Either flip now checks that its first save detached the occurrence and fails withoperationFailed, the occurrence unchanged, when it did not, rather than flipping an attached occurrence in one save.updateRecurringwithallEventsand a start on another day of a rule that pins days (Monday of a Mon/Wed rule to its Wednesday) moves the series. EventKit read the.futureEventssave, with the loaded rule left untouched, as moving one occurrence: it left the master where it was, detached the first occurrence onto the new day with no rule, and the plugin returned that occurrence's/RID=ID. The kept rule is now set on the event again for such a move, which makes the save a series edit (#206).updateRecurringwiththisAndFollowingand a start on another day the kept rule generates splits the series at the occurrence, with the rule's remaining count carried over, instead of refusing the move while the rule pins days. The same re-set of the kept rule makes EventKit split the series rather than detach the occurrence (#194).updateEventwithisAllDay: trueon one occurrence of a timed series saves in two steps — the other changes and the dates first, which detaches the occurrence, then the all-day flip. EventKit's iCloud store persisted the detached occurrence's end a day late when the detach and the flip happened in one save, whatever end was written: a 9–10am occurrence read back as two days and a 23:30–00:30 one as three. The local store, and so the simulator, got the one-step save right. WithoutstartDateorendDate, on a one-off as well as an occurrence, the all-day span is now also written explicitly — local midnight of the start day through the last second of the last day the timed event touched, the span Android writes (#203) in #195's end convention — rather than left to EventKit.
0.9.1 - 2026-10-01 #
Fixed #
updateRecurringrefuses a start move with no new rule unless the existing rule generates the series' new start. It compared only the weekday, day of month and month the rule pins, so an ordinal BYDAY or a BYSETPOS series (the 4th Thursday of November, say) could move to another occurrence of its weekday (the 3rd Thursday), leaving the start on a day the rule never generates (#189). A move onto another day the rule generates (Monday to Wednesday of a Mon/Wed/Fri rule) is now allowed throughallEvents; withthisAndFollowinga move to another day still throws while the rule pins days, until iOS can split such a series (#194).updateRecurringon an all-day series addsduration(or keeps the existing span, when onlystartmoves) in calendar days rather than 86,400-second days, so a multi-day all-day series no longer loses or gains its last day when its span crosses a DST change (#195).updateEventandupdateRecurringwrite an all-day event's end as the last second of its last day, the way EventKit stores it. An exclusive midnight end written onto an existing all-day event read back as one more day, so a two-daydurationor end gave three (#195).
0.9.0 - 2026-09-30 #
Changed #
- Breaking:
updateEventanddeleteEventwithout atimestamprefuse a recurring series withINVALID_ARGUMENTSand write nothing; series-wide changes go throughupdateRecurring/deleteRecurring(#175). updateRecurringforwards areminderspatch. AthisAndFollowingsplit that clears the rule keeps the occurrence's reminders on the standalone event it leaves, as Android does (#175).
Fixed #
updateRecurring(allEvents)switching a timed series to all-day shifts the start in local time, where EventKit puts all-day events. It shifted in the series' stored zone, so a UTC-stored series landed on UTC midnight, which west of UTC is the day before: the series gained an extra first occurrence off its BYDAY and lost its last one. The day-move check reads each date in its own zone too (#187).updateRecurringanddeleteRecurringwiththisAndFollowingrefuse a non-recurring event withINVALID_ARGUMENTSand write nothing, as Android does. A timestamp that fell inside the event matched it, so the whole event was edited or deleted and the call reported success (#124).updateRecurringrefuses a start move with no new rule when it breaks any day the rule pins, as Android does. It checked only BYDAY when the rule had one, so a yearlyBYMONTH=11;BYDAY=4THseries could move to a Thursday in December (#188).- Modal plumbing (#123): a second
showEventModal/showCreateEventModalwhile one is showing failsOPERATION_FAILEDinstead of orphaning the first reply; swiping the view modal down resolves it; a modal is presented from the top of the presentation stack, so an app sheet that's already up no longer swallows it; and a missing root view controller failsOPERATION_FAILEDinstead of crashing withfatalError. createEventrefuses a recurrence rule it can't parse (aFREQother thanDAILY/WEEKLY/MONTHLY/YEARLY, or malformed input) withINVALID_ARGUMENTSand writes nothing, asupdateRecurringalready does. It used to drop the rule and save a one-off event (#125).- On iOS 18, answering a full-access prompt with Add Events Only
reports
writeOnlyrather thannotDetermined, so acreateEventfired straight after the prompt passes its permission gate. The request now waits briefly for the OS status to catch up with an ungranted answer (#137).
0.8.0 - 2026-09-26 #
Fixed #
updateRecurringwith a new rule anchors the series on the first day that rule generates. Changing a weekly series to another weekday left its start on the old day, so the first occurrence was stranded there. A rule that generates no occurrence at all is refused withINVALID_ARGUMENTSand the series is left untouched (#140).deleteCalendarrefuses a calendar EventKit marks immutable or read-only withREAD_ONLYbefore asking the store, instead of surfacing the refused remove asOPERATION_FAILED.updateCalendarnow checksisImmutabletoo, EventKit's own flag for "can't be edited or deleted" (#126).
0.7.1 - 2026-09-21 #
Fixed #
- A grant is honoured while
EKEventStore.authorizationStatusstill reports.notDetermined. On iOS 17+ the live status can lag the request handler, so the first call after a fresh grant failed its permission gate until the app restarted. The tier the OS confirmed is now remembered for the process and consulted only when it outranks a stale live status; a terminaldenied/restrictedalways wins, so a Settings revocation is never masked (#134). showCreateEventModalis gated only below iOS 17, where the editor runs in-process. On iOS 17+EKEventEditViewControlleris out-of-process and needs no calendar access (#121).- Full-access requests on iOS 17+ check
NSCalendarsFullAccessUsageDescription(what the OS demands) rather than the legacy key, and only when a prompt will actually fire — already-granted and terminal states get their status back without a configuration error (#121). createEventwith a namedcalendarIdunder write-only access reportspermissionDeniedinstead ofnotFound(#121).
Changed #
- The permission stack is restructured behind a
CalendarAuthorizationseam:CalendarAccessnormalises EventKit's status across the iOS 17 divide andPermissionServiceholds policy only. Swift unit tests cover the grant, revocation and configuration paths (#134).
0.7.0 - 2026-06-17 #
Added #
- Write-only access via
requestWriteOnlyAccessToEvents(iOS 17+). It is not a permanent ceiling — a later full request re-prompts and upgrades the app in-app (#89). createEventwith nocalendarIdwrites todefaultCalendarForNewEvents(#88).- Event reminders via
EKAlarm(relativeOffset:)onEKEvent.alarms(#87).
Changed #
- Simplified the permission request into a single iOS 17 availability dispatch (#108).
0.6.0 - 2026-06-16 #
Changed #
- Breaking:
updateRecurringtakes the anchored occurrence's new start (newStartMillis) instead ofstartMinuteOfDay.shiftStarttranslates the series anchor by the wall-clock delta (calendar-day count + time-of-day) in the event'sEKEvent.timeZone, so a move can change the day and time together and stays correct across DST (#103).
Behaviour #
updateRecurringrejects astartthat moves the day of a series whoseEKRecurrenceRulepins it (daysOfTheWeek/daysOfTheMonth/monthsOfTheYear) unless a new rule is also supplied (dayMoveConflictsWithRule).
0.5.2 - 2026-06-15 #
Fixed #
- EventKit reads and writes now run on a background serial queue instead of the main thread, so operations on large calendars no longer stall the UI (#79)
listEventsover a span longer than EventKit's ~4-year predicate limit now chunks the query into windows and de-duplicates recurring instances across window boundaries, so long ranges return every event exactly once, sorted (#94)createCalendarnow fails with a clear error on sources that can't hold calendars (e.g. subscribed/holiday sources) instead of an opaque EventKit failure (#96)updateRecurring(thisAndFollowing, recurrenceRule: Patch.clear())now splits the series — truncating the master before the occurrence and detaching a standalone non-recurring event at the split point — instead of collapsing the whole series into a single event. Matches Android's behavior (#93)
0.5.1 - 2026-06-15 #
Fixed #
showEventModal(edit: true)no longer crashes withNSInvalidArgumentException("Pushing a navigation controller is not supported").EKEventEditViewControlleris aUINavigationControllersubclass and is now presented directly instead of being wrapped in another navigation controller (#77)
0.5.0 - 2026-06-11 #
Changed #
- Breaking: recurring-edit split —
updateRecurring/deleteRecurringaccept onlyallEventsandthisAndFollowing(bothEKSpan.futureEvents); single occurrences go throughupdateEvent/deleteEventwith an occurrence timestamp (EKSpan.thisEvent) updateRecurringtime changes preserve each occurrence's date, replacing only the time-of-day components
Fixed #
- Occurrence edits validate before mutating the live
EKEvent; an edit whosestartDatepasses the occurrence's untouched end now fails withinvalidArguments(matching Android) instead of saving an inverted event
0.4.0 - 2026-05-25 #
Added #
updateRecurring()— series-level recurring-event edits withEventSpan(allEvents / thisAndFollowing / thisInstance), backed byEKSpan.futureEventsandEKSpan.thisEventdeleteRecurring()— sameEventSpansemantics onEKEventStore.removeurlfield on events viaEKEvent.urlPatch<T>support inupdateEvent()— null leaves a field unchanged,Patch.setwrites,Patch.clearnils the field on theEKEventeditflag onshowEvent()— presentsEKEventEditViewControllerinstead ofEKEventViewController
0.3.5 - 2026-04-20 #
Fixed #
- Calendar source lookup fallback when default source is unavailable (#13)
createCalendardefault fallback prefers iCloud over other CalDAV sources (#33)
0.3.3 - 2025-12-21 #
Fixed #
- Fixed parsing of
instanceIdfor events with@in their event ID (e.g., Google Calendar IDs likeabc123@google.com)
0.3.2 - 2025-12-19 #
Changed #
createCalendar()signature updated to accept optionalplatformOptionsparameter (ignored on iOS)
0.3.1 - 2025-11-07 #
Fixed #
showEvent()now properly stores result callback and calls it ineventViewController(_:didCompleteWith:)delegate method after modal is dismissed
0.3.0 - 2024-11-05 #
Changed #
- BREAKING:
deleteEvent()now always deletes entire series for recurring events usingEKSpan.futureEventson master event (removeddeleteAllInstancesparameter) - BREAKING:
updateEvent()now always updates entire series for recurring events usingEKSpan.futureEventson master event (removedupdateAllInstancesparameter) - Native code now extracts event ID from instance ID format automatically and fetches master event
Removed #
- BREAKING:
NOT_SUPPORTEDerror code (no longer needed)
0.2.0 - 2024-11-05 #
0.1.1 - 2024-11-04 #
Version sync with other packages. No functional changes.
0.1.0 - 2024-11-04 #
Initial release.