Release v2.19.4.
**Fixed**
- A deleted occurrence stays deleted through a series re-timing, and through backup/restore ([#225]).
- "Only this event" saves the edit on calendars that never synced, and on a row that doesn't recur it edits or deletes the event itself instead of filing an exception against nothing.
- A reminder left on the account's default is no longer read as a lead time of Calendula's own.
- The widgets turn the page at midnight; the re-arm backstop for the inexact rollover alarm is back, throttled to once per 15 minutes on calendar changes.
- An event running past midnight can be dragged by either half ([#253]).
- One event the provider refuses no longer costs the rest of the import, and an import cut short reports honestly how far it got.
- EXDATE zone prefixes are read in the bare `<zone>;` form the provider and DAVx5 actually write, not only the iCalendar `TZID=` spelling; a list holding a stamp we can't parse is kept whole rather than re-emitted stripped of its zone; RDATE travels with RRULE when the recurrence set is rewritten.
**Added**
- Belarusian, Hungarian and Slovak, from community translators on Weblate.
**Changed**
- Arabic, Polish and Simplified Chinese are complete; Czech grew, and Russian is now at about half.
Bumps `versionName` to 2.19.4, so merging this triggers the release pipeline.
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/259
Every write sampled ZoneId.systemDefault() and stamped it into
EVENT_TIMEZONE, so the column was real but only ever held the device's
zone: an event synced from elsewhere could be read in its zone, never
authored in one.
Give EventForm a nullable `timezone`, where null keeps meaning "the
device zone at save time" — so every existing call site behaves exactly
as before — and a non-null value pins the event to a zone it then tracks
across DST. toWriteTimes resolves the form's zone ahead of the device's;
toEditForm pins only when the stored zone differs from the device's, and
prefills such an event in its own zone so the form shows the wall-clock
the event actually means.
Two provider-contract bugs fall out of this:
- Editing the time of a foreign-zone event rewrote EVENT_TIMEZONE to the
device's. The instants stayed right, so nothing looked wrong, but the
event silently stopped tracking its zone and would drift an hour at the
next DST boundary. Only the timesChanged gate spared title-only edits.
- A zone change with an untouched wall-clock is still a time change (the
same 09:00 elsewhere is a different instant), so it now trips
timesChanged and rewrites DTSTART instead of being dropped.
All-day events keep carrying no zone at all: they're date-anchored, and
the UTC midnights they normalise to are an anchor rather than a location.
TimeZoneCatalog is pure JVM so the search ranking and DST-aware offsets
stay plain JUnit tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Documentation pass after the 2.0 milestone:
- docs/ARCHITECTURE.md — principles (provider as single source of truth,
observer-driven UI, JVM-first tests, no network), layer + reminder
mermaid diagrams, navigation (overlay/held-key, no nav lib), and the
provider lessons (recurring-write invariants, conflict snapshots)
- docs/README.md — map of what documentation lives where, incl. the
convention that superpowers/ plans are historical artifacts while
.planning/ stays current
- README.md — showcase layout (centered header, badges, screenshot
gallery from the fastlane assets, grouped features, install/build/
architecture/roadmap sections); renders on Gitea
- .planning/{PROJECT,REQUIREMENTS,STATE}.md unstaled: read-only-V1 talk
removed, V1/V2 checklists marked shipped, state points at v3 + the
Locations & People go/no-go
release.yaml gains a gitea-release job: on every tag push it extracts the
tag's CHANGELOG section and creates a Gitea release with it as the notes.
No APK assets — distribution stays with the F-Droid repo. Idempotent
(skips an existing release), gated on the test job only so notes appear
even when the F-Droid upload hiccups.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>