示例#1
0
        public static async Task<bool> AddReminderAsync(string id, CalendarEvent calEvent)
        {
            var ready = await CheckPermissionsGetCalendarAsync();
            if (!ready)
                return false;

            try
            {
                var evolveCal = await GetOrCreateEvolveCalendarAsync();
                //Create event and then create the reminder!
                await CrossCalendars.Current.AddOrUpdateEventAsync(evolveCal, calEvent);
                await CrossCalendars.Current.AddEventReminderAsync(calEvent, new CalendarEventReminder
                {
                     Method = CalendarReminderMethod.Default,
                     TimeBefore = TimeSpan.FromMinutes(20)
                });
                Settings.Current.SaveReminderId(id, calEvent.ExternalID);

                if(!Settings.Current.HasSetReminder)
                {
                    MessagingService.Current.SendMessage<MessagingServiceAlert>(MessageKeys.Message, new MessagingServiceAlert
                        {
                            Title = "Reminder Added",
                            Message = $"Reminder has been added. Please check the {evolveCal.Name} calendar.",
                            Cancel = "OK"
                        });
                }
                Settings.Current.HasSetReminder = true;
            }
            catch(Exception ex)
            {
                Debug.WriteLine("Unable to create event: " + ex);
                MessagingService.Current.SendMessage<MessagingServiceAlert>(MessageKeys.Message, new MessagingServiceAlert
                    {
                        Title= "Event Creation",
                        Message = "Unable to create calendar event, please check calendar app and try again.",
                        Cancel = "OK"
                    });
                return false;
            }
            return true;
        }
        public async void Calendars_AddOrUpdateEvents_StartAfterEndThrows()
        {
            var calendarEvent = new CalendarEvent { Name = "Bob", Start = DateTime.Today, End = DateTime.Today.AddDays(-1) };
            var calendar = new Calendar { Name = _calendarName };

            await _service.AddOrUpdateCalendarAsync(calendar);

            Assert.IsTrue(await _service.AddOrUpdateEventAsync(calendar, calendarEvent).ThrowsAsync<ArgumentException>(), "Exception wasn't thrown");

            // Ensure that calendar still has no events
            Assert.That(await _service.GetEventsAsync(calendar, DateTime.Today.AddMonths(-1), DateTime.Today.AddMonths(1)), Is.Empty,
                "Calendar has event, even after throwing");
        }
        public async void Calendars_AddOrUpdateEvents_StartAfterEndThrows()
        {
            var calendarEvent = new CalendarEvent { Name = "Bob", Start = DateTime.Today, End = DateTime.Today.AddDays(-1) };
            var calendar = new Calendar { Name = _calendarName };

            await _service.AddOrUpdateCalendarAsync(calendar);

            Assert.IsTrue(await _service.AddOrUpdateEventAsync(calendar, calendarEvent).ThrowsAsync<ArgumentException>(),
                "Exception wasn't thrown");
        }
        /// <summary>
        /// Adds an event reminder to specified calendar event
        /// </summary>
        /// <param name="calendarEvent">Event to add the reminder to</param>
        /// <param name="reminder">The reminder</param>
        /// <returns>Success or failure</returns>
        /// <exception cref="ArgumentException">If calendar event is not created or not valid</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<bool> AddEventReminderAsync(CalendarEvent calendarEvent, CalendarEventReminder reminder)
        {
            if (string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                throw new ArgumentException("Missing calendar event identifier", "calendarEvent");
            }
           
            
            var existingAppt = await _localApptStore.GetAppointmentAsync(calendarEvent.ExternalID);
            

            if (existingAppt == null)
            {
                throw new ArgumentException("Specified calendar event not found on device");
            }


            var appCalendar = await _localApptStore.GetAppointmentCalendarAsync(existingAppt.CalendarId);

            if(appCalendar == null)
            {
                throw new ArgumentException("Event does not have a valid calendar.");
            }

            existingAppt.Reminder = reminder?.TimeBefore ?? TimeSpan.FromMinutes(15);
            
            await appCalendar.SaveAppointmentAsync(existingAppt);

            return true;
        }
        /// <summary>
        /// Adds an event reminder to specified calendar event
        /// </summary>
        /// <param name="calendarEvent">Event to add the reminder to</param>
        /// <param name="reminder">The reminder</param>
        /// <returns>Success or failure</returns>
        /// <exception cref="ArgumentException">If calendar event is not created or not valid</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public Task<bool> AddEventReminderAsync(CalendarEvent calendarEvent, CalendarEventReminder reminder)
        {
            if (string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                throw new ArgumentException("Missing calendar event identifier", "calendarEvent");
            }

            //Grab current event
            var existingEvent = _eventStore.EventFromIdentifier(calendarEvent.ExternalID);
        
            if (existingEvent == null)
            {
                throw new ArgumentException("Specified calendar event not found on device");
            }

            //
            var seconds = -reminder?.TimeBefore.TotalSeconds ?? defaultTimeBefore;
            var alarm = EKAlarm.FromTimeInterval(seconds);

            existingEvent.AddAlarm(alarm);
            NSError error = null;
            if (!_eventStore.SaveEvent(existingEvent, EKSpan.ThisEvent, out error))
            {
                // Without this, the eventStore will continue to return the "updated"
                // event 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();


                throw new ArgumentException(error.LocalizedDescription, "reminder", new NSErrorException(error));
            }


            return Task.FromResult(true);
        }
        public async void Calendars_DeleteEvent_WrongCalendarReturnsFalse()
        {
            var calendar1 = await _service.CreateCalendarAsync(_calendarName);
            var calendar2 = await _service.CreateCalendarAsync(_calendarName + "2");
            var calendarEvent = new CalendarEvent
            {
                Name = "Bob",
                Start = DateTime.Now.AddDays(5),
                End = DateTime.Now.AddDays(5).AddHours(2),
                AllDay = false
            };
            await _service.AddOrUpdateEventAsync(calendar1, calendarEvent);

            Assert.IsFalse(await _service.DeleteEventAsync(calendar2, calendarEvent));
        }
        public async void Calendars_DeleteEvent_DeletesExistingEvent()
        {
            var calendarEvent = new CalendarEvent
            {
                Name = "Bob",
                Start = DateTime.Now.AddDays(5),
                End = DateTime.Now.AddDays(5).AddHours(2),
                AllDay = false
            };
            var calendar = await _service.CreateCalendarAsync(_calendarName);

            await _service.AddOrUpdateEventAsync(calendar, calendarEvent);

            Assert.IsTrue(await _service.DeleteEventAsync(calendar, calendarEvent));

            Assert.IsNull(await _service.GetEventByIdAsync(calendarEvent.ExternalID));
        }
        public async void Calendars_AddOrUpdateEvent_ReadonlyCalendarThrows()
        {
            var calendarEvent = new CalendarEvent { Name = "Bob", Start = DateTime.Today, End = DateTime.Today.AddHours(1) };
            var calendars = await _service.GetCalendarsAsync();
            var readonlyCalendars = calendars.Where(c => !c.CanEditEvents).ToList();

            // For iOS we can rely on the built-in read-only Birthdays calendar
            //
            var readonlyCalendar = readonlyCalendars.First(c => c.Name == "Birthdays");

            Assert.IsTrue(await _service.AddOrUpdateEventAsync(readonlyCalendar, calendarEvent).ThrowsAsync<PlatformException>(), "Exception wasn't thrown");

            // Ensure that calendar does not contain the event
            Assert.IsFalse((await _service.GetEventsAsync(readonlyCalendar, DateTime.Today.AddMonths(-1), DateTime.Today.AddMonths(1))).Any(e => e.Name == "Bob"),
                "Calendar contains the new event, even after throwing");
        }
        /// <summary>
        /// Add new event to a calendar or update an existing event.
        /// </summary>
        /// <param name="calendar">Destination calendar</param>
        /// <param name="calendarEvent">Event to add or update</param>
        /// <exception cref="System.ArgumentException">Calendar is not specified, does not exist on device, or is read-only</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            if (string.IsNullOrEmpty(calendar.ExternalID))
            {
                throw new ArgumentException("Missing calendar identifier", "calendar");
            }
            else
            {
                // Verify calendar exists (Android actually allows using a nonexistent calendar ID...)
                //
                var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

                if (deviceCalendar == null)
                {
                    throw new ArgumentException("Specified calendar not found on device");
                }
            }

            // Validate times
            if (calendarEvent.End < calendarEvent.Start)
            {
                throw new ArgumentException("End time may not precede start time", "calendarEvent");
            }

            bool updateExisting = false;
            long existingId = -1;

            await Task.Run(() =>
                {
                    if (long.TryParse(calendarEvent.ExternalID, out existingId))
                    {
                        var calendarId = GetCalendarIdForEventId(calendarEvent.ExternalID);

                        if (calendarId.HasValue && calendarId.Value.ToString() == calendar.ExternalID)
                        {
                            updateExisting = true;
                        }
                    }

                    var eventValues = new ContentValues();

                    eventValues.Put(CalendarContract.Events.InterfaceConsts.CalendarId,
                        calendar.ExternalID);
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.Title,
                        calendarEvent.Name);
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.Description,
                        calendarEvent.Description);
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtstart,
                        DateConversions.GetDateAsAndroidMS(calendarEvent.Start));
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend,
                        DateConversions.GetDateAsAndroidMS(calendarEvent.End));
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.AllDay,
                        calendarEvent.AllDay);
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation,
                        calendarEvent.Location ?? string.Empty);

                    eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
                        Java.Util.TimeZone.Default.ID);

                    if (!updateExisting)
                    {
                        calendarEvent.ExternalID = Insert(_eventsUri, eventValues);
                    }
                    else
                    {
                        Update(_eventsUri, existingId, eventValues);
                    }
                });
        }
        /// <summary>
        /// Gets a single calendar event by platform-specific ID.
        /// </summary>
        /// <param name="externalId">Platform-specific calendar event identifier</param>
        /// <returns>The corresponding calendar event, or null if not found</returns>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public Task<CalendarEvent> GetEventByIdAsync(string externalId)
        {
            // Note that this is slightly different from the GetEvents projection
            // due to the Instances API vs Events API (specifically, IDs)
            //
            string[] eventsProjection =
            {
                CalendarContract.Events.InterfaceConsts.Id,
                CalendarContract.Events.InterfaceConsts.Title,
                CalendarContract.Events.InterfaceConsts.Description,
                CalendarContract.Events.InterfaceConsts.Dtstart,
                CalendarContract.Events.InterfaceConsts.Dtend,
                CalendarContract.Events.InterfaceConsts.EventLocation,
                CalendarContract.Events.InterfaceConsts.AllDay
            };
                    
            return Task.Run<CalendarEvent>(() => 
            {
                CalendarEvent calendarEvent = null;
                var cursor = Query(
                    ContentUris.WithAppendedId(_eventsUri, long.Parse(externalId)),
                    eventsProjection);

                try
                {
                    if (cursor.MoveToFirst())
                    {
                        calendarEvent = new CalendarEvent
                        {
                            Name = cursor.GetString(CalendarContract.Events.InterfaceConsts.Title),
                            ExternalID = cursor.GetString(CalendarContract.Events.InterfaceConsts.Id),
                            Description = cursor.GetString(CalendarContract.Events.InterfaceConsts.Description),
                            Start = cursor.GetDateTime(CalendarContract.Events.InterfaceConsts.Dtstart),
                            End = cursor.GetDateTime(CalendarContract.Events.InterfaceConsts.Dtend),
                            Location = cursor.GetString(CalendarContract.Events.InterfaceConsts.EventLocation),
                            AllDay = cursor.GetBoolean(CalendarContract.Events.InterfaceConsts.AllDay)
                        };
                    }
                }
                catch (Java.Lang.Exception ex)
                {
                    throw new PlatformException(ex.Message, ex);
                }
                finally
                {
                    cursor.Close();
                }
                
                return calendarEvent;
            });
        }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task<bool> DeleteEventAsync(Calendar calendar, CalendarEvent cev)
 {
     throw new NotSupportedException();
 }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task<bool> AddEventReminderAsync(CalendarEvent calendarEvent, CalendarEventReminder reminder)
 {
     throw new NotSupportedException();
 }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent)
 {
     throw new NotSupportedException();
 }
        /// <summary>
        /// Removes an event from the specified calendar.
        /// </summary>
        /// <param name="calendar">Calendar to remove event from</param>
        /// <param name="calendarEvent">Event to remove</param>
        /// <returns>True if successfully removed</returns>
        /// <exception cref="System.ArgumentException">Calendar is read-only</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<bool> DeleteEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            if (string.IsNullOrEmpty(calendar.ExternalID) || string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                return false;
            }

            await EnsureInitializedAsync().ConfigureAwait(false);

            bool deleted = false;
            //var appCalendar = await _localApptStore.GetAppointmentCalendarAsync(calendar.ExternalID).ConfigureAwait(false);
            var appCalendar = await GetLocalCalendarAsync(calendar.ExternalID).ConfigureAwait(false);

            if (appCalendar != null)
            {
                // Verify that event actually exists on calendar
                //
                var appt = await appCalendar.GetAppointmentAsync(calendarEvent.ExternalID).ConfigureAwait(false);

                // The second check is because AppointmentCalendar.GetAppointmentAsync will apparently still
                // return events if they are associated with a different calendar...
                //
                if (appt != null && appt.CalendarId == appCalendar.LocalId)
                {
                    // Sometimes DeleteAppointmentAsync throws UnauthorizedException if the event doesn't exist?
                    // And sometimes it just fails silently?
                    // Well, hopefully the above check will help avoid either case...
                    //
                    await appCalendar.DeleteAppointmentAsync(calendarEvent.ExternalID).ConfigureAwait(false);
                    deleted = true;
                }
            }
            else
            {
                // Check for calendar from non-local appt store
                // If we get it from there, then error that it's not writeable
                // else, it just doesn't exist, so return false

                appCalendar = await _apptStore.GetAppointmentCalendarAsync(calendar.ExternalID).ConfigureAwait(false);

                if (appCalendar != null)
                {
                    throw new ArgumentException("Cannot delete event from readonly calendar", "calendar");
                }
            }

            return deleted;
        }
