Пример #1
0
        public static async Task <Calendar?> GetCalendarAsync()
        {
            if (!await RequestPermissionsAsync())
            {
                return(null);
            }

            IList <Calendar> calendars = await GetAllCalendarsAsync();

            Calendar?defaultCalendar = calendars.SingleOrDefault(c => c.ExternalID == SettingsRepository.Settings.DefaultCalendarId);

            if (defaultCalendar != null)
            {
                return(defaultCalendar);
            }

            if (calendars.Count == 1)
            {
                return(calendars.First());
            }

            string targetCalendarName = await Shell.Current.DisplayActionSheet(LN.ChooseCalendar, LN.Cancel, null, calendars.Select(c => c.Name).ToArray());

            if (targetCalendarName == null || targetCalendarName == LN.Cancel)
            {
                return(null);
            }
            Calendar selectedCalendar = calendars.First(c => c.Name == targetCalendarName);

            return(selectedCalendar);
        }
Пример #2
0
        /// <summary>
        /// Gets a single calendar by platform-specific ID.
        /// </summary>
        /// <param name="externalId">Platform-specific calendar identifier</param>
        /// <returns>The corresponding calendar, 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 <Calendar> GetCalendarByIdAsync(string externalId)
        {
            long calendarId = -1;

            if (!long.TryParse(externalId, out calendarId))
            {
                return(null);
            }

            return(Task.Run <Calendar>(() =>
            {
                Calendar calendar = null;
                var cursor = Query(
                    ContentUris.WithAppendedId(_calendarsUri, calendarId),
                    _calendarsProjection);

                try
                {
                    if (cursor.MoveToFirst())
                    {
                        calendar = GetCalendar(cursor);
                    }
                }
                catch (Java.Lang.Exception ex)
                {
                    throw new PlatformException(ex.Message, ex);
                }
                finally
                {
                    cursor.Close();
                }

                return calendar;
            }));
        }
Пример #3
0
        public static async Task <IList <Calendar> > GetAllCalendars()
        {
            if (!await RequestPermissions())
            {
                return(null);
            }

            // Getting Calendar list
            IList <Calendar> calendars = await CrossCalendars.Current.GetCalendarsAsync();

            calendars = calendars
                        .Where(c => c.Name.ToLower() == c.AccountName.ToLower() || c.AccountName.ToLower() == CustomCalendarName.ToLower())
                        .ToList();

            // Getting our custom calendar
            Calendar customCalendar = calendars.FirstOrDefault(c => c.AccountName.ToLower() == CustomCalendarName.ToLower());

            if (customCalendar == null)
            {
                customCalendar = new Calendar
                {
                    Name  = CustomCalendarName,
                    Color = "#56a5de"
                };
                await CrossCalendars.Current.AddOrUpdateCalendarAsync(customCalendar);

                calendars.Add(customCalendar);
            }
            else if (calendars.Count(c => c.AccountName == customCalendar.AccountName) > 1)
            {
                MessagingCenter.Send(Application.Current, MessageTypes.ExceptionOccurred, new IndexOutOfRangeException($"There are {calendars.Count(c => c.AccountName == customCalendar.AccountName)} calendars with AccountName {customCalendar.AccountName}"));
            }

            return(calendars);
        }
