No locking (plan 03, decision 5): openForEdit keeps an EditSnapshot — the prefilled form plus the raw Events-row times, which the form itself can't see (it derives its times from the tapped occurrence, so an externally moved event would otherwise stay invisible). Right before writing, performSave re-reads the event and compares snapshots: a mismatch parks the save in SaveUiState.AwaitingConflict carrying the already-chosen recurring scope, and the dialog offers overwrite / discard / cancel (OptionCard style). Overwrite still writes only dirty fields, so external changes to untouched fields survive either way. A deleted event lands in SaveUiState.Gone — an informational dialog that closes form and detail. Fields the form can't write (attendees, status, self response, reminder methods) are excluded from the comparison so sync noise can't fake a conflict. The load-time zone is pinned in the EditTarget so a device timezone change mid-edit can't either. Store metadata: F-Droid descriptions (DE+EN) and the README stop claiming read-only and now describe write support and reminder delivery. New fastlane phoneScreenshots (6 per locale: week/month/day/detail/form/ reminder onboarding), captured on-device against demo-only calendars. Tests: EditSnapshot equality (unchanged event, field change, row-time move the form can't see, non-writable changes stay quiet). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
48 lines
1.3 KiB
Markdown
48 lines
1.3 KiB
Markdown
# Calendula
|
|
|
|
A modern Material 3 Expressive calendar app for Android.
|
|
|
|
Calendula is named after the flower of the same name, whose name comes from
|
|
the Latin *kalendae* — the first day of the month — the same root as the
|
|
word "calendar". Calendula reads from Android's built-in `CalendarContract`,
|
|
so any calendar source synced to your device (CalDAV via DAVx5, Google,
|
|
local, WebCal subscriptions, ...) is shown.
|
|
|
|
## Features
|
|
|
|
- Month, Week, and Day views
|
|
- Full event details — attendees, reminders, recurrence, availability, and more
|
|
- Create, edit, and delete events — recurring events with scoped writes
|
|
(only this event / this and all following / whole series) and a simple
|
|
recurrence picker
|
|
- Reminder notifications, delivered by Calendula itself (tap opens the event)
|
|
- Multi-calendar visibility toggle
|
|
- Material You Dynamic Color (Android 12+)
|
|
- Light/Dark theme follows system
|
|
- German + English UI
|
|
|
|
## Building
|
|
|
|
Requires Android SDK 36 and JDK 17. The Gradle wrapper is checked in, so no host Gradle install is needed:
|
|
|
|
```bash
|
|
# Build debug APK
|
|
./gradlew assembleDebug
|
|
|
|
# Run unit tests
|
|
./gradlew test
|
|
|
|
# Run lint
|
|
./gradlew lint
|
|
```
|
|
|
|
If your default JDK is something other than 17, set `JAVA_HOME` explicitly:
|
|
|
|
```bash
|
|
JAVA_HOME=/path/to/jdk-17 ./gradlew assembleDebug
|
|
```
|
|
|
|
## License
|
|
|
|
[MIT](LICENSE) — Jean-Luc Makiola, 2026
|