示例#15
0
        public async void Calendars_AddOrUpdateEvent_UnspecifiedCalendarThrows()
        {
            var calendarEvent = new CalendarEvent { Name = "Bob", Start = DateTime.Today, End = DateTime.Today.AddHours(1) };
            var calendar = new Calendar { Name = _calendarName };

            Assert.IsTrue(await _service.AddOrUpdateEventAsync(calendar, calendarEvent).ThrowsAsync<ArgumentException>(), "Exception wasn't thrown");
        }
        /// <summary>
        /// Adds an event reminder to specified calendar event
        /// </summary>
        /// <param name="calendarEvent">Event to add the reminder to</param>
        /// <param name="reminder">The reminder</param>
        /// <returns>Success or failure</returns>
        /// <exception cref="ArgumentException">If calendar event is not created or not valid</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<bool> AddEventReminderAsync(CalendarEvent calendarEvent, CalendarEventReminder reminder)
        {
            if (string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                throw new ArgumentException("Missing calendar event identifier", "calendarEvent");
            }
            // Verify calendar event exists 
            var existingAppt = await GetEventByIdAsync(calendarEvent.ExternalID).ConfigureAwait(false);

            if (existingAppt == null)
            {
                throw new ArgumentException("Specified calendar event not found on device");
            }
            
            return await Task.Run(() =>
            {
                var reminderValues = new ContentValues();
                reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Minutes, reminder?.TimeBefore.TotalMinutes ?? 15);
                reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.EventId, calendarEvent.ExternalID);
                switch(reminder.Method)
                {
                    case CalendarReminderMethod.Alert:
                        reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Method, (int)RemindersMethod.Alert);
                        break;
                    case CalendarReminderMethod.Default:
                        reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Method, (int)RemindersMethod.Default);
                        break;
                    case CalendarReminderMethod.Email:
                        reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Method, (int)RemindersMethod.Email);
                        break;
                    case CalendarReminderMethod.Sms:
                        reminderValues.Put(CalendarContract.Reminders.InterfaceConsts.Method, (int)RemindersMethod.Sms);
                        break;

                }
                var uri = CalendarContract.Reminders.ContentUri;
                Insert(uri, reminderValues);
                

                return true;
            });

        }
