From 030c3e6ce10e226bf06c5065a1c9272a28b847b7 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Wed, 1 Jul 2026 11:17:23 +0200 Subject: [PATCH] docs(design): mark contact special-dates implemented + note deviations Records the UID_2445 (vs SYNC_DATA1) identity decision, the sync-time age snapshot, and the seeded reminder default; checks off the #14/#15 task lists. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/design/contact-special-dates.md | 57 ++++++++++++++++++---------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/docs/design/contact-special-dates.md b/docs/design/contact-special-dates.md index 65bebb1..6af36a4 100644 --- a/docs/design/contact-special-dates.md +++ b/docs/design/contact-special-dates.md @@ -1,9 +1,25 @@ # Design: Contact special-dates calendars (+ per-calendar multiple reminders) -Status: **design / not yet implemented** -Date: 2026-06-30 +Status: **implemented** on `feat/contact-special-dates` (#14 prerequisite merged in) +Date: 2026-06-30 (implemented 2026-07-01) Tracking: Codeberg #15 (feature), Codeberg #14 (prerequisite) +Implementation notes / deviations from this design: + +- **Event identity key is a deterministic `Events.UID_2445`** + (`contact-:@calendula`), not `SYNC_DATA1`. On a LOCAL calendar + the provider drops `_sync` columns unless written through a sync-adapter URI; + `UID_2445` is written/read through the normal event URIs the app already uses + (and doubles as a stable iCal UID). The managed **calendar** still carries a + `CAL_SYNC2` marker for re-adoption (calendar-row writes already use the + sync-adapter URI). +- **Age is a sync-time snapshot.** A `FREQ=YEARLY` row has one static title, so + `{age}` reflects the upcoming birthday at the last sync (refreshed daily / on + foreground), not a per-occurrence value. +- New managed calendars seed a per-calendar all-day reminder default of + on-the-day + one week before, so birthdays get lead time out of the box. +- Title template is user-editable from day one (`{name}`, `{age}`). + This document captures the full design for surfacing contact birthdays — and, by extension, anniversaries and custom dates — as auto-updating local calendars in Calendula. It also specifies #14 (per-calendar *multiple* @@ -206,24 +222,25 @@ rest. ## Task outline ### #14 — per-calendar multiple default reminders (`feat/per-calendar-multi-reminders`) -- [ ] Widen global + per-calendar reminder defaults `Int` → `List` +- [x] Widen global + per-calendar reminder defaults `Int` → `List` (`SettingsPrefs.kt`), keep `Inherit/None/Minutes(list)`. -- [ ] `resolveDefaultReminder()` returns a list. -- [ ] `ReminderDefaultPicker` → multi-select (mirror event-form UI). -- [ ] Seed new events' `EventForm.reminders` from the resolved list. -- [ ] Migration / parse compatibility for existing single-value stored prefs. -- [ ] Tests: resolution, parse round-trip, all-day variant. +- [x] `resolveDefaultReminder()` returns a list. +- [x] `ReminderDefaultPicker` → multi-select (mirror event-form UI). +- [x] Seed new events' `EventForm.reminders` from the resolved list. +- [x] Migration / parse compatibility for existing single-value stored prefs. +- [x] Tests: resolution, parse round-trip, all-day variant. ### #15 — contact special-dates (`feat/contact-special-dates`) -- [ ] Declare `READ_CONTACTS`; feature-gated contextual request on enable. -- [ ] Per-type local calendars (create on enable, delete on disable+confirm). -- [ ] Contacts reader: `Event` rows by `TYPE`, year-less handling. -- [ ] Sync engine: idempotent diff keyed on `LOOKUP_KEY` in `SYNC_DATA1`; - targeted managed-column updates; seed user-owned fields on insert only. -- [ ] `FREQ=YEARLY` event generation + age (when year known). -- [ ] Auto-update: on enable, on foreground, daily WorkManager. -- [ ] Editor: disable managed fields for managed-calendar events. -- [ ] Revoked-permission detection + stalled-state surface. -- [ ] Settings sub-page: enable, per-type toggles, title template, show-age. -- [ ] Translatable strings (titles, sub-page). -- [ ] About / store copy for the optional `READ_CONTACTS` permission. +- [x] Declare `READ_CONTACTS`; feature-gated contextual request on enable. +- [x] Per-type local calendars (create on enable, delete on disable+confirm). +- [x] Contacts reader: `Event` rows by `TYPE`, year-less handling. +- [x] Sync engine: idempotent diff keyed on the deterministic `UID_2445` + (see notes; not `SYNC_DATA1`); targeted managed-column updates; seed + user-owned fields on insert only. +- [x] `FREQ=YEARLY` event generation + age (when year known; sync-time snapshot). +- [x] Auto-update: on enable, on foreground, daily WorkManager. +- [x] Editor: disable managed fields for managed-calendar events. +- [x] Revoked-permission detection + stalled-state surface. +- [x] Settings sub-page: enable, per-type toggles, title template, show-age. +- [x] Translatable strings (titles, sub-page). +- [x] About / store copy for the optional `READ_CONTACTS` permission.