Android Tutorial [B4A] [Class] [Calendar] Class wmCalendar - Android calendar manipulation based on DonManfred's explorations

This is a calendar manipulation class based on @DonManfred 's explorations which you can find at https://www.b4x.com/android/forum/t...ntresolver-query-insert-update-delete.100229/.

It contains the following methods:

- AddCalendar: Adds a new Calendar and returns its id, or -1 if no Calendar was added
- GetAllVisibleCalendars: Returns a list of type CalendarInfo containing all visible Calendars
- GetCalendarByID: Returns a variable of type CalendarInfo containing the selected Calendar's data, or Null if the ID doesn't exist
- GetCalendarByName: Returns a list of type CalendarInfo containing all Calendars with the specified name

- AddEvent: Adds a new Event to a Calendar and returns the new Event's id, or -1 if no Event was added
- GetAllVisibleEventsForCalendar: Returns a list of type EventInfo containing all visible Events for the specified Calendar id
- GetAllVisibleEventsInstancesForCalendar: Returns a list of type EventInfo containing all visible Events' Instances for the specified Calendar id
- GetSelectedEventsForCalendar: ' Returns a list of type EventInfo containing selected Events for the specified Calendar id
- GetSelectedEventsInstancesForCalendar: ' Returns a list of type EventInfo containing selected Events' Instances for the specified Calendar id
- GetEventByID: Returns a variable of type EventInfo containing the selected Event's data, or Null if the ID doesn't exist
- UpdateEvent: Attempts to update an Event and returns the number of Events that were updated
- DeleteEvent: Attempts to delete an Event and returns the number of Events that were deleted

- AddAttendeeToEvent: Adds an Attendee to an Event and returns the id of the added Attendee, or -1 if no Attendee was added
- GetEventAttendees: Returns a list of type AttendeeInfo containing all Attendees for the selected Event id

- AddReminderToEvent: Adds a Reminder to an Event and returns the id of the added Reminder, or -1 if no Reminder was added
- GetEventReminders: Returns a list of type ReminderInfo containing all Reminders for the selected Event id

Important:
- CalendarInfo, EventInfo, AttendeeInfo, and ReminderInfo are Types that are defined in the class
- Events vs. Instances: Instances are individual instances of recurring Events
- The Manifest has been edited as well, and RuntimePermissions must be requested - see @DonManfred 's post
- General Google information about the Calendar provider that can be useful when 'strange' things seem to happen (the Calendar is a complex beast): https://developer.android.com/guide/topics/providers/calendar-provider

Non-core library dependencies:
- GoogleCalendarClient: get V0.2 from @DonManfred's post
- ContentResolver
- RuntimePermissions
- SQL

An example project is attached, feel free to modify as desired; if you'd add/improve functionality, please post it here as well.

Enjoy!

EDIT 2022-04-19: adding an all-day event caused it to wind up for 'yesterday' instead of 'today'. The attached project was updated with the correct way to handle this, and comments were added.
 

Attachments

  • wmCalendarDemo.zip
    21.9 KB · Views: 605
Last edited:

RiverRaid

Active Member
Licensed User
Longtime User
Thank you for this!!

It workes really great but one thing: Did you AddCalender doesn't work, i don't know why. I tried your code.

It says that the Calendar has been added, but it's not.

Do you have maybe an idea?
Thank you
 

RiverRaid

Active Member
Licensed User
Longtime User
@walt61

Sure :) Sorry for the late answer



B4X:
Sub Process_Globals
    Private xui As XUI
    Private wmCalendar1 As wmCalendar
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Wait For(CreateCal) complete (Result3 As Boolean)
    If Result3 = False Then Return       
End Sub

Private Sub CreateCal As ResumableSub
        
    Private InputTemplate As B4XInputTemplate
    InputTemplate.Initialize
    InputTemplate.Text = "Dienste"
    InputTemplate.lblTitle.Text  ="New Calendar:"
    Private Dialog2 As B4XDialog
    Dialog2.Initialize(Activity)
    Dialog2.Title = "Name of Calendar:"
    Dialog2.BorderWidth = 0
    Dialog2.BlurBackground = True
    
    Wait For (Dialog2.ShowTemplate(InputTemplate, "Save", "", "cancel")) Complete (Result As Int)
    If Result = xui.DialogResponse_Positive Then

        Dim newName As String = InputTemplate.Text
        Dim cconValues As List
        cconValues.Initialize
        cconValues.Add(wmCalendar1.ccon.NAME)
        cconValues.Add(wmCalendar1.ccon.CALENDAR_DISPLAY_NAME)
        cconValues.Add(wmCalendar1.ccon.VISIBLE)

        Dim theCalendar As CalendarInfo
        theCalendar.Initialize
        theCalendar.name = newName
        theCalendar.displayName = newName
        theCalendar.visible = True

        
        Dim newCalendarID As Int = wmCalendar1.AddCalendar(theCalendar, cconValues)
        If newCalendarID < 0 Then
            MsgboxAsync("Error, the calender '" & newName & "' could't be created", Application.LabelName)
            Return False
        Else
            Starter.CalID = newCalendarID
            Starter.SettingsStore.Put("CalID",Starter.CalID)
            ToastMessageShow("Calendar '" & newName & "' created", True)
            Return True
        End If
    
    End If
    Return False
