diff --git a/ios/Calendarr iOS.xcodeproj/project.xcworkspace/xcuserdata/scarriffle.xcuserdatad/UserInterfaceState.xcuserstate b/ios/Calendarr iOS.xcodeproj/project.xcworkspace/xcuserdata/scarriffle.xcuserdatad/UserInterfaceState.xcuserstate index 5c63243..2e585ff 100644 Binary files a/ios/Calendarr iOS.xcodeproj/project.xcworkspace/xcuserdata/scarriffle.xcuserdatad/UserInterfaceState.xcuserstate and b/ios/Calendarr iOS.xcodeproj/project.xcworkspace/xcuserdata/scarriffle.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/Calendarr iOS/Models/CalendarStore.swift b/ios/Calendarr iOS/Models/CalendarStore.swift index c66929c..0ac1a30 100644 --- a/ios/Calendarr iOS/Models/CalendarStore.swift +++ b/ios/Calendarr iOS/Models/CalendarStore.swift @@ -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. diff --git a/ios/Calendarr iOS/Views/Calendar/CalendarHostView.swift b/ios/Calendarr iOS/Views/Calendar/CalendarHostView.swift index 44d78ee..8651b11 100644 --- a/ios/Calendarr iOS/Views/Calendar/CalendarHostView.swift +++ b/ios/Calendarr iOS/Views/Calendar/CalendarHostView.swift @@ -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()