Commit Graph

11 Commits

Author SHA1 Message Date
Jean-Luc Makiola
d03985eada Release 2.19.2 (#216)
All checks were successful
Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 7s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Successful in 16m50s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Successful in 1m34s
Release 2.19.2 — `versionName` 2.19.2 / `versionCode` 21902. Merging this cuts the release.

A meeting you declined is struck through everywhere it appears and no longer schedules a reminder (#180). Tapping an event in month view opens the event instead of its day, in every month style (#187). An edit shows immediately when the same occurrence is re-opened (#196).

The month widget's arrows died after a couple of taps: the grid serialised ~740 views and one update ran to 450–540 KB, which overran the launcher's async binder buffer and made Android drop the whole widget host — killing updates for every widget on the home screen. The grid is down to 192 views, and `SizeMode.Exact` is kept so a resized widget reflows instead of clipping (#214). Widget taps now redraw the tapped widget by its own id rather than `updateAll`, whose provider lookup is empty in a cold-woken process (#18).

Jump-to-today in seamless weeks lands on the current week row (#191), and the day and week timelines got an end inset (#192).

Two follow-ups beyond the issues: the detail re-read keeps the loaded content on screen instead of blinking back to the skeleton, and a month chip tap with no recorded touch down (TalkBack, D-pad) no longer resolves to the previous tap's chip.

Release notes: `CHANGELOG.md` 2.19.2 section and `fastlane/metadata/android/en-US/changelogs/21902.txt` (471 chars).

Closes #18
Closes #180
Closes #187
Closes #191
Closes #192
Closes #196
Closes #214

Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/216
2026-08-17 21:54:46 +02:00
Jean-Luc Makiola
93b9aa8f34 2.19.0 — drag to reschedule, bulk delete from search, onboarding wizard (#172)
All checks were successful
Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 12s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Successful in 14m58s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Successful in 1m2s
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/172
2026-08-10 18:40:55 +02:00
Jean-Luc Makiola
e8657117d6 2.17.0: reminders Calendula delivers itself, one visibility model, and a Settings you can navigate (#108)
Some checks failed
Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 8s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Failing after 6m29s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Has been skipped
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/108
2026-07-30 22:14:57 +02:00
9f7e93d5f8 fix(contacts): seal managed calendars off from user edits
Managed special-dates calendars were only recognised by an id cached in
preferences, and were offered as ordinary write targets — so a user could
create an event in 'Birthdays' (which the next sync then deleted), and after
a backup restore wiped the prefs the editor lock silently disappeared.

CalendarSource now carries isManaged, read from the durable CAL_SYNC2 marker
the data layer already stamps, so identity survives a restore. With it:
- the new-event calendar picker excludes managed calendars (no user events
  land in a calendar the sync owns);
- the editor lock keys off the marker, not a stored id;
- a managed event's save is forced to the whole series instead of parking in
  the scope dialog (a 'this/following' split creates rows the sync reverts);
- the detail sheet hides Delete for managed events (the sync would just
  resurrect them — a contact date is removed at its source).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:03:33 +02:00
e1cf00999d feat(views): optionally dim or hide past events
Adds two independent display settings under Settings › Appearance, both
defaulting to the current behaviour (off) so nothing changes until a user
opts in:

  • Agenda › "Past events" (Show / Dim / Hide) — events that already ended
    today can be left as-is, faded, or dropped from the list. Hiding also
    removes any day left empty, falling back to the empty state. Re-evaluated
    each minute so rows fade/fall away as they end while the screen is open.

  • Calendar › "Dim completed events" — a separate toggle that fades finished
    events in the month and week grids, kept independent of the agenda setting.

An event counts as completed once its end is at or before now (in-progress
events are never dimmed; all-day events only after their day is fully over),
via a shared EventInstance.hasEnded(now). The grids read the cut-off through
a new LocalDimCutoff CompositionLocal (mirroring LocalShowHourLines) so only
the event chips recompose on the per-minute tick, and only while dimming is on.

Also adds an "Agenda" section header so the agenda rows stand apart in the
now-busier Appearance screen, and documents the feature in the changelog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 21:48:19 +02:00
b62f097392 release: cut v2.4.0 — per-event colors
All checks were successful
CI / ci (push) Successful in 9m20s
Release — F-Droid repo + Gitea release / ci (push) Successful in 2m3s
Release — F-Droid repo + Gitea release / build-and-deploy (push) Successful in 9m22s
Release — F-Droid repo + Gitea release / gitea-release (push) Successful in 7s
Optional per-event color in the event form. The read/render path already
resolved EVENT_COLOR with a calendar fallback; this adds the write side and
the picker.

- Palette-backed calendars (Google, some CalDAV) pick from the account's
  Colors (TYPE_EVENT) and write EVENT_COLOR_KEY, so the color round-trips
  through sync; local calendars write a raw EVENT_COLOR from the shared
  CALENDAR_COLOR_PALETTE. Never writes a raw color to a palette calendar.
- Swatch row + palette extracted to ui/common/ColorSwatchRow.kt (shared with
  the calendar editor). Switching calendars resets the choice (keys are
  account-scoped); a "Reset" action returns to the calendar color.
- New "Allow colors on unsupported calendars" setting (off by default)
  extends the raw path to no-palette synced calendars, with an honest
  "may not survive sync" warning on the picker and in Settings.
- Color flows through insert / dirty-checked update / occurrence-exception;
  mapper, form, and repository tests added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 08:55:16 +02:00
e194da3766 release: cut v2.2.0 — tap-to-create + local calendar management
All checks were successful
CI / ci (push) Successful in 8m53s
Release — F-Droid repo + Gitea release / ci (push) Successful in 1m59s
Release — F-Droid repo + Gitea release / build-and-deploy (push) Successful in 8m57s
Release — F-Droid repo + Gitea release / gitea-release (push) Successful in 8s
Day/week: tap an empty slot to open the create form prefilled with that
day and the tapped hour (snapped to the hour, 1 h long). Threaded a start
time through CalendarHost → EventEditScreen → openNew; the FAB keeps its
default.

Local calendars: a full-screen editor from Settings → Calendars to
create/rename/recolor/delete device-only calendars (ACCOUNT_TYPE_LOCAL,
sync-adapter insert) with name, pastel-previewed colour, and a description
(stored in CAL_SYNC1). Synced calendars are listed read-only grouped by
account, each with a "manage in source app" deep-link resolved from the
account's own authenticator (DAVx5/ICSx5/…), plus an add-account shortcut;
a <queries> block makes the source apps launchable. Extracted a shared
InlineTextField into ui.common so the event form and calendar editor share
one borderless input style.

Tests: repository delegation + write-failure, mapper isLocal/description,
fake data source extended. Version bumped to 2.2.0 / 20200.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 09:49:14 +02:00
f0e2e12939 feat(edit): event editing — shared form, scoped recurring writes, recurrence picker (v1.3)
The create form (v1.2) now edits: a pencil on the detail screen (writable
calendars only, contextual WRITE upgrade like delete) opens it prefilled via
EventDetail.toEditForm; populated sections always show, the calendar is
fixed, and a dirty-check writes only changed columns (pristine saves are
no-ops). Saving a dirty recurring event parks in SaveUiState.AwaitingScope
and asks how far the change reaches (Google model): "only this event" =
modified-occurrence exception via CONTENT_EXCEPTION_URI (empty optionals as
explicit NULLs since the provider clones the parent row), "this and all
following" = series split (insert new event first, then truncate), "all
events" = series-row update with the time delta applied to the series
DTSTART. A changed rule drops the exception option. Delete gained the same
middle scope.

Recurrence: EventForm.rrule + SimpleRecurrence (FREQ/INTERVAL/UNTIL/COUNT +
weekly BYDAY with locale-ordered weekday toggles) behind a picker on create
and edit; unrepresentable rules render humanized (shared ui/common
RecurrenceText) and survive verbatim. UNTIL validation flags rules ending
before the event starts.

Provider lessons baked in (verified on-device via adb probes): instance
caches regenerate only from an update's own values, so truncation sends the
full time-column set (truncateSeries) — RRULE-only updates left a stale
duplicate occurrence on the split day; UNTIL is written as the local end of
day in UTC (toRRule(zone), previousLocalDayEndUtcMillis) so UTC+x zones
can't leak an extra day. Reminder edits reconcile against actual provider
rows, keeping untouched rows' methods.

Tests: RecurrenceTest (parse/render/round-trip, truncation), update/exception
mapper paths, repository pass-throughs, prefill + populatedFields, raw-title
mapper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 20:57:32 +02:00
9529f19c60 feat(write): event delete + WRITE_CALENDAR foundation (v1.1)
First slice of milestone 2 (write support), per the new plan in
docs/superpowers/plans/2026-06-11-03-write-support.md:

- Delete from the event detail screen with confirmation; recurring events
  choose "only this event" (cancelled exception via CONTENT_EXCEPTION_URI,
  series survives) or "all events in the series" (Events-row delete)
- WRITE_CALENDAR in the manifest; onboarding requests read+write in one
  system dialog but only read gates the app — declining write keeps it
  usable read-only. v1.0 installs get a contextual write request on their
  first delete
- CALENDAR_ACCESS_LEVEL is read into CalendarSource.canModifyContents;
  read-only calendars (WebCal, birthdays, …) show no write actions. The
  no-op placeholder Edit button is removed until edit ships (v1.3)
- Onboarding copy drops the now-false "read-only" claim (DE+EN)
- Tests: repository delete delegation/error propagation, access-level
  mapping; FakeCalendarDataSource grows write ops

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 12:55:15 +02:00
024512959f feat(detail): full event read — surface every readable field (v0.6.0)
Round out the read-only model so the detail view shows everything
CalendarContract actually stores, ahead of write support.

Data layer:
- New domain types: Reminder, EventStatus, Availability, AccessLevel,
  AttendeeRelationship, AttendeeType; EventDetail gains reminders, status,
  availability, accessLevel, eventTimezone, selfStatus and Attendee gains
  relationship + type (all defaulted so existing callers compile)
- EventDetailProjection reads STATUS / AVAILABILITY / ACCESS_LEVEL /
  EVENT_TIMEZONE / SELF_ATTENDEE_STATUS; AttendeeProjection reads
  RELATIONSHIP + TYPE; new ReminderProjection queries CalendarContract.Reminders
- Mappers translate each provider integer code, guarding STATUS's null-vs-0
  ambiguity (0 == TENTATIVE) so an absent status reads as Confirmed
- Mapper unit tests cover every new column's codes

Detail UI:
- Status / availability / access chips under the title; cancelled also strikes
  the title through
- Reminders card with humanised lead times (plurals, DE + EN)
- Foreign-timezone card, shown only for timed events in a non-device zone
- Attendee role badges + the user's own "Your response: …" line
- http(s) URLs in the description are now tappable

URL field cut: CalendarContract exposes no Events.URL column (only the
CUSTOM_APP_URI app deep-link), so URLs are surfaced by linkifying the
description instead. Recorded in ROADMAP/CHANGELOG.

Version bumped to 0.6.0 / 6.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 08:56:40 +02:00
af75965a31 domain: add pure-Kotlin models (CalendarSource, EventInstance, EventDetail, …) 2026-06-08 17:36:39 +02:00