From 9e28fa4981d7f04fb8afbae93bf4f19a3067cc26 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Fri, 24 Jul 2026 17:37:59 +0200 Subject: [PATCH 1/2] fix(intents): accept item-typed INSERT / INSERT_OR_EDIT for "Add to calendar" (#74) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other apps' "Add to calendar" / "Save to calendar" actions commonly fire the canonical insert intent — ACTION_INSERT with setType("vnd.android.cursor.item/ event") — the singular *item* MIME type (Android's own docs example; used by e.g. DB Navigator). Calendula advertised INSERT only on the *dir* MIME type, so it never matched: absent from the chooser, and a silent no-op when it was the only calendar app installed. Add the item-typed INSERT to the events filter, plus ACTION_INSERT_OR_EDIT (the third "add to calendar" action AOSP and Google Calendar register). The runtime parser already treats any ACTION_INSERT as create; teach insertFormOrNull / editEventKeyOrNull about INSERT_OR_EDIT so an id-less one is a create and an id-carrying one opens the edit form. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 7 ++++ app/src/main/AndroidManifest.xml | 37 ++++++++++++++----- .../jeanlucmakiola/calendula/MainActivity.kt | 13 ++++--- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49f8808..8aafac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Now a bigger widget gets bigger, more readable type and roomier rows, while the default size looks exactly as before — no new setting; it follows the size you already chose ([#51]). +- Calendula now appears under other apps' "Add to calendar" / "Save to calendar" + actions. Some apps (e.g. DB Navigator) fire the widely-used "insert event" + intent with the singular `vnd.android.cursor.item/event` type, which Calendula + didn't advertise — so it was left out of the chooser, and if it was your only + calendar app the save silently did nothing. It now accepts that form, plus the + `INSERT_OR_EDIT` action, and opens the new event prefilled for review ([#74]). ## [2.16.0] — 2026-07-17 @@ -1079,3 +1085,4 @@ automatically, with zero telemetry and no internet permission. [#53]: https://codeberg.org/jlmakiola/calendula/issues/53 [#60]: https://codeberg.org/jlmakiola/calendula/issues/60 [#65]: https://codeberg.org/jlmakiola/calendula/issues/65 +[#74]: https://codeberg.org/jlmakiola/calendula/issues/74 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7f73919..3de3eac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -123,11 +123,13 @@ + to the same prefilled create form. (The far more common *item*- + typed INSERT — the form the Android docs' example and apps like + DB Navigator use — is the item filter below, issue #74.) --> @@ -135,14 +137,31 @@ - + + + diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/MainActivity.kt b/app/src/main/java/de/jeanlucmakiola/calendula/MainActivity.kt index 1177165..0a0c20f 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/MainActivity.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/MainActivity.kt @@ -222,10 +222,12 @@ class MainActivity : AppCompatActivity() { * [buildInsertEventForm]. */ private fun Intent.insertFormOrNull(): EventForm? { - // ACTION_EDIT on an existing event routes to the edit form instead - // ([editEventKeyOrNull]); only an id-less EDIT is a create. + // ACTION_EDIT / ACTION_INSERT_OR_EDIT on an existing event route to the + // edit form instead ([editEventKeyOrNull]); an id-less one is a create, + // as is any plain ACTION_INSERT. val isCreate = action == Intent.ACTION_INSERT || - (action == Intent.ACTION_EDIT && editEventKeyOrNull() == null) + ((action == Intent.ACTION_EDIT || action == Intent.ACTION_INSERT_OR_EDIT) && + editEventKeyOrNull() == null) if (!isCreate) return null return buildInsertEventForm( beginMillis = longExtraOrNull(CalendarContract.EXTRA_EVENT_BEGIN_TIME), @@ -344,10 +346,11 @@ class MainActivity : AppCompatActivity() { * occurrence's times as `EXTRA_EVENT_BEGIN_TIME` / `EXTRA_EVENT_END_TIME` * when it has them, otherwise we carry [NO_OCCURRENCE_TIME] and * [EventEditViewModel.openForEdit] falls back to the event row's own - * DTSTART/DTEND. An id-less `ACTION_EDIT` is a create instead ([insertFormOrNull]). + * DTSTART/DTEND. An id-less `ACTION_EDIT` — or `ACTION_INSERT_OR_EDIT`, which + * some apps fire — is a create instead ([insertFormOrNull]). */ private fun Intent.editEventKeyOrNull(): LongArray? { - if (action != Intent.ACTION_EDIT) return null + if (action != Intent.ACTION_EDIT && action != Intent.ACTION_INSERT_OR_EDIT) return null val uri = data ?: return null if (uri.host != CALENDAR_PROVIDER_HOST) return null val segments = uri.pathSegments From 7b3893ddc6edde478cd2a0926e67e3430dbc23e6 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Fri, 24 Jul 2026 17:40:27 +0200 Subject: [PATCH 2/2] feat(intents): open .ics/.vcs handed over as application/octet-stream (#74) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mail clients, browsers and file managers frequently label a calendar attachment as a generic download (application/octet-stream) rather than text/calendar, so the MIME-typed VIEW filter missed them. Add a dedicated filter that matches those by .ics/.vcs extension via pathPattern — kept separate so the path constraint can't narrow the reliable MIME-typed filter. The import handler already ignores the declared MIME, so a let-through file imports normally. Best-effort: reliable for file:// and content:// whose path carries the name; nameless content:// URIs still fall back to the MIME filter. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 4 ++++ app/src/main/AndroidManifest.xml | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aafac8..724bb14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 didn't advertise — so it was left out of the chooser, and if it was your only calendar app the save silently did nothing. It now accepts that form, plus the `INSERT_OR_EDIT` action, and opens the new event prefilled for review ([#74]). +- Opening a `.ics`/`.vcs` file now works even when another app hands it over + mislabelled as a generic download (`application/octet-stream`), as some mail + clients, browsers and file managers do — Calendula recognises it by its file + extension instead of relying on the declared type ([#74]). ## [2.16.0] — 2026-07-17 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3de3eac..8e0df89 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -112,6 +112,28 @@ + + + + + + + + + + + + +