示例#17
0
        public async void Calendars_AddOrUpdateEvent_NonexistentCalendarThrows()
        {
            var calendarEvent = new CalendarEvent { Name = "Bob", Start = DateTime.Today, End = DateTime.Today.AddHours(1) };
            var calendar = new Calendar { Name = _calendarName };

            // Create/delete calendar so we have a valid ID for a nonexistent calendar
            //
            await _service.AddOrUpdateCalendarAsync(calendar);
            await _service.DeleteCalendarAsync(calendar);

            Assert.IsTrue(await _service.AddOrUpdateEventAsync(calendar, calendarEvent).ThrowsAsync<ArgumentException>(), "Exception wasn't thrown");
        }
        /// <summary>
        /// Removes an event from the specified calendar.
        /// </summary>
        /// <param name="calendar">Calendar to remove event from</param>
        /// <param name="calendarEvent">Event to remove</param>
        /// <returns>True if successfully removed</returns>
        /// <exception cref="System.ArgumentException">Calendar is read-only</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<bool> DeleteEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            long existingId = -1;

            // Even though a Calendar was passed-in, we get this to both verify
            // that the calendar exists and to make sure we have accurate permissions
            // (rather than trusting the permissions that were passed to us...)
            //
            var existingCal = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

            if (existingCal == null)
            {
                return false;
            }
            else if (!existingCal.CanEditEvents)
            {
                throw new ArgumentException("Cannot delete event from readonly calendar", "calendar");
            }

            if (long.TryParse(calendarEvent.ExternalID, out existingId))
            {
                return await Task.Run<bool>(() =>
                    {
                        var calendarId = GetCalendarIdForEventId(calendarEvent.ExternalID);

                        if (calendarId.HasValue && calendarId.Value.ToString() == calendar.ExternalID)
                        {
                            var eventsUri = CalendarContract.Events.ContentUri;
                            return Delete(eventsUri, existingId);
                        }
                        return false;
                    });
            }

            return false;
        }
