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.
This commit is contained in:
Naveen 2023-06-14 17:33:32 +05:30
parent 4ad1b2cf81
commit 6fe938632b
No known key found for this signature in database
GPG Key ID: 0E155DAD31671DA3
5 changed files with 51 additions and 15 deletions

View File

@ -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()
}
}

View File

@ -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 {

View File

@ -696,7 +696,7 @@ fun Context.handleEventDeleting(eventIds: List<Long>, timestamps: List<Long>, 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 -> {

View File

@ -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) {

View File

@ -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