From 2c7d976d6f76958271774a491c499ad7cf44f69d Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 26 Jul 2026 18:49:29 +0200 Subject: [PATCH] fix(calendars): don't reconcile visibility off an unreadable calendar list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The data source turns a null cursor — a provider that is momentarily unavailable — into an empty list, which the reconciler read as "this device has no calendars". Both of the decisions it then takes are one-way: every pending id counts as settled, so the whole set is dropped without VISIBLE = 0 ever being written and the calendars the user switched off come back on with their events and reminders; and with nothing to find hidden, the one-time notice is stored as "nothing to explain" for good. The repository already refuses to cache an empty read for exactly this reason. Do the same here and leave both decisions to the next run. Co-Authored-By: Claude Opus 5 (1M context) --- .../data/calendar/CalendarVisibilityReconciler.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarVisibilityReconciler.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarVisibilityReconciler.kt index bca56dd..b79c039 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarVisibilityReconciler.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarVisibilityReconciler.kt @@ -67,6 +67,14 @@ class CalendarVisibilityReconciler @Inject constructor( // drain and nothing left to decide, so don't pay for the query. if (pending.isEmpty() && noticeSettled) return@withContext val calendars = dataSource.calendars() + // An empty read means "couldn't read", not "no calendars": the data + // source turns a null cursor — a provider momentarily unavailable — + // into an empty list. Both decisions below are one-way, so taking + // that reading as the truth would drop the whole pending set without + // ever writing VISIBLE = 0 (switching the user's calendars back on, + // events and reminders with them) and settle the notice as "nothing + // to explain". Leave both to the next run. + if (calendars.isEmpty()) return@withContext settleNoticeOnce(hasSystemHiddenCalendars(calendars, pending)) if (pending.isEmpty() || !hasPermission(Manifest.permission.WRITE_CALENDAR)) { return@withContext