Пример #4
0
        public static async Task <bool> AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent)
        {
            if (!await RequestPermissionsAsync())
            {
                return(false);
            }

            Analytics.TrackEvent("Add to calendar");
Пример #5
0
        /// <summary>
        /// Gets all events for a calendar within the specified time range.
        /// </summary>
        /// <param name="calendar">Calendar containing events</param>
        /// <param name="start">Start of event range</param>
        /// <param name="end">End of event range</param>
        /// <returns>Calendar events</returns>
        /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Plugin.Calendars.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task <IList <CalendarEvent> > GetEventsAsync(Calendar calendar, DateTime start, DateTime end)
        {
            var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

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

            var eventsUriBuilder = CalendarContract.Instances.ContentUri.BuildUpon();

            // Note that this is slightly different from the GetEventById projection
            // due to the Instances API vs. Event API (specifically, IDs and start/end times)
            //
            string[] eventsProjection =
            {
                CalendarContract.Events.InterfaceConsts.Title,
                CalendarContract.Events.InterfaceConsts.Description,
                CalendarContract.Instances.Begin,
                CalendarContract.Instances.End,
                CalendarContract.Events.InterfaceConsts.AllDay,
                CalendarContract.Events.InterfaceConsts.EventLocation,
                CalendarContract.Instances.EventId
            };

            ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(start));
            ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(end));
            var eventsUri = eventsUriBuilder.Build();

            return(await Task.Run(() =>
            {
                var cursor = Query(eventsUri, eventsProjection,
                                   string.Format("{0} = {1}", CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID),
                                   null, CalendarContract.Events.InterfaceConsts.Dtstart + " ASC");

                var events = IterateCursor(cursor, () =>
                {
                    bool allDay = cursor.GetBoolean(CalendarContract.Events.InterfaceConsts.AllDay);

                    var calendarEvent = new CalendarEvent
                    {
                        Name = cursor.GetString(CalendarContract.Events.InterfaceConsts.Title),
                        ExternalID = cursor.GetString(CalendarContract.Instances.EventId),
                        Description = cursor.GetString(CalendarContract.Events.InterfaceConsts.Description),
                        Start = cursor.GetDateTime(CalendarContract.Instances.Begin, allDay),
                        End = cursor.GetDateTime(CalendarContract.Instances.End, allDay),
                        Location = cursor.GetString(CalendarContract.Events.InterfaceConsts.EventLocation),
                        AllDay = allDay
                    };
                    calendarEvent.Reminders = GetEventReminders(calendarEvent.ExternalID);

                    return calendarEvent;
                });

                return events;
            }).ConfigureAwait(false));
        }
        /// <summary>
        /// Creates a new calendar with the specified name and optional color.
        /// (just a convenience wrapper around AddOrUpdateCalendarAsync)
        /// </summary>
        /// <param name="api">ICalendars instance to extend</param>
        /// <param name="calendarName">Calendar name</param>
        /// <param name="color">Preferred color, or null to accept default</param>
        /// <returns>The created calendar</returns>
        public static async Task<Calendar> CreateCalendarAsync(this ICalendars api, string calendarName, string color = null)
        {
            var calendar = new Calendar
            {
                Name = calendarName,
                Color = color,
                CanEditCalendar = true,
                CanEditEvents = true
            };

            await api.AddOrUpdateCalendarAsync(calendar).ConfigureAwait(false);

            return calendar;
        }
Пример #7
0
        /// <summary>
        /// Removes a calendar and all its events from the system.
        /// </summary>
        /// <param name="calendar">Calendar to delete</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> DeleteCalendarAsync(Calendar calendar)
        {
            var existing = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

            if (existing == null)
            {
                return(false);
            }
            else if (!existing.CanEditCalendar)
            {
                throw new ArgumentException("Cannot delete calendar (probably because it's non-local)", "calendar");
            }

            return(await Task.Run(() => Delete(_calendarsUri, long.Parse(calendar.ExternalID))).ConfigureAwait(false));
        }
        /// <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="System.InvalidOperationException">Editing recurring events is not supported</exception>
        /// <exception cref="Plugin.Calendars.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>(() =>
                {
                    if (IsEventRecurring(calendarEvent.ExternalID))
                    {
                        throw new InvalidOperationException("Editing recurring events is not supported");
                    }

                    var calendarId = GetCalendarIdForEventId(calendarEvent.ExternalID);

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

            return(false);
        }
Пример #9
0
        public static async Task <IList <Calendar> > GetAllCalendarsAsync()
        {
            if (!await RequestPermissionsAsync())
            {
                return(new List <Calendar>());
            }

            // Getting Calendar list
            IList <Calendar> calendars = await CrossCalendars.Current.GetCalendarsAsync();

            calendars = calendars
                        .Where(c => string.Equals(c.Name, c.AccountName, StringComparison.OrdinalIgnoreCase) ||
                               string.Equals(c.AccountName, CustomCalendarName, StringComparison.OrdinalIgnoreCase))
                        .ToList();

            // Getting our custom calendar
            Calendar?customCalendar = calendars.FirstOrDefault(c => string.Equals(c.AccountName, CustomCalendarName, StringComparison.OrdinalIgnoreCase));

            if (customCalendar == null)
            {
                customCalendar = new Calendar
                {
                    Name  = CustomCalendarName,
                    Color = "#56a5de"
                };
                await CrossCalendars.Current.AddOrUpdateCalendarAsync(customCalendar);

                calendars.Add(customCalendar);
            }
            else if (calendars.Count(c => c.AccountName == customCalendar.AccountName) > 1)
            {
                ExceptionService.LogException(new IndexOutOfRangeException($"There are {calendars.Count(c => c.AccountName == customCalendar.AccountName)} calendars with AccountName {customCalendar.AccountName}"));
            }

            return(calendars);
        }
