forked from xamarin/Essentials
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Calendar Read-Only API * Return exceptions that match test case System.NotImplementedException --> Xamarin.Essentials.NotImplementedInReferenceAssemblyException (#45)
- Loading branch information
Showing
8 changed files
with
454 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Android.Content; | ||
using Android.Database; | ||
using Android.Provider; | ||
using Java.Security; | ||
|
||
namespace Xamarin.Essentials | ||
{ | ||
public static partial class Calendar | ||
{ | ||
const string andCondition = "AND"; | ||
|
||
static async Task<IEnumerable<DeviceCalendar>> PlatformGetCalendarsAsync() | ||
{ | ||
await Permissions.RequireAsync(PermissionType.CalendarRead); | ||
|
||
var calendarsUri = CalendarContract.Calendars.ContentUri; | ||
var calendarsProjection = new List<string> | ||
{ | ||
CalendarContract.Calendars.InterfaceConsts.Id, | ||
CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName | ||
}; | ||
var queryConditions = $"{CalendarContract.Calendars.InterfaceConsts.Deleted} != 1"; | ||
|
||
using (var cur = Platform.AppContext.ApplicationContext.ContentResolver.Query(calendarsUri, calendarsProjection.ToArray(), queryConditions, null, null)) | ||
{ | ||
var calendars = new List<DeviceCalendar>(); | ||
while (cur.MoveToNext()) | ||
{ | ||
calendars.Add(new DeviceCalendar() | ||
{ | ||
Id = cur.GetString(calendarsProjection.IndexOf(CalendarContract.Calendars.InterfaceConsts.Id)), | ||
Name = cur.GetString(calendarsProjection.IndexOf(CalendarContract.Calendars.InterfaceConsts.CalendarDisplayName)), | ||
}); | ||
} | ||
return calendars; | ||
} | ||
} | ||
|
||
static async Task<IEnumerable<DeviceEvent>> PlatformGetEventsAsync(string calendarId = null, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null) | ||
{ | ||
await Permissions.RequireAsync(PermissionType.CalendarRead); | ||
|
||
var eventsUri = CalendarContract.Events.ContentUri; | ||
var eventsProjection = new List<string> | ||
{ | ||
CalendarContract.Events.InterfaceConsts.Id, | ||
CalendarContract.Events.InterfaceConsts.CalendarId, | ||
CalendarContract.Events.InterfaceConsts.Title, | ||
CalendarContract.Events.InterfaceConsts.AllDay, | ||
CalendarContract.Events.InterfaceConsts.Dtstart, | ||
CalendarContract.Events.InterfaceConsts.Dtend, | ||
CalendarContract.Events.InterfaceConsts.Deleted | ||
}; | ||
var calendarSpecificEvent = string.Empty; | ||
var sDate = startDate ?? DateTimeOffset.Now.Add(defaultStartTimeFromNow); | ||
var eDate = endDate ?? sDate.Add(defaultEndTimeFromStartTime); | ||
if (!string.IsNullOrEmpty(calendarId)) | ||
{ | ||
calendarSpecificEvent = $"{CalendarContract.Events.InterfaceConsts.CalendarId}={calendarId} {andCondition} "; | ||
} | ||
calendarSpecificEvent += $"{CalendarContract.Events.InterfaceConsts.Dtend} >= {sDate.AddMilliseconds(sDate.Offset.TotalMilliseconds).ToUnixTimeMilliseconds()} {andCondition} "; | ||
calendarSpecificEvent += $"{CalendarContract.Events.InterfaceConsts.Dtstart} <= {eDate.AddMilliseconds(sDate.Offset.TotalMilliseconds).ToUnixTimeMilliseconds()} {andCondition} "; | ||
calendarSpecificEvent += $"{CalendarContract.Events.InterfaceConsts.Deleted} != 1"; | ||
|
||
using (var cur = Platform.AppContext.ApplicationContext.ContentResolver.Query(eventsUri, eventsProjection.ToArray(), calendarSpecificEvent, null, $"{CalendarContract.Events.InterfaceConsts.Dtstart} ASC")) | ||
{ | ||
var events = new List<DeviceEvent>(); | ||
while (cur.MoveToNext()) | ||
{ | ||
events.Add(new DeviceEvent() | ||
{ | ||
Id = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Id)), | ||
CalendarId = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.CalendarId)), | ||
Title = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Title)), | ||
StartDate = DateTimeOffset.FromUnixTimeMilliseconds(cur.GetLong(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Dtstart))), | ||
EndDate = cur.GetInt(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.AllDay)) == 0 ? (DateTimeOffset?)DateTimeOffset.FromUnixTimeMilliseconds(cur.GetLong(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Dtend))) : null | ||
}); | ||
} | ||
return events; | ||
} | ||
} | ||
|
||
static async Task<DeviceEvent> PlatformGetEventByIdAsync(string eventId) | ||
{ | ||
await Permissions.RequireAsync(PermissionType.CalendarRead); | ||
|
||
var eventsUri = CalendarContract.Events.ContentUri; | ||
var eventsProjection = new List<string> | ||
{ | ||
CalendarContract.Events.InterfaceConsts.Id, | ||
CalendarContract.Events.InterfaceConsts.CalendarId, | ||
CalendarContract.Events.InterfaceConsts.Title, | ||
CalendarContract.Events.InterfaceConsts.Description, | ||
CalendarContract.Events.InterfaceConsts.EventLocation, | ||
CalendarContract.Events.InterfaceConsts.AllDay, | ||
CalendarContract.Events.InterfaceConsts.Dtstart, | ||
CalendarContract.Events.InterfaceConsts.Dtend | ||
}; | ||
|
||
// Android event ids are always integers | ||
if (!int.TryParse(eventId, out var resultId)) | ||
{ | ||
throw new ArgumentException($"[Android]: No Event found for event Id {eventId}"); | ||
} | ||
|
||
var calendarSpecificEvent = $"{CalendarContract.Events.InterfaceConsts.Id}={resultId}"; | ||
using (var cur = Platform.AppContext.ApplicationContext.ContentResolver.Query(eventsUri, eventsProjection.ToArray(), calendarSpecificEvent, null, null)) | ||
{ | ||
if (cur.Count > 0) | ||
{ | ||
cur.MoveToNext(); | ||
var eventResult = new DeviceEvent | ||
{ | ||
Id = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Id)), | ||
CalendarId = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.CalendarId)), | ||
Title = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Title)), | ||
Description = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Description)), | ||
Location = cur.GetString(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.EventLocation)), | ||
StartDate = DateTimeOffset.FromUnixTimeMilliseconds(cur.GetLong(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Dtstart))), | ||
EndDate = cur.GetInt(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.AllDay)) == 0 ? (DateTimeOffset?)DateTimeOffset.FromUnixTimeMilliseconds(cur.GetLong(eventsProjection.IndexOf(CalendarContract.Events.InterfaceConsts.Dtend))) : null, | ||
Attendees = GetAttendeesForEvent(eventId) | ||
}; | ||
return eventResult; | ||
} | ||
else | ||
{ | ||
throw new ArgumentException($"[Android]: No Event found for event Id {eventId}"); | ||
} | ||
} | ||
} | ||
|
||
static IEnumerable<DeviceEventAttendee> GetAttendeesForEvent(string eventId) | ||
{ | ||
var attendeesUri = CalendarContract.Attendees.ContentUri; | ||
var attendeesProjection = new List<string> | ||
{ | ||
CalendarContract.Attendees.InterfaceConsts.EventId, | ||
CalendarContract.Attendees.InterfaceConsts.AttendeeEmail, | ||
CalendarContract.Attendees.InterfaceConsts.AttendeeName | ||
}; | ||
var attendeeSpecificAttendees = $"{CalendarContract.Attendees.InterfaceConsts.EventId}={eventId}"; | ||
var cur = Platform.AppContext.ApplicationContext.ContentResolver.Query(attendeesUri, attendeesProjection.ToArray(), attendeeSpecificAttendees, null, null); | ||
var attendees = new List<DeviceEventAttendee>(); | ||
while (cur.MoveToNext()) | ||
{ | ||
attendees.Add(new DeviceEventAttendee() | ||
{ | ||
Name = cur.GetString(attendeesProjection.IndexOf(CalendarContract.Attendees.InterfaceConsts.AttendeeName)), | ||
Email = cur.GetString(attendeesProjection.IndexOf(CalendarContract.Attendees.InterfaceConsts.AttendeeEmail)), | ||
}); | ||
} | ||
cur.Dispose(); | ||
return attendees; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using EventKit; | ||
using Foundation; | ||
|
||
namespace Xamarin.Essentials | ||
{ | ||
public static partial class Calendar | ||
{ | ||
static async Task<IEnumerable<DeviceCalendar>> PlatformGetCalendarsAsync() | ||
{ | ||
await Permissions.RequireAsync(PermissionType.CalendarRead); | ||
|
||
EKCalendar[] calendars; | ||
try | ||
{ | ||
calendars = CalendarRequest.Instance.Calendars; | ||
} | ||
catch (NullReferenceException ex) | ||
{ | ||
throw new Exception($"iOS: Unexpected null reference exception {ex.Message}"); | ||
} | ||
var calendarList = (from calendar in calendars | ||
select new DeviceCalendar | ||
{ | ||
Id = calendar.CalendarIdentifier, | ||
Name = calendar.Title | ||
}).ToList(); | ||
|
||
return calendarList; | ||
} | ||
|
||
static async Task<IEnumerable<DeviceEvent>> PlatformGetEventsAsync(string calendarId = null, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null) | ||
{ | ||
await Permissions.RequireAsync(PermissionType.CalendarRead); | ||
|
||
var startDateToConvert = startDate ?? DateTimeOffset.Now.Add(defaultStartTimeFromNow); | ||
var endDateToConvert = endDate ?? startDateToConvert.Add(defaultEndTimeFromStartTime); // NOTE: 4 years is the maximum period that a iOS calendar events can search | ||
var sDate = startDateToConvert.ToNSDate(); | ||
var eDate = endDateToConvert.ToNSDate(); | ||
EKCalendar[] calendars; | ||
try | ||
{ | ||
calendars = !string.IsNullOrWhiteSpace(calendarId) | ||
? CalendarRequest.Instance.Calendars.Where(x => x.CalendarIdentifier == calendarId).ToArray() | ||
: null; | ||
} | ||
catch (NullReferenceException ex) | ||
{ | ||
throw new NullReferenceException($"iOS: Unexpected null reference exception {ex.Message}"); | ||
} | ||
|
||
var query = CalendarRequest.Instance.PredicateForEvents(sDate, eDate, calendars); | ||
var events = CalendarRequest.Instance.EventsMatching(query); | ||
|
||
var eventList = (from e in events | ||
select new DeviceEvent | ||
{ | ||
Id = e.CalendarItemIdentifier, | ||
CalendarId = e.Calendar.CalendarIdentifier, | ||
Title = e.Title, | ||
StartDate = e.StartDate.ToDateTimeOffset(), | ||
EndDate = !e.AllDay ? (DateTimeOffset?)e.EndDate.ToDateTimeOffset() : null | ||
}) | ||
.OrderBy(e => e.StartDate) | ||
.ToList(); | ||
|
||
return eventList; | ||
} | ||
|
||
static async Task<DeviceEvent> PlatformGetEventByIdAsync(string eventId) | ||
{ | ||
await Permissions.RequireAsync(PermissionType.CalendarRead); | ||
|
||
EKEvent e; | ||
try | ||
{ | ||
e = CalendarRequest.Instance.GetCalendarItem(eventId) as EKEvent; | ||
} | ||
catch (NullReferenceException) | ||
{ | ||
throw new NullReferenceException($"[iOS]: No Event found for event Id {eventId}"); | ||
} | ||
|
||
return new DeviceEvent | ||
{ | ||
Id = e.CalendarItemIdentifier, | ||
CalendarId = e.Calendar.CalendarIdentifier, | ||
Title = e.Title, | ||
Description = e.Notes, | ||
Location = e.Location, | ||
StartDate = e.StartDate.ToDateTimeOffset(), | ||
EndDate = !e.AllDay ? (DateTimeOffset?)e.EndDate.ToDateTimeOffset() : null, | ||
Attendees = e.Attendees != null ? GetAttendeesForEvent(e.Attendees) : new List<DeviceEventAttendee>() | ||
}; | ||
} | ||
|
||
static IEnumerable<DeviceEventAttendee> GetAttendeesForEvent(IEnumerable<EKParticipant> inviteList) | ||
{ | ||
var attendees = (from attendee in inviteList | ||
select new DeviceEventAttendee | ||
{ | ||
Name = attendee.Name, | ||
Email = attendee.Name | ||
}) | ||
.OrderBy(e => e.Name) | ||
.ToList(); | ||
|
||
return attendees; | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
Xamarin.Essentials/Calendar/Calendar.netstandard.tvos.watchos.tizen.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace Xamarin.Essentials | ||
{ | ||
public static partial class Calendar | ||
{ | ||
static Task<IEnumerable<DeviceCalendar>> PlatformGetCalendarsAsync() => throw ExceptionUtils.NotSupportedOrImplementedException; | ||
|
||
static Task<IEnumerable<DeviceEvent>> PlatformGetEventsAsync(string calendarId = null, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null) => throw ExceptionUtils.NotSupportedOrImplementedException; | ||
|
||
static Task<DeviceEvent> PlatformGetEventByIdAsync(string eventId) => throw ExceptionUtils.NotSupportedOrImplementedException; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace Xamarin.Essentials | ||
{ | ||
public static partial class Calendar | ||
{ | ||
static TimeSpan defaultStartTimeFromNow = TimeSpan.Zero; | ||
|
||
static TimeSpan defaultEndTimeFromStartTime = TimeSpan.FromDays(14); | ||
|
||
public static Task<IEnumerable<DeviceCalendar>> GetCalendarsAsync() => PlatformGetCalendarsAsync(); | ||
|
||
public static Task<IEnumerable<DeviceEvent>> GetEventsAsync(string calendarId = null, DateTimeOffset? startDate = null, DateTimeOffset? endDate = null) => PlatformGetEventsAsync(calendarId, startDate, endDate); | ||
|
||
public static Task<DeviceEvent> GetEventByIdAsync(string eventId) => PlatformGetEventByIdAsync(eventId); | ||
} | ||
} |
Oops, something went wrong.