Jean-Luc Makiola b03bd67678 feat(reminders): reminder notifications — EVENT_REMINDER receiver, onboarding step, settings toggle (v1.4)
Calendula now posts event reminders itself (the Etar model): the provider
schedules the alarms and broadcasts EVENT_REMINDER, but a calendar app must
turn them into visible notifications — essential for users whose only
calendar app this is. A manifest-registered, exported receiver (data scheme
content://com.android.calendar) wakes us at reminder time; no foreground
service, no own alarm scheduling.

Delivery path (data/reminders/): EventReminderReceiver (Hilt, goAsync) →
ReminderAlertStore queries CalendarAlerts for STATE_SCHEDULED rows with
ALARM_TIME <= now → ReminderNotifier posts one notification per alert on a
dedicated high-importance channel, then best-effort marks rows FIRED
(needs WRITE_CALENDAR; without it a re-broadcast silently replaces — tag
per alert + setOnlyAlertOnce). Swiped notifications never return: FIRED
rows are never re-queried, so no dismiss-intent machinery. Research
(AOSP CalendarAlarmManager): the provider creates alert rows only for
METHOD_ALERT reminders, so the email-reminder filter happens upstream.

Tapping opens the event's detail screen: MainActivity is singleTop now,
parses eventId/begin/end extras (onCreate + onNewIntent) into Compose
state, and CalendarHost consumes the key exactly like an event tap.

Onboarding gained a one-time second step after the calendar grant (shared
OnboardingScaffold extracted from PermissionScreen): explains delivery,
warns that a second calendar app with notifications on duplicates
reminders, requests POST_NOTIFICATIONS (dialog on API 33+ only; minSdk 29).
"Not now" turns the feature off; reminders default ON. Settings mirrors
the toggle in a new Notifications section with the duplicate hint, and
re-requests the permission when enabling. Strings DE+EN.

Deliberately deferred (roadmap): snooze/dismiss actions, BOOT_COMPLETED /
exact-alarm scheduling, battery-exemption prompts.

Tests: reminderTimeText (all-day UTC-midnight reading, exclusive end day,
midnight-crossing ranges), reminders/onboarding pref round-trips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 21:23:34 +02:00

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 (V1)

  • Month, Week, and Day views
  • Read-only event details (write support comes in V2)
  • 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:

# 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:

JAVA_HOME=/path/to/jdk-17 ./gradlew assembleDebug

License

MIT — Jean-Luc Makiola, 2026

Description
A modern Material 3 Expressive calendar app for Android
Readme MIT 3.1 MiB
v2.7.0 Latest
2026-06-18 14:24:35 +00:00
Languages
Kotlin 99.6%
Python 0.4%