Пример #10
0
        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");
        }
Пример #11
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>
        /// 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;
        }
        /// <summary>
        /// Removes a calendar and all its events from the system.
        /// </summary>
        /// <param name="calendar">Calendar to delete</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> DeleteCalendarAsync(Calendar calendar)
        {
            if (string.IsNullOrEmpty(calendar.ExternalID))
            {
                return false;
            }

            await RequestCalendarAccess().ConfigureAwait(false);

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

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

            NSError error = null;
            if (!_eventStore.RemoveCalendar(deviceCalendar, 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();
                
                throw new ArgumentException(error.LocalizedDescription, "calendar", new NSErrorException(error));
            }

            return true;
        }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
   public Task<bool> DeleteCalendarAsync(Calendar calendar)
 {
     throw new NotSupportedException();
 }
Пример #15
0
        public async void Calendars_AddOrUpdateEvents_UpdatesEvents()
        {
            // TODO: Test description

            var originalEvents = new List<CalendarEvent> {
                new CalendarEvent { Name = "Bob", Description = "Bob's event", Start = DateTime.Today.AddDays(5), End = DateTime.Today.AddDays(5).AddHours(2), AllDay = false },
                new CalendarEvent { Name = "Steve", Description = "Steve's event", Start = DateTime.Today.AddDays(7), End = DateTime.Today.AddDays(8), AllDay = true },
                new CalendarEvent { Name = "Wheeee", Description = "Fun times", Start = DateTime.Today.AddDays(13), End = DateTime.Today.AddDays(15), AllDay = true }
            };
            var editedEvents = new List<CalendarEvent> {
                new CalendarEvent { Name = "Bob (edited)", Description = "Bob's edited event", Start = DateTime.Today.AddDays(5).AddHours(-2), End = DateTime.Today.AddDays(5).AddHours(1), AllDay = false },
                new CalendarEvent { Name = "Steve (edited)", Description = "Steve's edited event", Start = DateTime.Today.AddDays(6), End = DateTime.Today.AddDays(7).AddHours(-1), AllDay = false },
                new CalendarEvent { Name = "Yay (edited)", Description = "Edited fun times", Start = DateTime.Today.AddDays(12), End = DateTime.Today.AddDays(13), AllDay = true }
            };
            var calendar = new Calendar { Name = _calendarName };
            var queryStartDate = DateTime.Today;
            var queryEndDate = queryStartDate.AddDays(30);

            await _service.AddOrUpdateCalendarAsync(calendar);

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

            var eventResults = await _service.GetEventsAsync(calendar, queryStartDate, queryEndDate);

            Assert.That(eventResults, Is.EqualTo(originalEvents).Using<CalendarEvent>(_eventComparer));


            for (int i = 0; i < eventResults.Count; i++)
            {
                editedEvents.ElementAt(i).ExternalID = eventResults.ElementAt(i).ExternalID;
            }

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

            var editedEventResults = await _service.GetEventsAsync(calendar, queryStartDate, queryEndDate);

            Assert.That(editedEventResults, Is.EqualTo(editedEvents).Using<CalendarEvent>(_eventComparer));
        }
Пример #16
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");
        }