End Sub

It has no errors whatsoever, but the calender is not created
 

RiverRaid

Active Member
Licensed User
Longtime User
Thanks for the answer

Sorry, of course both is done correctly. I only posted the part of the new calendar.

Reading existing calendars, adding events and reminder worked like a charm. Only the adding of a new calendar won't work.
 

walt61

Active Member
Licensed User
Longtime User
Okies; the issue appears to be with the 'visible' value. All items in type CalendarInfo are String. According to https://developer.android.com/guide/topics/providers/calendar-provider, 'visible' should be 0 (not visible) or 1 (visible). As the item is a String, setting it to 'True' makes it "true" which then appears to be interpreted as 0 by the provider.

Changing
B4X:
theCalendar.visible = True
To
B4X:
theCalendar.visible = 1

does the trick: method 'GetAllVisibleCalendars' then returns the new calendar too :)
 

RiverRaid

Active Member
Licensed User
Longtime User
Wow, thank you very much!!!!
I'm at home again on Thursday evening and test it then. Thank you!
 

berndm2

Member
Licensed User
Longtime User
I tested wmcalendar and found that all specified entries but no later recurring entries are selected.
Is there a possibility to also select this?
Thank you for your answer.
 

berndm2

Member
Licensed User
Longtime User
I use the following call to get all current entries:
allEvents = wmCalendar1.GetSelectedEventsInstancesForCalendar("1",eventSelectionFields, eventSelectionOperators, eventSelectionArgs, DateTime.Add(DateTime.Now, 0, 0, -1), DateTime.Add(DateTime.Now, 0, 0, 1), wmCalendar1.econ.TITLE, True)
 

berndm2

Member
Licensed User
Longtime User
Hi walt61,
That's exactly what I want. However, I only get all single appointments in the selected period. The repeatable appointments that I had previously set, but which would be due again in the period, are concealed (but displayed in the ACALENDAR). Only newly set repeatable appointments are output by: GetSelectedEventsInstancesForCalendar. My suggestion is to announce due appointments repeatedly acoustically (e.g. every 10 minutes) if I am not carrying my smartphone with me. I hope my concern has become clear. Thank you for your help
 

walt61

Active Member
Licensed User
Longtime User
Aha ok, I just wanted to make sure you didn't intend to get '1 month/year earlier/later'.

I think I've found the issue and have been able to reproduce it. DateTime.Now includes the current time, not just the date. Therefore, depending on the instances' time, the DateTime.Add values may narrow the selection down too much. Something like this seems to work (you may need to tweak the range values for DateTime.Add a bit but I'm sure you'll see what I mean):

B4X:
    Dim allEvents As List
    Dim dateFrom As String = DateTime.Date(DateTime.Add(DateTime.Now, 0, 0, -2))
    Dim dateTo As String = DateTime.Date(DateTime.Add(DateTime.Now, 0, 0, 2))
    Dim eventSelectionFields() As String
    Dim eventSelectionOperators() As String
    Dim eventSelectionArgs() As String
    allEvents = wmCalendar1.GetSelectedEventsInstancesForCalendar(LabelSelectedCalendarID.Text, _
                                                                eventSelectionFields, eventSelectionOperators, eventSelectionArgs, _
                                                                DateTime.DateParse(dateFrom), DateTime.DateParse(dateTo), _
                                                                wmCalendar1.econ.TITLE, True)

If you request all instances and then examine the detailed information for some of them, you should be able to determine the correct values to use. Hope this helps!
 

berndm2

Member
Licensed User
Longtime User
The problem is solved if I only evaluate the times, i.e. the hours and minutes of the calendar entries, because repeated entries are shown with the date of the first entry and not with the date of the current repetition. To do this, I have to limit the selection to the current day.
Thank you for your help
Bernd
 

walt61

Active Member
Licensed User
Longtime User
Hang on - are you looking at fields 'dateTimeStart' and 'dateTimeEnd'? If you are, don't; they indeed refer to the event, not to an instance. Instead, look at 'instanceBegin' and 'instanceEnd', which are (as per https://developer.android.com/reference/android/provider/CalendarContract.Instances) 'the beginning/ending time of the instance, in UTC milliseconds'. My 'EventInfo' type is used for both events and instances (I seem to remember doing that to keep the code more compact).
 

catamitu

Member
Hi, thank you very much for your work.
Is there any way to delete created calendars? I cannot find them anywhere in google calendars and other widget calendars (such as Business Calendar) give me error now.
Thank you!
 

catamitu

Member
Hi @catamitu, you may have noticed the presence of method 'DeleteCalendar_DOES_NOT_WORK'; I remember spending quite a bit of time trying to figure out why it didn't work, but never found a solution :(
Oh, sorry to hear that. Thank you for your answer. Maybe in the future... Best wishes to all!
 
Top