From 6fe938632b8c32d105ec6696b7793ff97ab79ce3 Mon Sep 17 00:00:00 2001 From: Naveen Date: Wed, 14 Jun 2023 17:33:32 +0530 Subject: [PATCH] Properly handle `Update the selected occurrence only` Previously, if an event was modified using some other client then the exception event's parent id was ignored or overwritten with 0 at sync and that means the parent and child events were disconnected locally. Deleting the parent event did not delete the child event. If a recurrence was modified using Simple Calendar then it was disconnected from it's parent event both locally and on the server because `ORIGINAL_ID` and `ORIGINAL_INSTANCE_TIME` was not specified. On top of that, another exception event was created to make sure the parent event doesn't show up on the date of the disconnected child event. This change fixes these two issues. --- .../calendar/pro/activities/EventActivity.kt | 5 ++- .../calendar/pro/activities/TaskActivity.kt | 5 ++- .../calendar/pro/extensions/Context.kt | 2 +- .../calendar/pro/helpers/CalDAVHelper.kt | 36 +++++++++++++++---- .../calendar/pro/helpers/EventsHelper.kt | 18 +++++++++- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt index e3044aa8c..fac65a01e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt @@ -1155,7 +1155,7 @@ class EventActivity : SimpleActivity() { DeleteEventDialog(this, arrayListOf(mEvent.id!!), mEvent.repeatInterval > 0) { ensureBackgroundThread { when (it) { - DELETE_SELECTED_OCCURRENCE -> eventsHelper.addEventRepetitionException(mEvent.id!!, mEventOccurrenceTS, true) + DELETE_SELECTED_OCCURRENCE -> eventsHelper.deleteRepeatingEventOccurrence(mEvent.id!!, mEventOccurrenceTS, true) DELETE_FUTURE_OCCURRENCES -> eventsHelper.addEventRepeatLimit(mEvent.id!!, mEventOccurrenceTS) DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mEvent.id!!, true) } @@ -1361,7 +1361,6 @@ class EventActivity : SimpleActivity() { when (it) { EDIT_SELECTED_OCCURRENCE -> { ensureBackgroundThread { - eventsHelper.addEventRepetitionException(mEvent.id!!, mEventOccurrenceTS, true) mEvent.apply { parentId = id!!.toLong() id = null @@ -1370,7 +1369,7 @@ class EventActivity : SimpleActivity() { repeatLimit = 0 } - eventsHelper.insertEvent(mEvent, true, true) { + eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) { finish() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt index 8479b7bf6..ead2286d4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt @@ -474,7 +474,6 @@ class TaskActivity : SimpleActivity() { when (it) { EDIT_SELECTED_OCCURRENCE -> { ensureBackgroundThread { - eventsHelper.addEventRepetitionException(mTask.id!!, mTaskOccurrenceTS, addToCalDAV = false) mTask.apply { parentId = id!!.toLong() id = null @@ -533,9 +532,9 @@ class TaskActivity : SimpleActivity() { DeleteEventDialog(this, arrayListOf(mTask.id!!), mTask.repeatInterval > 0, isTask = true) { ensureBackgroundThread { when (it) { - DELETE_SELECTED_OCCURRENCE -> eventsHelper.addEventRepetitionException(mTask.id!!, mTaskOccurrenceTS, true) + DELETE_SELECTED_OCCURRENCE -> eventsHelper.deleteRepeatingEventOccurrence(mTask.id!!, mTaskOccurrenceTS, false) DELETE_FUTURE_OCCURRENCES -> eventsHelper.addEventRepeatLimit(mTask.id!!, mTaskOccurrenceTS) - DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mTask.id!!, true) + DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mTask.id!!, false) } runOnUiThread { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt index ad7a1f3e8..6820ad3c0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Context.kt @@ -696,7 +696,7 @@ fun Context.handleEventDeleting(eventIds: List, timestamps: List, ac when (action) { DELETE_SELECTED_OCCURRENCE -> { eventIds.forEachIndexed { index, value -> - eventsHelper.addEventRepetitionException(value, timestamps[index], true) + eventsHelper.deleteRepeatingEventOccurrence(value, timestamps[index], true) } } DELETE_FUTURE_OCCURRENCES -> { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt index fadf3f93f..c05b322d7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/CalDAVHelper.kt @@ -185,6 +185,7 @@ class CalDAVHelper(val context: Context) { Events.CALENDAR_TIME_ZONE, Events.DELETED, Events.AVAILABILITY, + Events.STATUS, Events.EVENT_COLOR ) @@ -214,6 +215,7 @@ class CalDAVHelper(val context: Context) { val reminders = getCalDAVEventReminders(id) val attendees = Gson().toJson(getCalDAVEventAttendees(id)) val availability = cursor.getIntValue(Events.AVAILABILITY) + val status = cursor.getIntValue(Events.STATUS) val color = cursor.getIntValueOrNull(Events.EVENT_COLOR) val displayColor = if (color != null) { getDisplayColorFromColor(color) @@ -255,14 +257,22 @@ class CalDAVHelper(val context: Context) { val parentImportId = "$source-$originalId" val parentEvent = context.eventsDB.getEventWithImportId(parentImportId) val originalDayCode = Formatter.getDayCodeFromTS(originalInstanceTime / 1000L) - if (parentEvent != null && !parentEvent.repetitionExceptions.contains(originalDayCode)) { - val storedEventId = context.eventsDB.getEventIdWithImportId(importId) - if (storedEventId != null) { - event.id = storedEventId + if (parentEvent != null) { + // add this event to the parent event's list of exceptions + if (!parentEvent.repetitionExceptions.contains(originalDayCode)) { + parentEvent.addRepetitionException(originalDayCode) + eventsHelper.insertEvent(parentEvent, addToCalDAV = false, showToasts = false) + } + + // store the event in the local db only if it is an occurrence that has been modified and not deleted + if (status != Events.STATUS_CANCELED) { + val storedEventId = context.eventsDB.getEventIdWithImportId(importId) + if (storedEventId != null) { + event.id = storedEventId + } + event.parentId = parentEvent.id!! + eventsHelper.insertEvent(event, addToCalDAV = false, showToasts = false) } - event.parentId = parentEvent.id!! - parentEvent.addRepetitionException(originalDayCode) - eventsHelper.insertEvent(parentEvent, addToCalDAV = false, showToasts = false) return@queryCursorInlined } @@ -432,6 +442,18 @@ class CalDAVHelper(val context: Context) { put(Events.ALL_DAY, 0) } + val parentEventId = event.parentId + if (parentEventId != 0L) { + val parentEvent = context.eventsDB.getEventWithId(parentEventId) ?: return@apply + put(Events.ORIGINAL_ID, parentEvent.getCalDAVEventId()) + put(Events.ORIGINAL_INSTANCE_TIME, event.startTS * 1000L) + if (parentEvent.getIsAllDay()) { + put(Events.ORIGINAL_ALL_DAY, 1) + } else { + put(Events.ORIGINAL_ALL_DAY, 0) + } + } + put(Events.DTSTART, event.startTS * 1000L) put(Events.EVENT_TIMEZONE, event.getTimeZoneString()) if (event.repeatInterval > 0) { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt index fc9327c71..0b0f25d0b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt @@ -116,6 +116,14 @@ class EventsHelper(val context: Context) { return } + val parentEventId = event.parentId + if (parentEventId != 0L) { + val parentEvent = eventsDB.getEventOrTaskWithId(parentEventId) ?: return + val startDayCode = Formatter.getDayCodeFromTS(event.startTS) + parentEvent.addRepetitionException(startDayCode) + eventsDB.updateEventRepetitionExceptions(parentEvent.repetitionExceptions.toString(), parentEventId) + } + event.id = eventsDB.insertOrUpdate(event) context.updateWidgets() @@ -129,6 +137,14 @@ class EventsHelper(val context: Context) { } fun insertTask(task: Event, showToasts: Boolean, callback: () -> Unit) { + val parentEventId = task.parentId + if (parentEventId != 0L) { + val parentEvent = eventsDB.getEventOrTaskWithId(parentEventId) ?: return + val startDayCode = Formatter.getDayCodeFromTS(task.startTS) + parentEvent.addRepetitionException(startDayCode) + eventsDB.updateEventRepetitionExceptions(parentEvent.repetitionExceptions.toString(), parentEventId) + } + task.id = eventsDB.insertOrUpdate(task) context.updateWidgets() context.scheduleNextEventReminder(task, showToasts) @@ -232,7 +248,7 @@ class EventsHelper(val context: Context) { } } - fun addEventRepetitionException(parentEventId: Long, occurrenceTS: Long, addToCalDAV: Boolean) { + fun deleteRepeatingEventOccurrence(parentEventId: Long, occurrenceTS: Long, addToCalDAV: Boolean) { ensureBackgroundThread { val parentEvent = eventsDB.getEventOrTaskWithId(parentEventId) ?: return@ensureBackgroundThread var repetitionExceptions = parentEvent.repetitionExceptions