Пример #17
0
        static async Task<Calendar> GetOrCreateEvolveCalendarAsync()
        {
            
            var id = Settings.Current.EvolveCalendarId;
            if (!string.IsNullOrWhiteSpace(id))
            {
                try
                {
                    var calendar = await CrossCalendars.Current.GetCalendarByIdAsync(id);
                    if(calendar != null)
                        return calendar;
                }
                catch(Exception ex)
                {
                    Debug.WriteLine("Unable to get calendar.. odd as we created it already: " + ex);

                }

            }

            //if for some reason the calendar does not exist then simply create a enw one.
            if (Device.OS == TargetPlatform.Android)
            {
                //On android it is really hard to delete a calendar made by an app, so just add to default calendar.
                try
                {
                    var calendars = await CrossCalendars.Current.GetCalendarsAsync();
                    foreach (var calendar in calendars)
                    {
                        //find first calendar we can add stuff to
                        if (!calendar.CanEditEvents)
                            continue;

                        Settings.Current.EvolveCalendarId = calendar.ExternalID;
                        return calendar;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Unable to get calendars.. " + ex);
                }
            }
            else
            {
                //try to find evolve app if already uninstalled for some reason
                try
                {
                    var calendars = await CrossCalendars.Current.GetCalendarsAsync();
                    foreach(var calendar in calendars)
                    {
                        //find first calendar we can add stuff to
                        if(calendar.CanEditEvents && calendar.Name == "Xamarin Evolve")
                        {
                            Settings.Current.EvolveCalendarId = calendar.ExternalID;
                            return calendar;
                        }
                    }
                }
                catch(Exception ex)
                {
                    Debug.WriteLine("Unable to get calendars.. " + ex);
                }
            }

            var evolveCalendar = new Calendar();
            evolveCalendar.Color = "#7635EB";
            evolveCalendar.Name = "Xamarin Evolve";

            try
            {
                await CrossCalendars.Current.AddOrUpdateCalendarAsync(evolveCalendar);
                Settings.Current.EvolveCalendarId = evolveCalendar.ExternalID;
                return evolveCalendar;
            }
            catch(Exception ex)
            {
                Debug.WriteLine("Unable to create calendar.. " + ex);
            }

            return null;
        }
Пример #18
0
        public async void Calendars_GetEvents_NonexistentCalendarThrows()
        {
            var calendar = new Calendar { Name = "Bob", ExternalID = "42" };

            Assert.IsTrue(await _service.GetEventsAsync(calendar, DateTime.Today, DateTime.Today.AddDays(30)).ThrowsAsync<ArgumentException>(), "Exception wasn't thrown");
        }
        /// <summary>
        /// Add new event to a calendar or update an existing event.
        /// If a new event was added, the ExternalID property will be set on the CalendarEvent object,
        /// to support future queries/updates.
        /// </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="System.InvalidOperationException">Editing recurring events is not supported</exception>
        /// <exception cref="Plugin.Calendars.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;
            CalendarEvent existingEvent  = null;

            await Task.Run(() =>
            {
                if (long.TryParse(calendarEvent.ExternalID, out existingId))
                {
                    if (IsEventRecurring(calendarEvent.ExternalID))
                    {
                        throw new InvalidOperationException("Editing recurring events is not supported");
                    }

                    var calendarId = GetCalendarIdForEventId(calendarEvent.ExternalID);

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

                var eventValues = new ContentValues();
                bool allDay     = calendarEvent.AllDay;
                var start       = allDay
                        ? DateTime.SpecifyKind(calendarEvent.Start.Date, DateTimeKind.Utc)
                        : calendarEvent.Start;
                var end = allDay
                        ? DateTime.SpecifyKind(calendarEvent.End.Date, DateTimeKind.Utc)
                        : calendarEvent.End;

                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(start));
                eventValues.Put(CalendarContract.Events.InterfaceConsts.Dtend,
                                DateConversions.GetDateAsAndroidMS(end));
                eventValues.Put(CalendarContract.Events.InterfaceConsts.AllDay,
                                allDay);
                eventValues.Put(CalendarContract.Events.InterfaceConsts.EventLocation,
                                calendarEvent.Location ?? string.Empty);

                // If we're updating an existing event, don't mess with the existing
                // time zone (since we don't support explicitly setting it yet).
                // *Unless* we're toggling the "all day" setting
                // (because that would mean the time zone is UTC rather than local...).
                //
                if (!updateExisting || allDay != existingEvent?.AllDay)
                {
                    eventValues.Put(CalendarContract.Events.InterfaceConsts.EventTimezone,
                                    allDay
                            ? Java.Util.TimeZone.GetTimeZone("UTC")?.ID ?? string.Empty
                            : Java.Util.TimeZone.Default.ID);
                }

                if (!updateExisting)
                {
                    calendarEvent.ExternalID = Insert(_eventsUri, eventValues);
                }
                else
                {
                    Update(_eventsUri, existingId, eventValues);
                }
            }).ConfigureAwait(false);
        }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task<IList<CalendarEvent>> GetEventsAsync(Calendar calendar, DateTime start, DateTime end)
 {
     throw new NotSupportedException();
 }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task AddOrUpdateCalendarAsync(Calendar calendar)
 {
     throw new NotSupportedException();
 }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task AddOrUpdateEventAsync(Calendar calendar, CalendarEvent calendarEvent)
 {
     throw new NotSupportedException();
 }