示例#19
0
        public async void Calendars_AddOrUpdateEvents_CopiesEventsBetweenCalendars()
        {
            var calendarEvent = new CalendarEvent
            {
                Name = "Bob",
                Start = DateTime.Today.AddDays(5),
                End = DateTime.Today.AddDays(5).AddHours(2),
                AllDay = false
            };
            var calendarSource = new Calendar { Name = _calendarName };
            var calendarTarget = new Calendar { Name = _calendarName + " copy destination" };

            await _service.AddOrUpdateCalendarAsync(calendarSource);
            await _service.AddOrUpdateCalendarAsync(calendarTarget);

            await _service.AddOrUpdateEventAsync(calendarSource, calendarEvent);

            var sourceEvents = await _service.GetEventsAsync(calendarSource, DateTime.Today, DateTime.Today.AddDays(30));

            //await _service.AddOrUpdateEventsAsync(calendarTarget, sourceEvents);
            foreach (var cev in sourceEvents)
            {
                await _service.AddOrUpdateEventAsync(calendarTarget, cev);
            }

            var targetEvents = await _service.GetEventsAsync(calendarTarget, DateTime.Today, DateTime.Today.AddDays(30));

            // Requery source events, just to be extra sure
            sourceEvents = await _service.GetEventsAsync(calendarSource, DateTime.Today, DateTime.Today.AddDays(30));

            // Make sure the events are the same...
            Assert.That(targetEvents, Is.EqualTo(sourceEvents).Using<CalendarEvent>(_eventComparer));

            // ...except for their IDs! (i.e., they are actually unique copies)
            Assert.That(targetEvents.Select(e => e.ExternalID).ToList(), Is.Not.EqualTo(sourceEvents.Select(e => e.ExternalID).ToList()));
        }
