From d0f88c10995796296acf52cddf23e049b3a4dedf Mon Sep 17 00:00:00 2001 From: Naveen Date: Tue, 20 Jun 2023 04:28:04 +0530 Subject: [PATCH 1/6] End repetition on the original date The bug: - Create a recurring event with a specific number of occurrences like 10 that starts on Jan 1 - Edit some occurrence e.g. 5th and select "Update this and future occurrences only" - The edited event (5th) keeps repeating 10 times instead of ending on the end date of the original event (10th Jan). This is not consistent with other calendars (except nextcloud). The fix: Count the occurrence number starting from the first event and subtract it from the total number of repetitions before saving the event --- .../calendar/pro/activities/EventActivity.kt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 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 fac65a01e..19d7668a1 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 @@ -1376,13 +1376,22 @@ class EventActivity : SimpleActivity() { } EDIT_FUTURE_OCCURRENCES -> { ensureBackgroundThread { - eventsHelper.addEventRepeatLimit(mEvent.id!!, mEventOccurrenceTS) - mEvent.apply { - id = null + val eventId = mEvent.id!! + val originalEvent = eventsDB.getEventWithId(eventId) ?: return@ensureBackgroundThread + val hasFixedRepeatCount = originalEvent.repeatLimit < 0 && mEvent.repeatLimit < 0 + val repeatLimitUnchanged = originalEvent.repeatLimit == mEvent.repeatLimit + if (hasFixedRepeatCount && repeatLimitUnchanged) { + val daysSinceStart = (mEventOccurrenceTS - originalEvent.startTS) / DAY + val newRepeatLimit = mEvent.repeatLimit + daysSinceStart + mEvent.repeatLimit = newRepeatLimit } - eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) { - finish() + mEvent.id = null + eventsHelper.apply { + addEventRepeatLimit(eventId, mEventOccurrenceTS) + insertEvent(mEvent, addToCalDAV = true, showToasts = true) { + finish() + } } } } From 46e17aa697a4c92c319d465d7935492bd40e7f3e Mon Sep 17 00:00:00 2001 From: Naveen Date: Sat, 24 Jun 2023 15:35:23 +0530 Subject: [PATCH 2/6] Properly handle repeat limits Fixes these issues: - When choosing `Update/Delete this and all future occurrences`, the selected occurrence is never deleted/updated. - When choosing `Update this and all future occurrences`, the event is duplicated on the date of the selection --- .../calendar/pro/helpers/EventsHelper.kt | 14 +++++++++++--- .../calendar/pro/helpers/Parser.kt | 9 ++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) 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 38f593d1e..d09fac49c 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 @@ -225,9 +225,17 @@ class EventsHelper(val context: Context) { deleteEvents(eventIds, true) } - fun addEventRepeatLimit(eventId: Long, limitTS: Long) { - val time = Formatter.getDateTimeFromTS(limitTS) - eventsDB.updateEventRepetitionLimit(limitTS - time.hourOfDay, eventId) + fun addEventRepeatLimit(eventId: Long, occurrenceTS: Long) { + val event = eventsDB.getEventWithId(eventId) ?: return + val previousOccurrenceTS = occurrenceTS - event.repeatInterval // always update repeat limit of the occurrence preceding the one being edited + val repeatLimitDateTime = Formatter.getDateTimeFromTS(previousOccurrenceTS).withTimeAtStartOfDay() + val repeatLimitTS = if (event.getIsAllDay()) { + repeatLimitDateTime.seconds() + } else { + repeatLimitDateTime.withTime(23, 59, 59, 0).seconds() + } + + eventsDB.updateEventRepetitionLimit(repeatLimitTS, eventId) context.cancelNotification(eventId) context.cancelPendingIntent(eventId) if (config.caldavSync) { diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt index b0b317e39..a4c6f9436 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/Parser.kt @@ -145,7 +145,14 @@ class Parser { private fun getRepeatLimitString(event: Event) = when { event.repeatLimit == 0L -> "" event.repeatLimit < 0 -> ";$COUNT=${-event.repeatLimit}" - else -> ";$UNTIL=${Formatter.getDayCodeFromTS(event.repeatLimit)}" + else -> if (event.getIsAllDay()) { + ";$UNTIL=${Formatter.getDayCodeFromTS(event.repeatLimit)}" + } else { + val dateTime = Formatter.getUTCDateTimeFromTS(event.repeatLimit) + val dayCode = dateTime.toString(Formatter.DAYCODE_PATTERN) + val timeCode = dateTime.toString(Formatter.TIME_PATTERN) + ";$UNTIL=${dayCode}T${timeCode}Z" + } } private fun getByMonth(event: Event) = when { From acff39740e9416178c128a30723c8a240dd2b4cd Mon Sep 17 00:00:00 2001 From: Naveen Date: Sat, 24 Jun 2023 16:04:10 +0530 Subject: [PATCH 3/6] Properly count occurrences --- .../calendar/pro/activities/EventActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 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 19d7668a1..286600d38 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 @@ -1381,8 +1381,8 @@ class EventActivity : SimpleActivity() { val hasFixedRepeatCount = originalEvent.repeatLimit < 0 && mEvent.repeatLimit < 0 val repeatLimitUnchanged = originalEvent.repeatLimit == mEvent.repeatLimit if (hasFixedRepeatCount && repeatLimitUnchanged) { - val daysSinceStart = (mEventOccurrenceTS - originalEvent.startTS) / DAY - val newRepeatLimit = mEvent.repeatLimit + daysSinceStart + val occurrencesSinceStart = (mEventOccurrenceTS - originalEvent.startTS) / originalEvent.repeatInterval + val newRepeatLimit = mEvent.repeatLimit + occurrencesSinceStart mEvent.repeatLimit = newRepeatLimit } From 05084ea3307a53ecedaaf74d6d50fd08af8c896a Mon Sep 17 00:00:00 2001 From: Naveen Date: Sat, 24 Jun 2023 18:49:56 +0530 Subject: [PATCH 4/6] Properly handle repeating tasks --- .../calendar/pro/activities/EventActivity.kt | 9 +-------- .../calendar/pro/activities/TaskActivity.kt | 16 +++++++++------- .../calendar/pro/extensions/Event.kt | 10 ++++++++++ .../calendar/pro/helpers/EventsHelper.kt | 2 +- 4 files changed, 21 insertions(+), 16 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 286600d38..9c3d9d8ba 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 @@ -1378,14 +1378,7 @@ class EventActivity : SimpleActivity() { ensureBackgroundThread { val eventId = mEvent.id!! val originalEvent = eventsDB.getEventWithId(eventId) ?: return@ensureBackgroundThread - val hasFixedRepeatCount = originalEvent.repeatLimit < 0 && mEvent.repeatLimit < 0 - val repeatLimitUnchanged = originalEvent.repeatLimit == mEvent.repeatLimit - if (hasFixedRepeatCount && repeatLimitUnchanged) { - val occurrencesSinceStart = (mEventOccurrenceTS - originalEvent.startTS) / originalEvent.repeatInterval - val newRepeatLimit = mEvent.repeatLimit + occurrencesSinceStart - mEvent.repeatLimit = newRepeatLimit - } - + mEvent.maybeAdjustRepeatLimitCount(originalEvent, mEventOccurrenceTS) mEvent.id = null eventsHelper.apply { addEventRepeatLimit(eventId, mEventOccurrenceTS) 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 ead2286d4..cf1e94685 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 @@ -489,13 +489,15 @@ class TaskActivity : SimpleActivity() { } EDIT_FUTURE_OCCURRENCES -> { ensureBackgroundThread { - eventsHelper.addEventRepeatLimit(mTask.id!!, mTaskOccurrenceTS) - mTask.apply { - id = null - } - - eventsHelper.insertTask(mTask, showToasts = true) { - finish() + val taskId = mTask.id!! + val originalTask = eventsDB.getTaskWithId(taskId) ?: return@ensureBackgroundThread + mTask.maybeAdjustRepeatLimitCount(originalTask, mTaskOccurrenceTS) + mTask.id = null + eventsHelper.apply { + addEventRepeatLimit(taskId, mTaskOccurrenceTS) + insertTask(mTask, showToasts = true) { + finish() + } } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt index e9d2c8847..51f7f10bb 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt @@ -29,3 +29,13 @@ fun Event.toUtcAllDayEvent() { startTS = Formatter.getShiftedUtcTS(startTS) endTS = Formatter.getShiftedUtcTS(endTS) } + +fun Event.maybeAdjustRepeatLimitCount(original: Event, occurrenceTS: Long) { + val hasFixedRepeatCount = original.repeatLimit < 0 && repeatLimit < 0 + val repeatLimitUnchanged = original.repeatLimit == repeatLimit + if (hasFixedRepeatCount && repeatLimitUnchanged) { + val occurrencesSinceStart = (occurrenceTS - original.startTS) / original.repeatInterval + val newRepeatLimit = repeatLimit + occurrencesSinceStart + this.repeatLimit = newRepeatLimit + } +} 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 d09fac49c..92567695f 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 @@ -226,7 +226,7 @@ class EventsHelper(val context: Context) { } fun addEventRepeatLimit(eventId: Long, occurrenceTS: Long) { - val event = eventsDB.getEventWithId(eventId) ?: return + val event = eventsDB.getEventOrTaskWithId(eventId) ?: return val previousOccurrenceTS = occurrenceTS - event.repeatInterval // always update repeat limit of the occurrence preceding the one being edited val repeatLimitDateTime = Formatter.getDateTimeFromTS(previousOccurrenceTS).withTimeAtStartOfDay() val repeatLimitTS = if (event.getIsAllDay()) { From fe09a937ec5730d15de54413b1d916096bc50e8f Mon Sep 17 00:00:00 2001 From: Naveen Date: Sat, 24 Jun 2023 19:42:13 +0530 Subject: [PATCH 5/6] Delete original event to avoid duplication --- .../calendar/pro/activities/EventActivity.kt | 4 ++++ .../simplemobiletools/calendar/pro/activities/TaskActivity.kt | 4 ++++ 2 files changed, 8 insertions(+) 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 9c3d9d8ba..28507736c 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 @@ -1382,6 +1382,10 @@ class EventActivity : SimpleActivity() { mEvent.id = null eventsHelper.apply { addEventRepeatLimit(eventId, mEventOccurrenceTS) + if (mEventOccurrenceTS == originalEvent.startTS) { + deleteEvent(eventId, true) + } + 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 cf1e94685..99b2a1edf 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 @@ -495,6 +495,10 @@ class TaskActivity : SimpleActivity() { mTask.id = null eventsHelper.apply { addEventRepeatLimit(taskId, mTaskOccurrenceTS) + if (mTaskOccurrenceTS == originalTask.startTS) { + deleteEvent(taskId, true) + } + insertTask(mTask, showToasts = true) { finish() } From 3830e849d6bed25971e65faa1f914240213b0aab Mon Sep 17 00:00:00 2001 From: Naveen Date: Sat, 24 Jun 2023 20:10:56 +0530 Subject: [PATCH 6/6] Add comment --- .../com/simplemobiletools/calendar/pro/extensions/Event.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt index 51f7f10bb..de9908b4c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/extensions/Event.kt @@ -30,6 +30,7 @@ fun Event.toUtcAllDayEvent() { endTS = Formatter.getShiftedUtcTS(endTS) } +// this is to make sure the repetition ends on the date set when creating the original event fun Event.maybeAdjustRepeatLimitCount(original: Event, occurrenceTS: Long) { val hasFixedRepeatCount = original.repeatLimit < 0 && repeatLimit < 0 val repeatLimitUnchanged = original.repeatLimit == repeatLimit