Пример #23
0
        public async void Calendars_AddOrUpdateEvents_AddsEvents()
        {
            var events = new List<CalendarEvent> {
                new CalendarEvent { Name = "Bob", Description = "Bob's event", Start = DateTime.Today.AddDays(5), End = DateTime.Today.AddDays(5).AddHours(2), AllDay = false },
                new CalendarEvent { Name = "Steve", Description = "Steve's event", Start = DateTime.Today.AddDays(7), End = DateTime.Today.AddDays(8), AllDay = true },
                new CalendarEvent { Name = "Wheeee", Description = "Fun times", Start = DateTime.Today.AddDays(13), End = DateTime.Today.AddDays(15), AllDay = true }
            };
            var calendar = new Calendar { Name = _calendarName };

            await _service.AddOrUpdateCalendarAsync(calendar);

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

            var eventResults = await _service.GetEventsAsync(calendar, DateTime.Today, DateTime.Today.AddDays(30));

            Assert.That(eventResults, Is.EqualTo(events).Using<CalendarEvent>(_eventComparer));

            // Extra check that DateTime.Kinds are local
            Assert.AreEqual(DateTimeKind.Local, eventResults.Select(e => e.Start.Kind).Distinct().Single());
            Assert.AreEqual(DateTimeKind.Local, eventResults.Select(e => e.End.Kind).Distinct().Single());
        }
Пример #24
0
        /// <summary>
        /// Creates a new calendar or updates the name and color of an existing one.
        /// </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="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task AddOrUpdateCalendarAsync(Calendar calendar)
        {
            bool updateExisting = false;
            long existingId     = -1;

            if (long.TryParse(calendar.ExternalID, out existingId))
            {
                var existingCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

                if (existingCalendar != null)
                {
                    if (!existingCalendar.CanEditCalendar)
                    {
                        throw new ArgumentException("Destination calendar is not writeable");
                    }

                    updateExisting = true;
                }
                else
                {
                    throw new ArgumentException("Specified calendar does not exist on device", "calendar");
                }
            }

            var values = new ContentValues();

            values.Put(CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName, calendar.Name);
            values.Put(CalendarContract.Calendars.Name, calendar.Name);

            // Unlike iOS/WinPhone, Android does not automatically assign a color for us,
            // so we use our own default of blue.
            //
            int colorInt = unchecked ((int)0xFF0000FF);

            if (!string.IsNullOrEmpty(calendar.Color))
            {
                int.TryParse(calendar.Color.Trim('#'), NumberStyles.HexNumber,
                             CultureInfo.InvariantCulture, out colorInt);
            }

            values.Put(CalendarContract.Calendars.InterfaceConsts.CalendarColor, colorInt);

            if (!updateExisting)
            {
                values.Put(CalendarContract.Calendars.InterfaceConsts.CalendarAccessLevel, (int)CalendarAccess.AccessOwner);
                values.Put(CalendarContract.Calendars.InterfaceConsts.AccountName, AccountName);
                values.Put(CalendarContract.Calendars.InterfaceConsts.OwnerAccount, OwnerAccount);
                values.Put(CalendarContract.Calendars.InterfaceConsts.Visible, true);
                values.Put(CalendarContract.Calendars.InterfaceConsts.SyncEvents, true);

                values.Put(CalendarContract.Calendars.InterfaceConsts.AccountType, CalendarContract.AccountTypeLocal);
            }

            await Task.Run(() =>
            {
                if (updateExisting)
                {
                    Update(_calendarsUri, existingId, values);
                }
                else
                {
                    var uri = _calendarsUri.BuildUpon()
                              .AppendQueryParameter(CalendarContract.CallerIsSyncadapter, "true")
                              .AppendQueryParameter(CalendarContract.Calendars.InterfaceConsts.AccountName, AccountName)
                              .AppendQueryParameter(CalendarContract.Calendars.InterfaceConsts.AccountType, CalendarContract.AccountTypeLocal)
                              .Build();

                    calendar.ExternalID = Insert(uri, values);

                    calendar.CanEditCalendar = true;
                    calendar.CanEditEvents   = true;
                    calendar.Color           = "#" + colorInt.ToString("x8");
                }
            }).ConfigureAwait(false);
        }