示例#20
0
        public async Task Calendars_AddOrUpdateEvent_ReadonlyCalendarThrows()
        {
            var calendarEvent = new CalendarEvent { Name = "Bob", Start = DateTime.Today, End = DateTime.Today.AddHours(1) };
            var calendars = await _service.GetCalendarsAsync();
            var readonlyCalendars = calendars.Where(c => !c.CanEditEvents).ToList();
            var readonlyCalendar = readonlyCalendars.First();

            // TODO: Handle more specific exception

            Assert.IsTrue(await _service.AddOrUpdateEventAsync(readonlyCalendar, calendarEvent).ThrowsAsync<ArgumentException>(), "Exception wasn't thrown");
        }
示例#21
0
        public async void Calendars_DeleteEvent_NonexistentCalendarReturnsFalse()
        {
            // Create and delete a calendar and event so that we have valid IDs for nonexistent calendar/event
            //
            var calendar = await _service.CreateCalendarAsync(_calendarName);
            var calendarEvent = new CalendarEvent
            {
                Name = "Bob",
                Start = DateTime.Now.AddDays(5),
                End = DateTime.Now.AddDays(5).AddHours(2),
                AllDay = false
            };
            await _service.AddOrUpdateEventAsync(calendar, calendarEvent);
            await _service.DeleteCalendarAsync(calendar);

            Assert.IsFalse(await _service.DeleteEventAsync(calendar, calendarEvent));
        }
