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) { DeleteEventDialog(this, arrayListOf(mEvent.id!!), mEvent.repeatInterval > 0) {
ensureBackgroundThread { ensureBackgroundThread {
when (it) { 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_FUTURE_OCCURRENCES -> eventsHelper.addEventRepeatLimit(mEvent.id!!, mEventOccurrenceTS)
DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mEvent.id!!, true) DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mEvent.id!!, true)
} }
@ -1361,7 +1361,6 @@ class EventActivity : SimpleActivity() {
when (it) { when (it) {
EDIT_SELECTED_OCCURRENCE -> { EDIT_SELECTED_OCCURRENCE -> {
ensureBackgroundThread { ensureBackgroundThread {
eventsHelper.addEventRepetitionException(mEvent.id!!, mEventOccurrenceTS, true)
mEvent.apply { mEvent.apply {
parentId = id!!.toLong() parentId = id!!.toLong()
id = null id = null
@ -1370,7 +1369,7 @@ class EventActivity : SimpleActivity() {
repeatLimit = 0 repeatLimit = 0
} }
eventsHelper.insertEvent(mEvent, true, true) { eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) {
finish() finish()
} }
} }

View File

@ -474,7 +474,6 @@ class TaskActivity : SimpleActivity() {
when (it) { when (it) {
EDIT_SELECTED_OCCURRENCE -> { EDIT_SELECTED_OCCURRENCE -> {
ensureBackgroundThread { ensureBackgroundThread {
eventsHelper.addEventRepetitionException(mTask.id!!, mTaskOccurrenceTS, addToCalDAV = false)
mTask.apply { mTask.apply {
parentId = id!!.toLong() parentId = id!!.toLong()
id = null id = null
@ -533,9 +532,9 @@ class TaskActivity : SimpleActivity() {
DeleteEventDialog(this, arrayListOf(mTask.id!!), mTask.repeatInterval > 0, isTask = true) { DeleteEventDialog(this, arrayListOf(mTask.id!!), mTask.repeatInterval > 0, isTask = true) {
ensureBackgroundThread { ensureBackgroundThread {
when (it) { 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_FUTURE_OCCURRENCES -> eventsHelper.addEventRepeatLimit(mTask.id!!, mTaskOccurrenceTS)
DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mTask.id!!, true) DELETE_ALL_OCCURRENCES -> eventsHelper.deleteEvent(mTask.id!!, false)
} }
runOnUiThread { runOnUiThread {

View File

@ -696,7 +696,7 @@ fun Context.handleEventDeleting(eventIds: List<Long>, timestamps: List<Long>, ac
when (action) { when (action) {
DELETE_SELECTED_OCCURRENCE -> { DELETE_SELECTED_OCCURRENCE -> {
eventIds.forEachIndexed { index, value -> eventIds.forEachIndexed { index, value ->
eventsHelper.addEventRepetitionException(value, timestamps[index], true) eventsHelper.deleteRepeatingEventOccurrence(value, timestamps[index], true)
} }
} }
DELETE_FUTURE_OCCURRENCES -> { DELETE_FUTURE_OCCURRENCES -> {

View File

@ -185,6 +185,7 @@ class CalDAVHelper(val context: Context) {
Events.CALENDAR_TIME_ZONE, Events.CALENDAR_TIME_ZONE,
Events.DELETED, Events.DELETED,
Events.AVAILABILITY, Events.AVAILABILITY,
Events.STATUS,
Events.EVENT_COLOR Events.EVENT_COLOR
) )
@ -214,6 +215,7 @@ class CalDAVHelper(val context: Context) {
val reminders = getCalDAVEventReminders(id) val reminders = getCalDAVEventReminders(id)
val attendees = Gson().toJson(getCalDAVEventAttendees(id)) val attendees = Gson().toJson(getCalDAVEventAttendees(id))
val availability = cursor.getIntValue(Events.AVAILABILITY) val availability = cursor.getIntValue(Events.AVAILABILITY)
val status = cursor.getIntValue(Events.STATUS)
val color = cursor.getIntValueOrNull(Events.EVENT_COLOR) val color = cursor.getIntValueOrNull(Events.EVENT_COLOR)
val displayColor = if (color != null) { val displayColor = if (color != null) {
getDisplayColorFromColor(color) getDisplayColorFromColor(color)
@ -255,14 +257,22 @@ class CalDAVHelper(val context: Context) {
val parentImportId = "$source-$originalId" val parentImportId = "$source-$originalId"
val parentEvent = context.eventsDB.getEventWithImportId(parentImportId) val parentEvent = context.eventsDB.getEventWithImportId(parentImportId)
val originalDayCode = Formatter.getDayCodeFromTS(originalInstanceTime / 1000L) val originalDayCode = Formatter.getDayCodeFromTS(originalInstanceTime / 1000L)
if (parentEvent != null && !parentEvent.repetitionExceptions.contains(originalDayCode)) { if (parentEvent != null) {
val storedEventId = context.eventsDB.getEventIdWithImportId(importId) // add this event to the parent event's list of exceptions
if (storedEventId != null) { if (!parentEvent.repetitionExceptions.contains(originalDayCode)) {
event.id = storedEventId 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 return@queryCursorInlined
} }
@ -432,6 +442,18 @@ class CalDAVHelper(val context: Context) {
put(Events.ALL_DAY, 0) 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.DTSTART, event.startTS * 1000L)
put(Events.EVENT_TIMEZONE, event.getTimeZoneString()) put(Events.EVENT_TIMEZONE, event.getTimeZoneString())
if (event.repeatInterval > 0) { if (event.repeatInterval > 0) {

View File

@ -116,6 +116,14 @@ class EventsHelper(val context: Context) {
return 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) event.id = eventsDB.insertOrUpdate(event)
context.updateWidgets() context.updateWidgets()
@ -129,6 +137,14 @@ class EventsHelper(val context: Context) {
} }
fun insertTask(task: Event, showToasts: Boolean, callback: () -> Unit) { 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) task.id = eventsDB.insertOrUpdate(task)
context.updateWidgets() context.updateWidgets()
context.scheduleNextEventReminder(task, showToasts) 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 { ensureBackgroundThread {
val parentEvent = eventsDB.getEventOrTaskWithId(parentEventId) ?: return@ensureBackgroundThread val parentEvent = eventsDB.getEventOrTaskWithId(parentEventId) ?: return@ensureBackgroundThread
var repetitionExceptions = parentEvent.repetitionExceptions var repetitionExceptions = parentEvent.repetitionExceptions