Пример #25
0
        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");
        }
        /// <summary>
        /// Gets all events for a calendar within the specified time range.
        /// </summary>
        /// <param name="calendar">Calendar containing events</param>
        /// <param name="start">Start of event range</param>
        /// <param name="end">End of event range</param>
        /// <returns>Calendar events</returns>
        /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<IList<CalendarEvent>> GetEventsAsync(Calendar calendar, DateTime start, DateTime end)
        {
            await EnsureInitializedAsync().ConfigureAwait(false);

            AppointmentCalendar deviceCalendar = null;

            try
            {
                deviceCalendar = await _apptStore.GetAppointmentCalendarAsync(calendar.ExternalID).ConfigureAwait(false);
            }
            catch (ArgumentException ex)
            {
                throw new ArgumentException("Specified calendar not found on device", ex);
            }

            // Not all properties are populated by default
            //
            var options = new FindAppointmentsOptions { IncludeHidden = false };
            options.FetchProperties.Add(AppointmentProperties.Subject);
            options.FetchProperties.Add(AppointmentProperties.Details);
            options.FetchProperties.Add(AppointmentProperties.StartTime);
            options.FetchProperties.Add(AppointmentProperties.Duration);
            options.FetchProperties.Add(AppointmentProperties.AllDay);
            options.FetchProperties.Add(AppointmentProperties.Location);

            var appointments = await deviceCalendar.FindAppointmentsAsync(start, end - start, options).ConfigureAwait(false);
            var events = appointments.Select(a => a.ToCalendarEvent()).ToList();

            return events;
        }
Пример #27
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>
        /// Creates a new calendar or updates the name and color of an existing one.
        /// </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="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public 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", "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);
                }

                NSError error = null;
                if (!_eventStore.SaveCalendar(deviceCalendar, true, out 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));
                    }
                }
            }
        }
Пример #29
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()));
        }
 /// <summary>
 /// Not supported for Windows Store apps
 /// </summary>
 public Task<bool> DeleteEventAsync(Calendar calendar, CalendarEvent cev)
 {
     throw new NotSupportedException();
 }
        /// <summary>
        /// Gets all events for a calendar within the specified time range.
        /// </summary>
        /// <param name="calendar">Calendar containing events</param>
        /// <param name="start">Start of event range</param>
        /// <param name="end">End of event range</param>
        /// <returns>Calendar events</returns>
        /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<IList<CalendarEvent>> GetEventsAsync(Calendar calendar, DateTime start, DateTime end)
        {
            var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

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

            var eventsUriBuilder = CalendarContract.Instances.ContentUri.BuildUpon();

            // Note that this is slightly different from the GetEventById projection
            // due to the Instances API vs. Event 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.AllDay,
                CalendarContract.Events.InterfaceConsts.EventLocation,
                CalendarContract.Instances.EventId
            };

            ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(start));
            ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(end));
            var eventsUri = eventsUriBuilder.Build();
            var events = new List<CalendarEvent>();

            await Task.Run(() => 
            {
                var cursor = Query(eventsUri, eventsProjection,
                   string.Format("{0} = {1}", CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID),
                   null, CalendarContract.Events.InterfaceConsts.Dtstart + " ASC");

                try
                {
                    if (cursor.MoveToFirst())
                    {
                        do
                        {
                            events.Add(new CalendarEvent
                                {
                                    Name = cursor.GetString(CalendarContract.Events.InterfaceConsts.Title),
                                    ExternalID = cursor.GetString(CalendarContract.Instances.EventId),
                                    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)
                                });
                        } while (cursor.MoveToNext());
                    }
                }
                catch (Java.Lang.Exception ex)
                {
                    throw new PlatformException(ex.Message, ex);
                }
                finally
                {
                    cursor.Close();
                }
            });
            
            return events;
        }
        /// <summary>
        /// Creates a new calendar or updates the name and color of an existing one.
        /// </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="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task AddOrUpdateCalendarAsync(Calendar calendar)
        {
            bool updateExisting = false;
            long existingId = -1;

            if (long.TryParse(calendar.ExternalID, out existingId))
            {
                var existingCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

                if (existingCalendar != null)
                {
                    if (!existingCalendar.CanEditCalendar)
                    {
                        throw new ArgumentException("Destination calendar is not writeable");
                    }

                    updateExisting = true;
                }
                else
                {
                    throw new ArgumentException("Specified calendar does not exist on device", "calendar");
                }
            }

            var values = new ContentValues();
            values.Put(CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName, calendar.Name);
            values.Put(CalendarContract.Calendars.Name, calendar.Name);

            // Unlike iOS/WinPhone, Android does not automatically assign a color for us,
            // so we use our own default of blue.
            //
            int colorInt = unchecked((int)0xFF0000FF);

            if (!string.IsNullOrEmpty(calendar.Color))
            {
                int.TryParse(calendar.Color.Trim('#'), NumberStyles.HexNumber,
                    CultureInfo.InvariantCulture, out colorInt);
            }

            values.Put(CalendarContract.Calendars.InterfaceConsts.CalendarColor, colorInt);

            if (!updateExisting)
            {
                values.Put(CalendarContract.Calendars.InterfaceConsts.CalendarAccessLevel, (int)CalendarAccess.AccessOwner);
                values.Put(CalendarContract.Calendars.InterfaceConsts.AccountName, AccountName);
                values.Put(CalendarContract.Calendars.InterfaceConsts.OwnerAccount, OwnerAccount);
                values.Put(CalendarContract.Calendars.InterfaceConsts.Visible, true);
                values.Put(CalendarContract.Calendars.InterfaceConsts.SyncEvents, true);

                values.Put(CalendarContract.Calendars.InterfaceConsts.AccountType, CalendarContract.AccountTypeLocal);
            }

            await Task.Run(() =>
                {
                    if (updateExisting)
                    {
                        Update(_calendarsUri, existingId, values);
                    }
                    else
                    {
                        var uri = _calendarsUri.BuildUpon()
                            .AppendQueryParameter(CalendarContract.CallerIsSyncadapter, "true")
                            .AppendQueryParameter(CalendarContract.Calendars.InterfaceConsts.AccountName, AccountName)
                            .AppendQueryParameter(CalendarContract.Calendars.InterfaceConsts.AccountType, CalendarContract.AccountTypeLocal)
                            .Build();

                        calendar.ExternalID = Insert(uri, values);

                        calendar.CanEditCalendar = true;
                        calendar.CanEditEvents = true;
                        calendar.Color = "#" + colorInt.ToString("x8");
                    }
                }).ConfigureAwait(false);
        }
