fix: detach the occurrence when editing one instance of an unsynced series (#234)
"Edit only this event" wrote a modified-occurrence exception unconditionally. That is the right shape for a synced series and the wrong one for everything else: an exception attaches to its parent through ORIGINAL_SYNC_ID, so on a row with no _sync_id the link never forms — the insert fails or lands an orphan, the generic catch in EventEditViewModel turns it into a snackbar, and the scope dialog just closes again. To the reporter that read as "nothing happens, ever", with a stray copy of the event left behind the one time the insert did land. This is the same constraint deleteOccurrence has documented since #47, and the same calendars: a local calendar, Calendula's own contact special-date calendars, and — the reporter's case — a Google calendar whose rows the sync adapter has not stamped yet, which is exactly why it "shows as on-device". updateOccurrence now branches on _sync_id the way deleteOccurrence does. A synced series keeps the exception path untouched; its write shape is load- bearing and verified. A series without one gets the occurrence excluded from the parent via EXDATE and the edited values inserted as a standalone event on the same calendar — a detached instance, minus the RECURRENCE-ID the provider has no way to store here. The cost is honest and worth naming: the edited occurrence stops travelling with its series. The alternative is an edit that silently does nothing. Two things shape the write. The parent update reuses buildOccurrenceExdateValues unchanged, so it keeps carrying the whole time/recurrence set — an EXDATE-only update is not a recurrence change to the provider and leaves the expanded instances standing (#47's first quirk). And the form's RRULE is stripped before the insert: the exception path gets an inherited rule cleared for free by DTSTART + DURATION, but nothing clears one here, so leaving it would insert a second *series* overlapping the first. Ordering is chosen for the failure cases, not the happy path. The insert runs first, so a failure there leaves the series completely untouched — the discipline updateEventFromOccurrence already follows. If the EXDATE update then fails, the new row is a visible duplicate of an occurrence still in the series, so it is rolled back (best effort) before the failure surfaces. The reverse order could strand an occurrence excluded from its series with nothing standing in for it, turning an edit into a silent delete. Also makes a failed save legible, since this bug was invisible precisely because it wasn't: the failure snackbar gets the long duration instead of a flash, and the catch logs the scope and event id — never the form's content — so a failure leaves something to report. Adds JVM tests for the detached shape: the rule is dropped and the row becomes a one-off with DTEND, all-day stays on UTC midnights, and the detached row's DTSTART agrees with the EXDATE stamp that removes it from the parent, timed and all-day. The provider behaviour itself still needs a device. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- **"Only this event" now actually saves your edit.** On some calendars —
|
||||
including Google ones that still show as on-device, and any local calendar —
|
||||
editing a single occurrence of a repeating event did nothing at all: the scope
|
||||
dialog closed, the edit screen stayed put, and saving again just repeated it.
|
||||
Android can only attach a single-occurrence change to its series once the
|
||||
calendar has been synced at least once, so on those calendars the change had
|
||||
nowhere to go. Calendula now removes that one occurrence from the series and
|
||||
saves the edit as its own event instead, which is what you see either way. A
|
||||
save that does fail also says so for longer, rather than flashing past
|
||||
([#234]).
|
||||
|
||||
## [2.19.3] — 2026-08-22
|
||||
|
||||
### Added
|
||||
@@ -1471,3 +1483,4 @@ automatically, with zero telemetry and no internet permission.
|
||||
[#192]: https://codeberg.org/jlmakiola/calendula/issues/192
|
||||
[#196]: https://codeberg.org/jlmakiola/calendula/issues/196
|
||||
[#214]: https://codeberg.org/jlmakiola/calendula/issues/214
|
||||
[#234]: https://codeberg.org/jlmakiola/calendula/issues/234
|
||||
|
||||
Reference in New Issue
Block a user