docs(roadmap): sync state and promote attendee editing to Tier 5
Bring the planning docs up to date with reality from the changelog and recent merges: - Mark the .ics engine (export + import) shipped in v2.7.0 and local- calendar backup done; clear the stale "in progress" tags. - Note snooze/dismiss merged into release/v2.8.0 alongside Codeberg crash reports. - Record drag-and-drop rescheduling as consciously rejected. - Promote attendee editing out of the gated bucket into Tier 5 #12 (read side already shipped in v0.6; only the write side is missing), with the sync-adapter invitation caveat to resolve first. - Refresh STATE.md (was stuck at v2.4) through v2.7.5 and the 2.8.0 integration branch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -236,22 +236,34 @@ pass on the existing controls; new toggles ride in with their own features.
|
|||||||
9. **Reminders — defaults + delivery reliability** *(shipped v2.6.0)* — global
|
9. **Reminders — defaults + delivery reliability** *(shipped v2.6.0)* — global
|
||||||
default reminder **+ per-calendar override**, bundled with battery-exemption
|
default reminder **+ per-calendar override**, bundled with battery-exemption
|
||||||
hardening. Full sketch in "Reminders — defaults & delivery reliability" below.
|
hardening. Full sketch in "Reminders — defaults & delivery reliability" below.
|
||||||
10. **The `.ics` engine — export + import** *(in progress → v2.7)* — one
|
10. **The `.ics` engine — export + import** *(shipped v2.7.0, 2026-06-18)* — one
|
||||||
hand-rolled serializer/parser (zero deps, stays on `kotlinx-datetime`),
|
hand-rolled serializer/parser (zero deps, stays on `kotlinx-datetime`),
|
||||||
four surfaces: single-event share + whole-calendar backup (export),
|
four surfaces all shipped: single-event share + whole-calendar backup
|
||||||
open-`.ics`→form + whole-calendar restore (import). Closes the
|
(export), open-`.ics`→form + whole-calendar bulk import (import). Closed the
|
||||||
device-local-calendar data-loss gap (#10/#11 merged here). Built as **two
|
device-local-calendar data-loss gap (#10/#11 merged here). Built as two
|
||||||
sequential branches in one release**: `feat/ics-export` (write side +
|
sequential branches: `feat/ics-export` (write side + UID-on-create precursor)
|
||||||
UID-on-create precursor) then `feat/ics-import` (parser, restore, dedup).
|
then `feat/ics-import` (parser, restore, dedup by UID). Import is
|
||||||
Import is liberal-in/strict-out: skip-and-report foreign `VTIMEZONE` /
|
liberal-in/strict-out: skip-and-report foreign `VTIMEZONE` / `RECURRENCE-ID`
|
||||||
`RECURRENCE-ID` it can't model. Timezone rule: all-day `VALUE=DATE`,
|
/ guest lists it can't model. Plans:
|
||||||
non-recurring timed UTC `Z`, recurring timed `TZID`-labelled from the stored
|
`docs/superpowers/plans/2026-06-18-05-ics-export.md` + `…-06-ics-import.md`.
|
||||||
`EVENT_TIMEZONE` (no `VTIMEZONE` blocks; resolved against the OS tz DB on
|
11. **Snooze / dismiss notification actions** *(merged into release/v2.8.0)* —
|
||||||
import). Plan: `docs/superpowers/plans/2026-06-18-05-ics-export.md`.
|
followed the `.ics` work; inherits v2.6's deferred exact-alarm/WorkManager
|
||||||
11. **Snooze / dismiss notification actions** *(next, after v2.7)* — follows the
|
decision (snooze must re-fire an alarm).
|
||||||
`.ics` work; inherits v2.6's deferred exact-alarm/WorkManager decision (snooze
|
|
||||||
must re-fire an alarm).
|
**Tier 5 — close the read/write gap on the event model** *(opened 2026-06-22)*
|
||||||
12. Drag & drop rescheduling in day/week — big-ticket, own slice (recurring drops reuse the scope dialog)
|
12. **Attendee editing** *(next — promoted from the gated "Locations & People"
|
||||||
|
bucket, owner says high-importance 2026-06-22)* — attendees are already
|
||||||
|
*read* (queried, mapped, shown on the detail screen since v0.6) but the
|
||||||
|
event form can't *write* them, the last big read-only gap in the event
|
||||||
|
model. Add an attendees section to `EventEditScreen` / `EventForm`: add by
|
||||||
|
typed email (contact-picker entry can follow later), edit/remove rows, set
|
||||||
|
role (required / optional) — writing `CalendarContract.Attendees` rows on
|
||||||
|
insert + dirty-checked update, mirroring the reminders-diff pattern.
|
||||||
|
**Caveat to resolve first:** writing `Attendees` rows triggers sync-adapter
|
||||||
|
*invitation* behavior that differs by backend (Google auto-emails invites;
|
||||||
|
DAVx5/CalDAV writes the `ATTENDEE` property and lets the server decide) —
|
||||||
|
decide and document what Calendula promises before building. Full sketch in
|
||||||
|
"Attendee editing" under Locations & People below.
|
||||||
|
|
||||||
**Gated — explicit go/no-go before any work (mostly INTERNET-permission calls)**
|
**Gated — explicit go/no-go before any work (mostly INTERNET-permission calls)**
|
||||||
- Remote calendar create/edit (re-implements DAVx5; INTERNET + credential storage)
|
- Remote calendar create/edit (re-implements DAVx5; INTERNET + credential storage)
|
||||||
@@ -263,11 +275,13 @@ pass on the existing controls; new toggles ride in with their own features.
|
|||||||
2026-06-17; cheap but low value, pick up only if asked
|
2026-06-17; cheap but low value, pick up only if asked
|
||||||
|
|
||||||
**Unranked / fill-in** — pinch-to-zoom time scale, tablet/foldable layouts,
|
**Unranked / fill-in** — pinch-to-zoom time scale, tablet/foldable layouts,
|
||||||
full-text search, ICS file import. Pulled in opportunistically, not sequenced.
|
full-text search. Pulled in opportunistically, not sequenced.
|
||||||
|
|
||||||
Debatable calls worth a second look: whether **local-calendar backup (#10)**
|
Tier 4 is now fully shipped (#9 reminders defaults v2.6.0, #10 `.ics`
|
||||||
should lead Tier 4 outright (it's a silent data-loss risk, not a feature);
|
export/import v2.7.0, #11 snooze/dismiss in release/v2.8.0; drag-drop rejected).
|
||||||
whether drag-drop (#12) jumps ahead given its daily-driver impact.
|
**Next committed work is Tier 5 #12 — attendee editing** (the last read-only gap
|
||||||
|
in the event model). After it: the theme-group ideas and Tier 2/3 leftovers
|
||||||
|
(quick-settings tile, now-line, week numbers in month, full-text search).
|
||||||
|
|
||||||
## Navigation & views
|
## Navigation & views
|
||||||
|
|
||||||
@@ -288,8 +302,6 @@ whether drag-drop (#12) jumps ahead given its daily-driver impact.
|
|||||||
|
|
||||||
## Event editing & creation
|
## Event editing & creation
|
||||||
|
|
||||||
- Drag & drop rescheduling in day/week (recurring drops reuse the scope
|
|
||||||
dialog) — big-ticket, own slice
|
|
||||||
- Duplicate event (detail action → prefilled create form)
|
- Duplicate event (detail action → prefilled create form)
|
||||||
- **Per-event color** (`Events.EVENT_COLOR`, OptionCard picker in the form)
|
- **Per-event color** (`Events.EVENT_COLOR`, OptionCard picker in the form)
|
||||||
*(next)* — chosen to follow the in-progress tap-to-create + calendar
|
*(next)* — chosen to follow the in-progress tap-to-create + calendar
|
||||||
@@ -319,13 +331,11 @@ whether drag-drop (#12) jumps ahead given its daily-driver impact.
|
|||||||
go/no-go gate as the OSM/INTERNET item below.
|
go/no-go gate as the OSM/INTERNET item below.
|
||||||
- Move event to another calendar (copy+delete model with a consequences
|
- Move event to another calendar (copy+delete model with a consequences
|
||||||
warning — deferred from v2.0; `CALENDAR_ID` is sync-adapter-owned) *(was v3.0)*
|
warning — deferred from v2.0; `CALENDAR_ID` is sync-adapter-owned) *(was v3.0)*
|
||||||
- **Local-calendar backup / export** *(Tier 4 #10)* — device-only
|
- ~~**Local-calendar backup / export** *(Tier 4 #10)*~~ **shipped v2.7.0** —
|
||||||
(`ACCOUNT_TYPE_LOCAL`) calendars are first-class in Calendula but have **no
|
device-only (`ACCOUNT_TYPE_LOCAL`) calendars had no sync and therefore no
|
||||||
sync and therefore no backup**: a lost/wiped phone destroys them permanently.
|
backup. Settings → Calendars → Export writes every event to a user-chosen
|
||||||
Whole-calendar `.ics` (VCALENDAR) export to a user-chosen file (SAF), plus
|
`.ics` file (SAF); restore is the bulk-import path (pick a calendar, dedup by
|
||||||
restore-on-import that recreates events into a chosen local calendar. Reuses
|
UID). Closed the silent data-loss gap.
|
||||||
the .ics serializer from the single-event share work; the restore path reuses
|
|
||||||
the import parser. A data-integrity obligation, not a feature.
|
|
||||||
|
|
||||||
## Reminders — defaults & delivery reliability *(implemented 2026-06-17, `feat/default-reminders` — pending on-device review)*
|
## Reminders — defaults & delivery reliability *(implemented 2026-06-17, `feat/default-reminders` — pending on-device review)*
|
||||||
|
|
||||||
@@ -419,9 +429,11 @@ it directly undermines the feature's premise, so it rides in here.
|
|||||||
|
|
||||||
## Sharing & interop
|
## Sharing & interop
|
||||||
|
|
||||||
- Share event as .ics + open/receive .ics into a prefilled create form
|
- ~~Share event as .ics + open/receive .ics into a prefilled create form~~
|
||||||
(front-runs the import below)
|
**shipped v2.7.0** — single-event share from detail; opening an `.ics` with one
|
||||||
- ICS file import (drag-and-drop) *(was v3.0, optional)*
|
event prefills the create form, many events opens a bulk import (dedup by UID)
|
||||||
|
- ~~ICS file import~~ **shipped v2.7.0** — covered by the open/receive `.ics`
|
||||||
|
flow above (single → form, many → bulk import)
|
||||||
|
|
||||||
## Platform & launchers
|
## Platform & launchers
|
||||||
|
|
||||||
@@ -455,9 +467,37 @@ in detail yet:
|
|||||||
trade-off is an explicit go/no-go decision before any work starts.
|
trade-off is an explicit go/no-go decision before any work starts.
|
||||||
- **Inline contact suggestions** while typing (needs READ_CONTACTS) — only
|
- **Inline contact suggestions** while typing (needs READ_CONTACTS) — only
|
||||||
if the picker proves clunky.
|
if the picker proves clunky.
|
||||||
- **Attendee editing / invites from contacts** — own milestone; writing
|
- **Attendee editing** *(promoted out of this gated bucket 2026-06-22 — now
|
||||||
`Attendees` rows touches sync-adapter invitation behavior (Google vs
|
Tier 5 #12, high-importance; the no-permission typed-email path is not an
|
||||||
DAVx5 differ).
|
INTERNET/contacts call)*. See the "Attendee editing" sketch below.
|
||||||
|
|
||||||
|
### Attendee editing *(Tier 5 #12, opened 2026-06-22)*
|
||||||
|
|
||||||
|
The last read-only gap in the event model: attendees are read & shown on the
|
||||||
|
detail screen (since v0.6) but the form can't write them. Make guests editable.
|
||||||
|
|
||||||
|
- **Read side already done:** `Attendee` domain model + status/relationship/type
|
||||||
|
enums, `queryAttendees` + `EventDetailMapper.toAttendee` (with tests), and the
|
||||||
|
attendees `DetailCard` + `AttendeeRow` in `EventDetailScreen`. Nothing to add
|
||||||
|
there.
|
||||||
|
- **Write side (new):** add `attendees` to `EventForm` and an attendees section
|
||||||
|
to `EventEditScreen` — add a guest by typed email (+ optional display name),
|
||||||
|
remove rows, set role (required / optional). Persist by diffing against the
|
||||||
|
provider's `CalendarContract.Attendees` rows on insert + dirty-checked update,
|
||||||
|
mirroring the reminders-diff (kept rows keep their fields). Organizer/self rows
|
||||||
|
are not user-editable.
|
||||||
|
- **No new permission for the typed-email path** — writing `Attendees` needs only
|
||||||
|
the existing `WRITE_CALENDAR`. A contact-picker entry (`ACTION_PICK` on emails,
|
||||||
|
one-shot, no READ_CONTACTS) can follow as a convenience, reusing the address-
|
||||||
|
picker mechanism above.
|
||||||
|
- **Sync-adapter caveat — decide before building:** writing `Attendees` rows
|
||||||
|
triggers backend-specific *invitation* behavior. Google's provider may auto-mail
|
||||||
|
invites; CalDAV/DAVx5 writes the `ATTENDEE` property and leaves delivery to the
|
||||||
|
server. Calendula sends nothing itself (no INTERNET), so what actually reaches a
|
||||||
|
guest depends entirely on the sync adapter. Settle and document the honest
|
||||||
|
promise (and any "your account may email this guest" copy) up front.
|
||||||
|
- **Out of scope (for now):** RSVP/your-own-response editing, free/busy lookups,
|
||||||
|
resource booking — all carry server round-trips or richer sync semantics.
|
||||||
|
|
||||||
## Consciously rejected
|
## Consciously rejected
|
||||||
|
|
||||||
@@ -465,3 +505,5 @@ in detail yet:
|
|||||||
- Natural-language quick entry (high effort, locale-fragile; the prefilled
|
- Natural-language quick entry (high effort, locale-fragile; the prefilled
|
||||||
form already covers fast entry)
|
form already covers fast entry)
|
||||||
- Quick-add sheet (the prefilled full form already covers it — cut in v2.0)
|
- Quick-add sheet (the prefilled full form already covers it — cut in v2.0)
|
||||||
|
- Drag & drop rescheduling in day/week — **rejected** (owner decision,
|
||||||
|
reaffirmed 2026-06-22): not wanted. Rescheduling stays via the edit form.
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
# Calendula — Current State
|
# Calendula — Current State
|
||||||
|
|
||||||
*Last updated: 2026-06-17*
|
*Last updated: 2026-06-22*
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
**Milestone:** 2 (write support) **complete** — v2.0.0 shipped 2026-06-11;
|
**Milestone:** 2 (write support) **complete** — v2.0.0 shipped 2026-06-11.
|
||||||
v2.1.0 (month event grid, drawer view tabs, cursor fix) shipped 2026-06-15.
|
**Phase:** post-2.x theme-based backlog work (organised in `ROADMAP.md`).
|
||||||
**Phase:** post-2.1 backlog work. v2.2.0 (tap-to-create in day/week + local
|
**Latest released tag: v2.7.5.** The whole Tier 4 (reliability/data-safety/
|
||||||
calendar management) and v2.3.0 (Material 3 grouped-list redesign of Settings,
|
interop) arc is now done or in flight:
|
||||||
the calendar manager and the navigation drawer) both shipped 2026-06-16;
|
- v2.4.0 per-event colors (2026-06-17)
|
||||||
v2.4.0 (per-event colors) and v2.5.0 (jump-to-date, Agenda view, home-screen
|
- v2.5.0 jump-to-date, Agenda view, agenda + month home-screen widgets, "New
|
||||||
agenda + month widgets, and a "New event" launcher shortcut) shipped
|
event" launcher shortcut (2026-06-17)
|
||||||
2026-06-17. The backlog is now organised by theme in `ROADMAP.md`.
|
- v2.6.0 default reminders (global + per-calendar override, all-day default,
|
||||||
|
battery-exemption row) + system per-app language (2026-06-18)
|
||||||
|
- v2.7.0 **`.ics` engine** — single-event share, local-calendar backup export,
|
||||||
|
open/receive `.ics` (single → form, many → bulk import, dedup by UID)
|
||||||
|
(2026-06-18)
|
||||||
|
- v2.7.1–v2.7.5 — crash-reporting + F-Droid reproducible-build hardening + fixes
|
||||||
|
|
||||||
|
**Next release `release/v2.8.0` (integration branch, not yet cut to main):**
|
||||||
|
holds crash reports via the public Codeberg tracker (MR !27) + reminder
|
||||||
|
snooze/dismiss notification actions (MR !28). Version bump to 2.8.0 happens at
|
||||||
|
release-cut.
|
||||||
|
|
||||||
## Progress
|
## Progress
|
||||||
|
|
||||||
@@ -120,11 +130,47 @@ agenda + month widgets, and a "New event" launcher shortcut) shipped
|
|||||||
sync" warning on the picker and in Settings. Color writes flow through
|
sync" warning on the picker and in Settings. Color writes flow through
|
||||||
insert / dirty-checked update / occurrence-exception; mapper + form tests.
|
insert / dirty-checked update / occurrence-exception; mapper + form tests.
|
||||||
|
|
||||||
|
- [x] v2.5 (shipped 2026-06-17) — Agenda view (4th top-level view),
|
||||||
|
jump-to-date drawer date picker, two home-screen widgets (scrolling
|
||||||
|
"Upcoming" agenda + month grid), and a "New event" launcher long-press
|
||||||
|
shortcut
|
||||||
|
|
||||||
|
- [x] v2.6 (shipped 2026-06-18) — default reminders: global timed default +
|
||||||
|
separate all-day default + per-calendar override (timed), applied on create
|
||||||
|
with dirty-flag handling; three pickers + override list in Settings →
|
||||||
|
Notifications; battery-optimisation exemption row (status + system deep-link,
|
||||||
|
no new permission). Plus system per-app language (Android 13+) and an
|
||||||
|
immediate-effect fix for the in-app language picker
|
||||||
|
|
||||||
|
- [x] v2.7 (shipped 2026-06-18) — the `.ics` engine: share a single event as
|
||||||
|
`.ics` from the detail screen; back up local calendars (Settings → Calendars
|
||||||
|
→ Export) to a SAF file; open/receive an `.ics` — one event prefills the
|
||||||
|
create form, many events open a bulk import into a chosen calendar (dedup by
|
||||||
|
UID, skip-and-report unrepresentable VTIMEZONE / RECURRENCE-ID / guests).
|
||||||
|
Hand-rolled serializer/parser, zero deps. Plus all-day single-day UTC fix and
|
||||||
|
a widget R8 keep-rule crash fix
|
||||||
|
|
||||||
|
- [x] v2.7.1–v2.7.5 (2026-06-21) — launch crash fix (listener before grant),
|
||||||
|
user-controlled crash reporting, widget loading-spinner R8 keep rule, and
|
||||||
|
F-Droid reproducible-build cleanups for the official repo
|
||||||
|
|
||||||
|
- [~] release/v2.8.0 (not yet cut) — crash reports via the public Codeberg
|
||||||
|
tracker (MR !27) + reminder snooze/dismiss notification actions (MR !28,
|
||||||
|
snooze self-schedules an exact alarm; primary delivery stays provider-broadcast)
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
1. Monitor the F-Droid build/publish for the v2.4.0 tag
|
1. Cut **v2.8.0** from `release/v2.8.0` (bump versionName → tag via the
|
||||||
2. Decide the "Locations & People" and "remote calendar create/edit"
|
merge-driven pipeline) once on-device review signs off
|
||||||
go/no-go calls (both hinge on the INTERNET permission) — see `ROADMAP.md`
|
2. **Attendee editing** — the committed next feature (Tier 5 #12, high-
|
||||||
3. **Duplicate event** and **jump-to-date** are the cheap follow-ups; then
|
importance, opened 2026-06-22). Attendees are already read & shown on the
|
||||||
agenda view (strategic, backs a future widget). Full ranked sequence in
|
detail screen since v0.6; the gap is the write side — make guests editable
|
||||||
`ROADMAP.md` → "Near-term sequence".
|
in `EventEditScreen` / `EventForm` (add by typed email, role, remove),
|
||||||
|
persisted by diffing `CalendarContract.Attendees`. No new permission for the
|
||||||
|
typed-email path. **Resolve first:** the backend-specific invitation/sync
|
||||||
|
behavior (Google auto-mails invites, CalDAV writes `ATTENDEE`) — decide and
|
||||||
|
document the honest promise. Full sketch in `ROADMAP.md` → "Attendee editing".
|
||||||
|
3. Then: the two INTERNET go/no-go calls (OSM autocomplete, remote calendar
|
||||||
|
create/edit) and Tier 2/3 leftovers (quick-settings tile, now-line, week
|
||||||
|
numbers in month, full-text search, accessibility pass). Drag-and-drop
|
||||||
|
rescheduling is **rejected**.
|
||||||
|
|||||||
Reference in New Issue
Block a user