Stop the calendar blinking empty after saving an event

Routing the post-save reload through the manual sync button made a new Home
Assistant event appear, but at the cost of invalidateCache(), which drops the
cached events as well as the range bounds — so every event vanished and
reappeared for one new one. That reads as unfinished, and it is.

Only the range bounds have to go: nil bounds are what force the next fetch to
reach the server. The events can stay on screen until the fresh ones replace
them. Saving now does exactly that and nothing more; the menu's manual sync
keeps clearing everything, which is what a full refresh is for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-20 22:01:16 +02:00
co-authored by Claude Opus 5
parent 75ae038529
commit 2db4b42fa1
3 changed files with 20 additions and 3 deletions
@@ -514,6 +514,14 @@ class CalendarStore {
allCachedEvents = []
}
/// Force the next fetch to reach the server, without emptying what is on
/// screen. `invalidateCache()` drops the events too, which makes the whole
/// calendar blink empty and refill — far too much for one new event.
func invalidateRange() {
cachedStart = nil
cachedEnd = nil
}
/// Calendars / sources that reported a sync error on the last fetch. Events
/// matching either must NOT be evicted from the cache on a partial sync —
/// stale data beats a completely empty calendar.
@@ -464,9 +464,7 @@ struct CalendarHostView: View {
showNewBirthday: $showNewBirthday,
api: api,
reload: { await onNavigate() },
// Same path as the manual reload button, which is the
// one that demonstrably shows a new Home Assistant event.
reloadForce: { await forceReload() })
reloadForce: { await reloadAfterSave() })
}
// MARK: – Loading logic
@@ -527,6 +525,17 @@ struct CalendarHostView: View {
await store.loadEvents(api: api, start: s, end: e)
}
/// After creating or editing: refetch the visible range from the server,
/// keeping the current events on screen while it happens. Clearing only the
/// range — not the events — is what separates this from the menu's manual
/// sync, which is allowed to blank the calendar because the user asked for
/// a full refresh.
private func reloadAfterSave() async {
store.invalidateRange()
let (s, e) = store.rangeForCurrentView()
await store.loadEvents(api: api, start: s, end: e, force: true)
}
/// Called when cacheMonths setting changes – clear cache and re-prefetch.
private func recache() async {
store.invalidateCache()