Пример #33
0
        /// <summary>
        /// Gets all events for a calendar within the specified time range.
        /// </summary>
        /// <param name="calendar">Calendar containing events</param>
        /// <param name="start">Start of event range</param>
        /// <param name="end">End of event range</param>
        /// <returns>Calendar events</returns>
        /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task <IList <CalendarEvent> > GetEventsAsync(Calendar calendar, DateTime start, DateTime end)
        {
            var deviceCalendar = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

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

            var eventsUriBuilder = CalendarContract.Instances.ContentUri.BuildUpon();

            // Note that this is slightly different from the GetEventById projection
            // due to the Instances API vs. Event 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.AllDay,
                CalendarContract.Events.InterfaceConsts.EventLocation,
                CalendarContract.Instances.EventId
            };

            ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(start));
            ContentUris.AppendId(eventsUriBuilder, DateConversions.GetDateAsAndroidMS(end));
            var eventsUri = eventsUriBuilder.Build();
            var events    = new List <CalendarEvent>();

            await Task.Run(() =>
            {
                var cursor = Query(eventsUri, eventsProjection,
                                   string.Format("{0} = {1}", CalendarContract.Events.InterfaceConsts.CalendarId, calendar.ExternalID),
                                   null, CalendarContract.Events.InterfaceConsts.Dtstart + " ASC");

                try
                {
                    if (cursor.MoveToFirst())
                    {
                        do
                        {
                            events.Add(new CalendarEvent
                            {
                                Name        = cursor.GetString(CalendarContract.Events.InterfaceConsts.Title),
                                ExternalID  = cursor.GetString(CalendarContract.Instances.EventId),
                                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)
                            });
                        } while (cursor.MoveToNext());
                    }
                }
                catch (Java.Lang.Exception ex)
                {
                    throw new PlatformException(ex.Message, ex);
                }
                finally
                {
                    cursor.Close();
                }
            });

            return(events);
        }
        /// <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);
                    }
                });
        }
