9 Commits
Author SHA1 Message Date
Jean-Luc Makiolaandmakiolaj e10fae0710 Release v2.20.0 (#286)
Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 5s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Successful in 32m28s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Failing after 1m21s
Release 2.20.0.

**Added**
- Long-press an event's title, location or description to copy it ([#195]).
- Settings → About lists the open-source projects Calendula ships, with
  copyright holder, licence and a link to each project's source ([#281]).

**Changed**
- Week and day view seat every hour in its own rounded cell instead of drawing a
  separator line across the column; an on-the-hour event fills its cell rather
  than overhanging the seam ([#113]).
- Event titles run to the edge of their chip in all three grid views — no
  ellipsis. RTL keeps it, where clipping would cut the start of the title
  ([#164]).
- Month events show their start time where the chip is wide enough, and event
  times across month, week and day are set in a regular weight ([#219]).
- An invitation you haven't answered is drawn as an outline; declined events
  keep their filled, struck-through chip and now sort last in the month view
  ([#230]).
- The top-bar title falls back to a shorter form instead of being cut off, and
  the bar's trailing edge lines up with the grid under it ([#165]).
- The jump-to-today button carries today's date and rolls over at midnight
  ([#220]).
- The quick-switch pill hides when there is nothing to switch between, and views
  can now be turned off down to a single one ([#150]).

**Fixed**
- A long location wraps and its card grows, instead of scrolling sideways out of
  sight ([#273]).
- The event form capitalizes sentences again; location stays uncapitalized,
  being as often a URL as an address ([#146]).
- A dragged block's floating copy wraps its time and title the way the block
  does, instead of clipping to one line while held ([#267]).

### Release preparation

`versionName`/`versionCode` → 2.20.0/22000, `CHANGELOG.md`'s Unreleased section
moved under a dated 2.20.0 heading, and a hand-written 497-character
`fastlane/metadata/android/en-US/changelogs/22000.txt`.

Six of the merged PRs had no CHANGELOG entry (#146, #150, #195, #230, #267,
#281); they are written up here. The existing #164 entry only described the
month view and did not mention the RTL exception — both corrected.

### Also here

`scripts/check_changelog_lengths.sh`, run in CI next to the reproducible-release
invariant. Play rejects a "What's New" over 500 characters, which would fail the
upload *after* the release had already shipped to F-Droid and Codeberg —
2.19.4 went out at 697. The script walks every locale, fails on the current
`versionCode` and only warns on the already-published files, of which 13 are
over the limit from when the pipeline auto-generated them from `CHANGELOG.md`.

Deviation worth naming: this does not fix those 13. They are published and Play
never re-reads them, so failing on them would paint every PR red for no gain;
`--strict` covers them if they are ever backfilled.

Follow-up filed as #285 — the store listing exists in only 4 of 12 locales and
its graphics still don't qualify for Play.

All twelve issues above are closed by their own PRs; this branch ships them.

Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de>
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/286
2026-09-07 21:25:35 +02:00
Jean-Luc Makiola a8a83a39d0 2.18.0 (#126)
Release — F-Droid repo + Gitea/Codeberg release + Play / detect (push) Successful in 6s
Release — F-Droid repo + Gitea/Codeberg release + Play / release (push) Successful in 13m15s
Release — F-Droid repo + Gitea/Codeberg release + Play / play (push) Successful in 1m34s
Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/126
2026-07-31 22:22:10 +02:00
makiolajandClaude Opus 4.8 955d47ef12 chore: draw shared code from floret-kit (fresh re-migration onto current main)
Supersedes the stale chore/floret-kit-core-time branch: re-applies the
floret-kit migration on top of current main (122 commits ahead of the old
branch's base), pinning the kit at the multi-value-reminders + pinned-picker HEAD.

- Submodule + composite build (includeBuild), 6 module deps, CI submodules:
  recursive, reproducible-release scan extended to the kit, F-Droid recipe.
- Deletes the inline copies now owned by the kit (GroupedList, Picker scaffolds,
  InlineTextField, OptionCard, DialogControls, CrashReporter + dialog/submit,
  OnboardingScaffold, AppLanguage, TimeBridge, ReorderableColumn, DebugRibbon)
  and redraws them from components/identity/core-crash/core-locale/core-time.
- Reminder overrides drawn from core-reminders (multi-value ReminderOverride +
  codec); Calendula keeps its app-specific bits (all-day resolution, labels,
  presets, the multi-select ReminderDefaultPicker, its own CrashReportActivity).
- Theme draws FloretExpressiveTheme while keeping the user-typography param.

Build pending (deferred): run ./gradlew :app:compileDebugKotlin with ANDROID_HOME
(or floret-kit/local.properties) set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 09:28:56 +02:00
makiolajandClaude Opus 4.8 b6bee55fc6 ci(fdroid): guard all three reproducible-build invariants
CI / ci (pull_request) Successful in 2m19s
The reproducible-release CI guard only asserted `vcsInfo { include = false }`.
F-Droid review surfaced two more invariants that, if they regress, silently
stall official publishing (fails safe — stuck on an old version):

- no foojay toolchain resolver in any Gradle script (the offline source
  scanner rejects org.gradle.toolchains.foojay-resolver — it can fetch a JDK
  over the network), and
- `dependenciesInfo { includeInApk = false }` (else AGP embeds a "Dependency
  metadata" block, id 0x504b4453, in the APK Signing Block, which the binary
  scanner rejects as an extra signing block).

The script now checks all three, accumulates failures (reports every broken
invariant in one run, not just the first), and exits non-zero if any fails.
Verified positive + one negative per invariant + all-three-broken.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 11:27:58 +02:00
makiolajandClaude Opus 4.8 36e2199dff chore(fdroid): finalize recipe at v2.7.3 + reproducible-release CI guard
CI / ci (pull_request) Successful in 8m50s
v2.7.3 is the first release built with `vcsInfo { include = false }` and is
verified reproducible: a clean from-source build matched the published
calendula_v2.7.3.apk byte-for-byte across all 1382 zip entries (only the
signature block differs, which F-Droid copies).

- Point the fdroiddata recipe's Builds entry + CurrentVersion at v2.7.3
  (was the 2.7.2 placeholder, which lacks the fix and would fail verification).
- UpdateCheckMode: Tags ^v[0-9.]+$ — after this one-time submission F-Droid
  auto-tracks new release tags and adds build entries itself; no manual recipe
  edits per release.
- Add scripts/check_reproducible_release.sh + an always-on CI step asserting the
  release build keeps VCS-info disabled, so reproducibility can't silently
  regress and quietly stop official-repo publishing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 14:28:01 +02:00
makiolajandClaude Opus 4.8 f3f155b5ff chore(fdroid): single-source fastlane metadata + reproducible-build prep
CI / ci (pull_request) Failing after 8s
Make fastlane/metadata/android/ the single source of truth for store
listing metadata, consumed directly by the official F-Droid repo and
transformed into the self-hosted repo's localized layout at release time.

- Move fdroid-metadata/<appid>/<locale>/ -> fastlane/metadata/android/<locale>/
  (git-tracked renames: summary->short_description, description->full_description,
  + title.txt, images/icon.png, images/phoneScreenshots/); keep the app-level
  .yml control file for the self-hosted `fdroid update`.
- Add scripts/fastlane_to_fdroid_localized.sh (fastlane -> F-Droid localized,
  incl. changelogs) and scripts/sync_changelog_to_fastlane.sh (CHANGELOG.md ->
  fastlane changelog); verified byte-identical to the previous metadata.
- release.yaml: build self-hosted metadata from the fastlane tree and sync the
  per-version changelog before the transform (one changelog source for both
  channels).
- Disable AGP VCS-info embedding on release builds (vcsInfo { include = false })
  so builds reproduce byte-for-byte vs the distributed APK — the only file that
  otherwise differed (META-INF/version-control-info.textproto). Effective from
  the next release.
- Add docs/fdroid-official/ (draft fdroiddata recipe: reproducible build +
  AllowedAPKSigningKeys + Binaries + notes).
- Repoint README screenshots/icon, update docs/README + RELEASING, and skip the
  Android build on fastlane-only changes (ci.yaml).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 13:17:21 +02:00
makiolajandClaude Opus 4.8 df203c0b6b ci: release on merge-to-main; consolidate pipeline triggers
Translations / check (pull_request) Successful in 5s
CI / ci (pull_request) Successful in 5m55s
Reworks the pipeline so a change is built once and a release is driven by the
merge, not a manual tag push.

- ci.yaml now runs on pull_request (one gate per PR) instead of every branch
  push, so there's no CI-on-push + CI-on-merge double run. A single `ci` job
  with a docs-only fast-path keeps the required "CI" check always reporting
  (docs/metadata-only PRs skip the Android build but still go green).
- release.yaml triggers on push to main. A cheap `detect` job reads versionName
  from build.gradle; only when no tag for it exists does the `release` job run:
  tests on the merged commit, build + sign, publish to F-Droid, then create the
  vX.Y.Z tag + Gitea release via the API (target_commitish = the merged sha).
  The tag is now an OUTPUT of a successful release, not its trigger — a failure
  before publish leaves no tag, so re-running safely retries. No more separate
  tag-triggered run or duplicate ci job.
- The committed versionName/versionCode are now the source of truth (pipeline
  pins versionCode from versionName); updated the build.gradle comment.
- translations.yaml switched to pull_request (same path filter).
- docs/RELEASING.md: release-by-merge flow, no manual git tag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 12:32:56 +02:00
makiolajandClaude Opus 4.8 0c95479051 build,docs: add on-device release verification gate
Adds a mandatory pre-tag step to the release process: build the R8-shrunk
release candidate and smoke-test it on a real device, including a first-run /
permission-not-granted state. The v2.7.0 launch crash (calendar observer
registered before the permission gate) reached users because it only manifests
in the minified release build on a device without the permission already
granted — the debug build and an already-permissioned phone both hid it.

- New `releaseTest` build type: same R8 shrinking + obfuscation as `release`,
  but debug-signed with a `.releasetest` applicationId suffix so it installs
  alongside the production and debug apps. Never published; CI only ever builds
  the real `release` variant from the tag.
- scripts/verify-release.sh: builds + installs `releaseTest` and resets it to a
  first-run state, with an on-device checklist.
- docs/RELEASING.md: formalize the release/vX.Y.Z branch flow and the on-device
  verification gate before tagging.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 12:27:30 +02:00
makiolajandClaude Opus 4.8 cf380b6eab ci(i18n): translation parity guard + allow partial translations
Translations / check (push) Successful in 7s
CI / ci (push) Failing after 17m45s
Add scripts/check_translations.py and a lightweight Translations workflow
that runs it (no Android SDK needed) so Weblate PRs get fast feedback. The
script fails on stale keys (present in a translation but not the base) and on
translating translatable="false" entries; missing keys are reported as
coverage only.

Downgrade lint's MissingTranslation to informational: partial community
translations are expected and fall back to the English base at runtime.
Stale/extra keys (ExtraTranslation) remain fatal in lintDebug.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 08:43:06 +02:00