This is what I do for both macOS and iOS, as a common external Method and Class:
- I build an SQLite database
- I populate the SQLite database with all Calendar Events within a given date range.
- I then query this database to get the results I need as a RowSet.
CalendarEventsDB is a SQLiteDatabase
myEventStoreMBS is a ClassEventStoreMBS
Build the SQLite file:
Public Sub doReset()
#If (TargetDesktop And TargetMacOS) Or TargetiOS Then
Var tempSQL As String
Var totalSQL() As String
If myEventStoreMBS = Nil Or Not myEventStoreMBS.isAccessGrantedCalendar Or CalendarEventsDB <> Nil Then 'if the database has already been set up, then exit!
Return 'access to Calendar not granted?
End If
Try
Var f As FolderItem = CommonFolders.SpecialFolderDatabases.Child("CalendarEventsDB.SQLite")
If f <> Nil And f.Exists Then
CommonFolders.doDeleteFolderWAD(f)
End If
'set up the new in memory database
CalendarEventsDB = New SQLiteDatabase
CalendarEventsDB.DatabaseFile = f 'CommonFolders.getDownloadFolderItemWAD("CalendarEventsDB.SQLite")
CalendarEventsDB.WriteAheadLogging = True
CalendarEventsDB.CreateDatabase
If Not CalendarEventsDB.Connect Then
CalendarEventsDB = Nil
Return
End If
totalSQL.Add("CREATE TABLE IF NOT EXISTS CalendarEvents (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,")
'Calendar
totalSQL.Add("CalendarIdentifier TEXT,")
totalSQL.Add("CalendarColor INTEGER,")
totalSQL.Add("isCalendarImmutable INTEGER,") 'Immutable
'totalSQL.Add("isCalendarSubscribed INTEGER,") 'Subscribed
totalSQL.Add("CalendarTitle TEXT,")
totalSQL.Add("CalendarType TEXT,")
'Calendar Event
totalSQL.Add("isAllDay INTEGER,")
'totalSQL.Add("CalendarItemIdentifier TEXT,")
'totalSQL.Add("CreationDateTime TIMESTAMP,")
totalSQL.Add("EndDateTime TIMESTAMP,")
totalSQL.Add("EventIdentifier TEXT,")
'totalSQL.Add("hasNotes INTEGER,")
totalSQL.Add("Location TEXT,")
totalSQL.Add("Notes TEXT,")
'totalSQL.Add("OccurrenceDateTime TIMESTAMP,")
totalSQL.Add("StartDateTime TIMESTAMP,")
totalSQL.Add("Title TEXT,")
totalSQL.Add("URL TEXT")
totalSQL.Add(")")
tempSQL = String.FromArray(totalSQL, " ")
CalendarEventsDB.ExecuteSQL(tempSQL)
'CalendarEventsDB.ExecuteSQL("VACUUM") 'clear out any previous space. Not needed since it deletes the file!
Catch Error
CommonWindow.doDisplayErrorWAD(Error.Message, CurrentMethodName, Error.ErrorNumber)
End Try
#EndIf
End Sub
Populate the SQLite database:
Protected Sub doPopulateCalendarEvents(StartDate As DateTime, EndDate As DateTime, DaysPlusMinus As Integer = 90)
#If (TargetDesktop And TargetMacOS) Or TargetiOS Then
If CalendarEventsDB = Nil Or myEventStoreMBS = Nil Or Not myEventStoreMBS.isAccessGrantedCalendar Then
Return 'DB not yet initialised
End If
If StartDate = Nil Then
StartDate = DateTime.Now
StartDate = StartDate.SubtractInterval(0, 0, DaysPlusMinus)
End If
If EndDate = Nil Then
EndDate = DateTime.Now
EndDate = EndDate.AddInterval(0, 0, DaysPlusMinus)
End If
Dim tempNSPredicateMBS As NSPredicateMBS = myEventStoreMBS.predicateForEvents(startDate, endDate)
Dim tempEKEventMBS() As EKEventMBS = myEventStoreMBS.eventsMatchingPredicate(tempNSPredicateMBS)
Try
CalendarEventsDB.ExecuteSQL("DELETE FROM CalendarEvents") 'wipe any existing records!
For Each e As EKEventMBS In tempEKEventMBS
If e.calendar.calendarIdentifier = "" Or e.eventIdentifier = "" Or e.title = "" Then
'Break 'shouldn't happen!
Var aBreak As Boolean
Else
Var rec As New DatabaseRow
rec.Column("CalendarIdentifier").StringValue = e.calendar.calendarIdentifier
rec.Column("CalendarColor").IntegerValue = CommonPictures.getColorToNumberWAD(e.calendar.Color.colorValue) 'e.calendar.Color.colorValue.ToString
rec.Column("isCalendarImmutable").IntegerValue = If(e.calendar.Immutable, 1, 0)
'rec.Column("isCalendarSubscribed").IntegerValue = If(e.calendar.Subscribed, 1, 0)
rec.Column("CalendarTitle").StringValue = e.calendar.title
rec.Column("CalendarType").StringValue = getCalendarType(e.calendar.type)
rec.Column("isAllDay").IntegerValue = If(e.AllDay, 1, 0)
'rec.Column("CalendarItemIdentifier").StringValue = e.calendarItemIdentifier
'rec.Column("CreationDateTime").StringValue = e.creationDateTime.SQLDateTime
rec.Column("EndDateTime").StringValue = e.endDateTime.SQLDateTime
rec.Column("EventIdentifier").StringValue = e.eventIdentifier
'rec.Column("hasNotes").IntegerValue = If(e.hasNotes, 1, 0)
rec.Column("Location").StringValue = e.location
rec.Column("Notes").StringValue = e.notes
'rec.Column("OccurrenceDateTime").StringValue = e.occurrenceDateTime.SQLDateTime
rec.Column("StartDateTime").StringValue = e.startDateTime.SQLDateTime
rec.Column("Title").StringValue = e.title
rec.Column("URL").StringValue = e.URL
CalendarEventsDB.AddRow("CalendarEvents", rec)
End If
Next
Catch Error
CommonWindow.doDisplayErrorWAD(Error.Message, CurrentMethodName, Error.ErrorNumber)
End Try
#EndIf
End Sub
Get the Calendar Events as a RowSet:
Protected Sub getCalendarEvents(ByRef rs As RowSet)
#If (TargetDesktop And TargetMacOS) Or TargetiOS Then
myEventStoreMBS = New ClassEventStoreMBS
myEventStoreMBS.requestAccessToEntityType(EKEventStoreMBS.kEntityTypeEvent)
If myEventStoreMBS.defaultCalendarForNewEvents = Nil Then 'cancel pressed?
CommonWindow.doMessageBox("You must give " + app.ApplicationCore + " access to Calendar Events to access the calendars")
Return
End If
Var MemoryDB As New SQLiteDatabase
Var tempSQL As String
If Not MemoryDB.Connect Then
Return
End If
tempSQL = "CREATE TABLE IF NOT EXISTS Data (id INTEGER PRIMARY KEY AUTOINCREMENT, "
tempSQL = tempSQL + "Title TEXT, "
tempSQL = tempSQL + "CalendarUID TEXT, "
tempSQL = tempSQL + "Type TEXT, "
tempSQL = tempSQL + "Description TEXT, "
tempSQL = tempSQL + "Colour TEXT, "
tempSQL = tempSQL + "isEditable INTEGER "
tempSQL = tempSQL + ") "
Try
MemoryDB.ExecuteSQL(tempSQL)
Catch Error
CommonWindow.doDisplayErrorWAD(Error.Message, CurrentMethodName, Error.ErrorNumber)
Return
End Try
Var tempEKCalendarMBS() As EKCalendarMBS = myEventStoreMBS.calendarsForEntityType(EKEventStoreMBS.kEntityTypeEvent)
For Each myCalendarMBS As EKCalendarMBS In tempEKCalendarMBS
Var rec As New DatabaseRow
rec.Column("Title").StringValue = myCalendarMBS.Title
rec.Column("CalendarUID").StringValue = myCalendarMBS.calendarIdentifier
'rec.Column("Type").StringValue = tempType
rec.Column("Type").StringValue = getCalendarType(myCalendarMBS.type)
rec.Column("Description").StringValue = ""
rec.Column("Colour").StringValue = myCalendarMBS.Color.colorValue.ToString
rec.Column("isEditable").IntegerValue = If(myCalendarMBS.allowsContentModifications, 1, 0)
Try
MemoryDB.AddRow("Data", rec)
Catch Error
CommonWindow.doDisplayErrorWAD(Error.Message, CurrentMethodName, Error.ErrorNumber)
Return
End Try
Next
'Only show new Calendars not already chosen by the user
Var CalendarUIDArray() As String = CommonHMS.getCalendarUIDArray
Try
tempSQL = "SELECT * FROM Data "
If CalendarUIDArray.LastIndex >= 0 Then 'exclude any CalendarUIDs that are already being used by this User
tempSQL = tempSQL + "WHERE NOT CalendarUID IN(""" + String.FromArray(CalendarUIDArray, """,""") + """)"
End If
rs = MemoryDB.SelectSQL(tempSQL)
Catch Error
CommonWindow.doDisplayErrorWAD(Error.Message, CurrentMethodName, Error.ErrorNumber)
Return
End Try
If MemoryDB <> Nil Then MemoryDB.Close
#EndIf
End Sub
Get the Calendar Type as text:
Private Function getCalendarType(TypeID As Integer) As String
#If (TargetDesktop And TargetMacOS) Or TargetiOS Then
Select Case TypeID
Case EKCalendarMBS.kTypeBirthday
Return "Birthday"
Case EKCalendarMBS.kTypeCalDAV
Return "CalDAV"
Case EKCalendarMBS.kTypeExchange
Return "Exchange"
Case EKCalendarMBS.kTypeLocal
Return "Local"
Case EKCalendarMBS.kTypeSubscription
Return "Subscription"
Else
Return "Unknown"
End Select
#EndIf
End Function