Long-pressing one of the three free-text fields in the event view puts the whole field on the clipboard.
| Field | Tap | Long-press |
| --- | --- | --- |
| Title | — | copy |
| Location | opens maps (unchanged) | copy |
| Description | links still open (unchanged) | copy |
Times, calendar, recurrence and attendees stay uncopyable. The confirmation snackbar only shows below API 33 — Android 13+ raises its own clipboard chip. A failed copy is reported on every API level.
First clipboard use in the app, so the helper lives in `ui/common` as a `FieldCopier` plus a `copyOnLongPress` modifier. A field with no tap action gets the gesture through `pointerInput` and merged `onLongClick` semantics rather than a `clickable` that would announce a tap it doesn't have.
Deviation worth naming: the description takes the gesture on its card rather than its text. A linkified URL consumes the press over its own glyphs, so long-pressing a URL copies nothing either way — the card at least adds the icon and padding as target. A description that is nothing but a link stays awkward to copy.
Closes#195
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/263
### Part A — the title shortens instead of wrapping
`CalendarTitleButton` measures the full title against the width the bar hands
the title slot (`BoxWithConstraints` + `rememberTextMeasurer`) and falls back to
a shorter form when it does not fit. One pass, so no flicker, and it adapts on
its own to locale, font scale and to the pill being absent after #150.
- Month and week fall back to the three-letter month ("Sep", "Mär").
- Day drops the weekday instead ("Wed, 2 Sep 2027" → "2 Sep 2027") — there is no
shorter month form left there, `EEEdMMM` is already abbreviated.
- Either way the title now clamps to one line and ellipsises rather than growing
the bar to two lines.
The choice itself is a pure `titleFor(title, shortTitle, titleWidth,
availableWidth)`, so it is unit-tested rather than only reachable through a
composable. `formatCalendarTitle` gained no new behaviour, so the widget header
is untouched.
### Part B — the trailing edge, not the whole rhythm
`AppBarSpacing` holds the shared values: the side inset (also consumed by the
month grid, so the pill lines up with the content under it), the title's start
inset, and the two trailing insets — one measured to a container's background,
one to an icon button's glyph.
**Deviation from the issue:** the issue asks for one edge inset at *both* ends
and one gap between adjacent controls. Only the trailing edge and the title
inset are shared here. M3 derives both the title's position and the gap between
two adjacent action icons from the icon buttons' width, so putting the leading
edge and the inter-icon gaps on the same rhythm meant narrowing the icon buttons
from 48.dp to 32.dp — that reads cramped and shrinks the touch targets. The
leading edge and the icon gaps stay on M3's defaults. The title's 8.dp start
inset stays real padding rather than a negative offset, so the menu button's hit
box is intact.
The agenda range bar picks its end inset from whether the view switcher is
showing: aligned to the pill's background when it is, to the search icon's glyph
once #150 hides it.
Closes#165
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/261
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
Calendula is published on Google Play, so the pipeline and the docs stop treating it as pending.
**README**
- Google Play badge next to F-Droid/Obtainium, linking the store page.
- Install table: the Play row goes from "Coming soon / —" to a real channel.
- The "coming soon" section becomes a live one with the store link; the closed-testing "testers wanted" call drops out. The note that Play signs with Google's key (so switching channels needs an uninstall) stays, and the trailing shared-signing-key line now flags Play as the exception.
**Play track**
- Release uploads default to `production` instead of `internal` — in the lane (`fastlane/Fastfile`) and in the workflow default (`.gitea/workflows/release.yaml`). Merging a bumped versionName to main is already the human gate, so the manual Console promotion only added delay.
- `docs/RELEASING.md` updated to match, including the escape hatches (`PLAY_TRACK=internal` to stage, `PLAY_RELEASE_STATUS=draft` to hold).
Note: if a `PLAY_TRACK` repo variable is set on Gitea it still wins over the new default — needs checking there.
No issue for this one.
Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/244