Пример #35
0
        /// <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>
        /// Removes a calendar and all its events from the system.
        /// </summary>
        /// <param name="calendar">Calendar to delete</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> DeleteCalendarAsync(Calendar calendar)
        {
            var existing = await GetCalendarByIdAsync(calendar.ExternalID).ConfigureAwait(false);

            if (existing == null)
            {
                return false;
            }
            else if (!existing.CanEditCalendar)
            {
                throw new ArgumentException("Cannot delete calendar (probably because it's non-local)", "calendar");
            }

            return await Task.Run(() => Delete(_calendarsUri, long.Parse(calendar.ExternalID))).ConfigureAwait(false);
        }
        /// <summary>
        /// Gets all events for a calendar within the specified time range.
        /// </summary>
        /// <param name="calendar">Calendar containing events</param>
        /// <param name="start">Start of event range</param>
        /// <param name="end">End of event range</param>
        /// <returns>Calendar events</returns>
        /// <exception cref="System.ArgumentException">Calendar does not exist on device</exception>
        /// <exception cref="System.UnauthorizedAccessException">Calendar access denied</exception>
        /// <exception cref="Calendars.Plugin.Abstractions.PlatformException">Unexpected platform-specific error</exception>
        public async Task<IList<CalendarEvent>> GetEventsAsync(Calendar calendar, DateTime start, DateTime end)
        {
            await RequestCalendarAccess().ConfigureAwait(false);

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

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

            var query = _eventStore.PredicateForEvents(start.ToNSDate(), end.ToNSDate(), new EKCalendar[] { deviceCalendar });
            var events = await Task.Run(() =>
            {
                var iosEvents = _eventStore.EventsMatching(query);
                return iosEvents == null ? new List<CalendarEvent>() : iosEvents.Select(e => e.ToCalendarEvent()).ToList();
            }).ConfigureAwait(false);

            return events;
        }
        /// <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;
        }
        /// <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;
        }
Пример #40
0
        public async Task Calendars_AddOrUpdateEvents_UpdatesEvents()
        {
            var originalEvents = new List<CalendarEvent> {
                new CalendarEvent { Name = "Bob", Description = "Bob's event", Start = DateTime.Today.AddDays(5), End = DateTime.Today.AddDays(5).AddHours(2), AllDay = false },
                new CalendarEvent { Name = "Steve", Description = "Steve's event", Start = DateTime.Today.AddDays(7), End = DateTime.Today.AddDays(8), AllDay = true },
                new CalendarEvent { Name = "Wheeee", Description = "Fun times", Start = DateTime.Today.AddDays(13), End = DateTime.Today.AddDays(15), AllDay = true }
            };
            var editedEvents = new List<CalendarEvent> {
                new CalendarEvent { Name = "Bob (edited)", Description = "Bob's edited event", Start = DateTime.Today.AddDays(5).AddHours(-2), End = DateTime.Today.AddDays(5).AddHours(1), AllDay = false },
                new CalendarEvent { Name = "Steve (edited)", Description = "Steve's edited event", Start = DateTime.Today.AddDays(6), End = DateTime.Today.AddDays(7).AddHours(-1), AllDay = false },
                new CalendarEvent { Name = "Yay (edited)", Description = "Edited fun times", Start = DateTime.Today.AddDays(12), End = DateTime.Today.AddDays(13), AllDay = true }
            };
            var calendar = new Calendar { Name = _calendarName };
            var queryStartDate = DateTime.Today;
            var queryEndDate = queryStartDate.AddDays(30);

            await _service.AddOrUpdateCalendarAsync(calendar);

            foreach (var cev in originalEvents)
            {
                await _service.AddOrUpdateEventAsync(calendar, cev);
            }

            var eventResults = await _service.GetEventsAsync(calendar, queryStartDate, queryEndDate);
            Assert.IsNotNull(eventResults);

            CollectionAssert.AreEqual((ICollection)originalEvents, (ICollection)eventResults, _eventComparer);

            for (int i = 0; i < eventResults.Count; i++)
            {
                editedEvents.ElementAt(i).ExternalID = eventResults.ElementAt(i).ExternalID;
            }

            foreach (var cev in editedEvents)
            {
                await _service.AddOrUpdateEventAsync(calendar, cev);
            }

            var editedEventResults = await _service.GetEventsAsync(calendar, queryStartDate, queryEndDate);
            Assert.IsNotNull(editedEventResults);

            CollectionAssert.AreEqual((ICollection)editedEvents, (ICollection)editedEventResults, _eventComparer);
        }
        /// <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>
        /// Removes a calendar and all its events from the system.
        /// </summary>
        /// <param name="calendar">Calendar to delete</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> DeleteCalendarAsync(Calendar calendar)
        {
            if (string.IsNullOrEmpty(calendar.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)
            {
                // Perform the delete and return true
                await appCalendar.DeleteAsync().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 read-only calendar", "calendar");
                }
            }

            return deleted;
        }