示例#22
0
        public async Task Calendars_AddOrUpdateEvents_CopiesEventsBetweenCalendars()
        {
            var calendarEvent = new CalendarEvent
            {
                Name = "Bob",
                Start = DateTime.Today.AddDays(5),
                End = DateTime.Today.AddDays(5).AddHours(2),
                AllDay = false
            };
            var calendarSource = new Calendar { Name = _calendarName };
            var calendarTarget = new Calendar { Name = _calendarName + " copy destination" };

            await _service.AddOrUpdateCalendarAsync(calendarSource);
            await _service.AddOrUpdateCalendarAsync(calendarTarget);

            await _service.AddOrUpdateEventAsync(calendarSource, calendarEvent);

            var sourceEvents = await _service.GetEventsAsync(calendarSource, DateTime.Today, DateTime.Today.AddDays(30));

            await _service.AddOrUpdateEventAsync(calendarTarget, calendarEvent);

            var targetEvents = await _service.GetEventsAsync(calendarTarget, DateTime.Today, DateTime.Today.AddDays(30));

            // Requery source events, just to be extra sure
            sourceEvents = await _service.GetEventsAsync(calendarSource, DateTime.Today, DateTime.Today.AddDays(30));

            // Make sure the events are the same...
            CollectionAssert.AreEqual((ICollection)sourceEvents, (ICollection)targetEvents, _eventComparer);

            // ...except for their IDs! (i.e., they are actually unique copies)
            CollectionAssert.AreNotEqual(sourceEvents.Select(e => e.ExternalID).ToList(), targetEvents.Select(e => e.ExternalID).ToList());
        }
        /// <summary>
        /// Add new event to a calendar or update an existing event.
        /// Throws if Calendar ID is empty, calendar does not exist, or calendar is read-only.
        /// </summary>
        /// <param name="calendar">Destination calendar</param>
        /// <param name="calendarEvent">Event to add or update</param>
        /// <exception cref="System.ArgumentException">Calendar is not specified, does not exist on device, or is read-only</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            await RequestCalendarAccess().ConfigureAwait(false);

            EKCalendar deviceCalendar = null;

            if (string.IsNullOrEmpty(calendar.ExternalID))
            {
                throw new ArgumentException("Missing calendar identifier", "calendar");
            }
            else
            {
                deviceCalendar = _eventStore.GetCalendar(calendar.ExternalID);

                if (deviceCalendar == null)
                {
                    throw new ArgumentException("Specified calendar not found on device");
                }
            }

            EKEvent iosEvent = null;

            // If Event already corresponds to an existing EKEvent in the target
            // Calendar, then edit that instead of creating a new one.
            //
            if (!string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                var existingEvent = _eventStore.EventFromIdentifier(calendarEvent.ExternalID);

                if (existingEvent.Calendar.CalendarIdentifier == deviceCalendar.CalendarIdentifier)
                {
                    iosEvent = existingEvent;
                }
            }

            if (iosEvent == null)
            {
                iosEvent = EKEvent.FromStore(_eventStore);
            }

            iosEvent.Title = calendarEvent.Name;
            iosEvent.Notes = calendarEvent.Description;
            iosEvent.AllDay = calendarEvent.AllDay;
            iosEvent.Location = calendarEvent.Location ?? string.Empty;
            iosEvent.StartDate = calendarEvent.Start.ToNSDate();

            // If set to AllDay and given an EndDate of 12am the next day, EventKit
            // assumes that the event consumes two full days.
            // (whereas WinPhone/Android consider that one day, and thus so do we)
            //
            iosEvent.EndDate = calendarEvent.AllDay ? calendarEvent.End.AddMilliseconds(-1).ToNSDate() : calendarEvent.End.ToNSDate();
            iosEvent.Calendar = deviceCalendar;

            NSError error = null;
            if (!_eventStore.SaveEvent(iosEvent, EKSpan.ThisEvent, out error))
            {
                // Without this, the eventStore will continue to return the "updated"
                // event 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();

                // Technically, probably any ekerrordomain error would be an ArgumentException?
                // - but we don't necessarily know *which* argument (at least not without the code)
                // - for now, just focusing on the start > end scenario and translating the rest to PlatformException. Can always add more later.

                if (error.Domain == _ekErrorDomain && error.Code == (int)EKErrorCode.DatesInverted)
                {
                    throw new ArgumentException(error.LocalizedDescription, new NSErrorException(error));
                }
                else
                {
                    throw new PlatformException(error.LocalizedDescription, new NSErrorException(error));
                }
            }

            calendarEvent.ExternalID = iosEvent.EventIdentifier;
        }
