/// <summary> /// Tries to create a new calendar with the specified source/name/color. /// May fail depending on source. /// </summary> /// <remarks> /// This is only intended as a helper method for CreateEKCalendar, /// not to be called independently. /// </remarks> /// <returns>The created native calendar, or null on failure</returns> /// <param name="source">Calendar source (e.g. iCloud vs local vs gmail)</param> /// <param name="calendarName">Calendar name.</param> /// <param name="color">Calendar color.</param> private static EKCalendar SaveEKCalendar(EKSource source, string calendarName, string color = null) { var calendar = EKCalendar.Create(EKEntityType.Event, _eventStore); // Setup calendar to be inserted // calendar.Title = calendarName; if (!string.IsNullOrEmpty(color)) { calendar.CGColor = ColorConversion.ToCGColor(color); } calendar.Source = source; if (_eventStore.SaveCalendar(calendar, true, out NSError error)) { xLog.Debug($"Successfully saved calendar with source {source.Title}"); // TODO: Should we try calling GetCalendars to make sure that // the calendar isn't hidden?? // return(calendar); } else { xLog.Debug($"Tried and failed to save calendar with source {source.Title}"); } _eventStore.Reset(); return(null); }
/// <summary> /// Creates a new calendar or updates the name and color of an existing one. /// If a new calendar was created, the ExternalID property will be set on the Calendar object, /// to support future queries/updates. /// </summary> /// <param name="calendar">The calendar to create/update</param> /// <exception cref="System.ArgumentException">Calendar does not exist on device or is read-only</exception> /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception> /// <exception cref="System.InvalidOperationException">No active calendar sources available to create calendar on.</exception> /// <exception cref="Plugin.Calendars.Abstractions.PlatformException">Unexpected platform-specific error</exception> public static async Task AddOrUpdateCalendarAsync(Calendar calendar) { await RequestCalendarAccess().ConfigureAwait(false); EKCalendar deviceCalendar = null; if (!string.IsNullOrEmpty(calendar.ExternalID)) { deviceCalendar = _eventStore.GetCalendar(calendar.ExternalID); if (deviceCalendar == null) { throw new ArgumentException("Specified calendar does not exist on device", nameof(calendar)); } } if (deviceCalendar == null) { deviceCalendar = CreateEKCalendar(calendar.Name, calendar.Color); calendar.ExternalID = deviceCalendar.CalendarIdentifier; // Update color in case iOS assigned one if (deviceCalendar?.CGColor != null) { calendar.Color = ColorConversion.ToHexColor(deviceCalendar.CGColor); } } else { deviceCalendar.Title = calendar.Name; if (!string.IsNullOrEmpty(calendar.Color)) { deviceCalendar.CGColor = ColorConversion.ToCGColor(calendar.Color); } if (!_eventStore.SaveCalendar(deviceCalendar, true, out NSError error)) { // Without this, the eventStore will continue to return the "updated" // calendar even though the save failed! // (this obviously also resets any other changes, but since we own the eventStore // we can be pretty confident that won't be an issue) // _eventStore.Reset(); if (error.Domain == _ekErrorDomain && error.Code == (int)EKErrorCode.CalendarIsImmutable) { throw new ArgumentException(error.LocalizedDescription, new NSErrorException(error)); } else { throw new PlatformException(error.LocalizedDescription, new NSErrorException(error)); } } } }