From f440d385fa5d71d797c01e40026e1fa4fda65d9b Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 6 Jul 2026 18:38:21 +0200 Subject: [PATCH] fix: exclude managed special-dates calendars from .ics export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contact special-dates mirror calendars (birthdays/anniversaries) are derived from contacts and re-materialise from the contact sync, so backing them up only duplicates events on restore. Skip managed calendars in exportableEvents — covers both the manual export and the auto-backup, which share this path. Co-Authored-By: Claude Opus 4.8 --- .../calendula/data/calendar/CalendarDataSource.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt index 0c01ef2..e251f38 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/data/calendar/CalendarDataSource.kt @@ -613,10 +613,13 @@ class AndroidCalendarDataSource @Inject constructor( override fun exportableEvents(): List { // Only the local calendars the app owns and can write — synced calendars - // already have a backup (their server). Map id → display name for the + // already have a backup (their server). Exclude the managed special-dates + // mirror calendars: their events are derived from contacts, not authored + // here, and re-materialise from the contact sync — backing them up would + // just duplicate them on restore. Map id → display name for the // X-CALENDULA-CALENDAR tag a restore uses to fan back out. val names = calendars() - .filter { it.isLocal && it.canModifyContents } + .filter { it.isLocal && it.canModifyContents && !it.isManaged } .associate { it.id to it.displayName } if (names.isEmpty()) return emptyList()