示例#24
0
        public async Task Calendars_DeleteEvent_NonexistentEventReturnsFalse()
        {
            var calendar = await _service.CreateCalendarAsync(_calendarName);

            // Create and delete an event so that we have a valid event ID for a nonexistent event
            //
            var calendarEvent = new CalendarEvent
            {
                Name = "Bob",
                Start = DateTime.Now.AddDays(5),
                End = DateTime.Now.AddDays(5).AddHours(2),
                AllDay = false
            };
            await _service.AddOrUpdateEventAsync(calendar, calendarEvent);
            await _service.DeleteEventAsync(calendar, calendarEvent);

            Assert.IsFalse(await _service.DeleteEventAsync(calendar, calendarEvent));
        }
        /// <summary>
        /// Removes an event from the specified calendar.
        /// </summary>
        /// <param name="calendar">Calendar to remove event from</param>
        /// <param name="calendarEvent">Event to remove</param>
        /// <returns>True if successfully removed</returns>
        /// <exception cref="System.ArgumentException">Calendar is read-only</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<bool> DeleteEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            if (string.IsNullOrEmpty(calendar.ExternalID) || string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                return false;
            }
            
            await RequestCalendarAccess().ConfigureAwait(false);

            var deviceCalendar = _eventStore.GetCalendar(calendar.ExternalID);

            if (deviceCalendar == null)
            {
                return false;
            }

            var iosEvent = _eventStore.EventFromIdentifier(calendarEvent.ExternalID);

            if (iosEvent == null || iosEvent.Calendar.CalendarIdentifier != deviceCalendar.CalendarIdentifier)
            {
                return false;
            }

            NSError error = null;
            if (!_eventStore.RemoveEvent(iosEvent, EKSpan.ThisEvent, true, out error))
            {
                // Without this, the eventStore may act like the remove succeeded.
                // (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.CalendarReadOnly)
                {
                    throw new ArgumentException(error.LocalizedDescription, "calendar", new NSErrorException(error));
                }
                else
                {
                    throw new PlatformException(error.LocalizedDescription, new NSErrorException(error));
                }
            }

            return true;
        }
        /// <summary>
        /// Add new event to a calendar or update an existing event.
        /// Throws if Calendar ID is empty, calendar does not exist, or calendar is read-only.
        /// </summary>
        /// <param name="calendar">Destination calendar</param>
        /// <param name="calendarEvent">Event to add or update</param>
        /// <exception cref="System.ArgumentException">Calendar is not specified, does not exist on device, or is read-only</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            await EnsureInitializedAsync().ConfigureAwait(false);

            AppointmentCalendar appCalendar = null;

            if (string.IsNullOrEmpty(calendar.ExternalID))
            {
                throw new ArgumentException("Missing calendar identifier", "calendar");
            }
            else
            {
                appCalendar = await GetAndValidateLocalCalendarAsync(calendar.ExternalID).ConfigureAwait(false);
            }

            Appointment appt = null;

            // If Event already corresponds to an existing Appointment in the target
            // Calendar, then edit that instead of creating a new one.
            //
            if (!string.IsNullOrEmpty(calendarEvent.ExternalID))
            {
                var existingAppt = await _localApptStore.GetAppointmentAsync(calendarEvent.ExternalID);

                if (existingAppt != null && existingAppt.CalendarId == appCalendar.LocalId)
                {
                    appt = existingAppt;
                }
            }

            if (appt == null)
            {
                appt = new Appointment();
            }

            appt.Subject = calendarEvent.Name;
            appt.Details = calendarEvent.Description ?? string.Empty;
            appt.StartTime = calendarEvent.Start;
            appt.Duration = calendarEvent.End - calendarEvent.Start;
            appt.AllDay = calendarEvent.AllDay;
            appt.Location = calendarEvent.Location ?? string.Empty;

            await appCalendar.SaveAppointmentAsync(appt);

            calendarEvent.ExternalID = appt.LocalId;
        }