259 lines
15 KiB
Markdown
259 lines
15 KiB
Markdown
# Changelog
|
|
|
|
All notable changes to floret-kit are documented here. The format follows
|
|
[Keep a Changelog](https://keepachangelog.com/).
|
|
|
|
floret-kit is consumed **from source** — each app embeds it as a git submodule
|
|
and builds it through a Gradle composite build, pinning a specific commit. There
|
|
are no binary releases; "version" tracks the shared `version` in the root build
|
|
(currently `0.3.0`). Entries are grouped by module.
|
|
|
|
## [Unreleased]
|
|
|
|
### Added
|
|
|
|
- **`components`** — `GroupedSectionHeader`, the label above a run of
|
|
`GroupedRow`s: small, `primary`, inset to `GroupedListInset` so it shares the
|
|
cards' left margin. Converged from Calendula's settings hub, where the recipe
|
|
was written as a private `SectionHeader`, and now Agendula's, which had grown
|
|
a flat run of a dozen rows with nothing separating how the app behaves from
|
|
what it is.
|
|
|
|
- **`components`** — `GroupedRow` takes a `contentColor`, the pair to the
|
|
existing `container`: a row given a tint now names the `on*` role that goes
|
|
with it instead of leaving its text on `onSurface`, which only happens to
|
|
read on a container the theme did not pick. Wanted by a status row that
|
|
colours itself by outcome (Agendula's export receipt: `secondaryContainer` on
|
|
success, `errorContainer` on failure).
|
|
|
|
- **`components`** — `ScaledViewPreview` and `ViewPreviewFrame`, the preview
|
|
picker's two halves: the first measures real screen composables at a phone
|
|
viewport and scales the finished layout down (swallowing touches and
|
|
collapsing semantics, so a preview reads as a picture rather than a control),
|
|
the second is the tonal plate it sits on, cross-fading between options and
|
|
taking `GroupedListInset` and the grouped rows' outer radius so preview and
|
|
options read as one stack. Converged from Calendula's view/month-style
|
|
choosers, where the pattern was invented, and now Agendula's onboarding step
|
|
for the quick-add bar; the viewport height the app scales from is a parameter
|
|
rather than a calendar-shaped constant.
|
|
|
|
### Fixed
|
|
|
|
- **`core-crash`** — The prefilled crash issue is filed in English again. Its
|
|
title and body came from string resources, so a crash on a French phone
|
|
opened the tracker with a French issue — unreadable to whoever has to triage
|
|
it. That text is now fixed English in `CrashReportSubmit`, out of resources
|
|
altogether, and `CrashConfig` no longer takes an `issueTitle` (apps drop the
|
|
argument, and their own `crash_report_issue_title` / `crash_report_body_*`
|
|
strings with it). Everything the reporter *sees* — the dialog, the toasts,
|
|
the clipboard label — stays translated.
|
|
|
|
## [0.3.0] - 2026-08-10
|
|
|
|
### Added
|
|
|
|
- **`components`** — `OnboardingScaffold`, the shared shell for a first-run
|
|
flow: hero, body and a call-to-action stack, so the family's onboarding
|
|
screens read as one family while keeping their own mark. A multi-step flow
|
|
passes `progress`, which `OnboardingProgress` draws as one capsule per step
|
|
with the caller's own localised label, and `navigationIcon` for a step that
|
|
can be stepped back from — the navigation slot's width is reserved whether or
|
|
not it is filled and mirrored on the other side, so the progress stays centred
|
|
as steps come and go. `topSpacing` gives a step whose hero is a large picture
|
|
rather than a mark room to breathe; `contentPadding` is the scrolling column's
|
|
horizontal inset, which a step built from grouped rows passes 0 for since
|
|
those carry their own; and `scrollingActions` moves the actions off the bottom
|
|
bar onto the end of the content, for a step taller than the screen where a
|
|
pinned bar eats the room the content needs and hides that there is more below.
|
|
`BenefitRow` is the icon/title/body line those screens list their points with.
|
|
|
|
- **`components`** — `SnackChip`, the family's compact confirmation: a
|
|
content-sized pill sliding up from the bottom with an optional trailing action,
|
|
for the case where the surface behind the confirmation *is* the confirmation
|
|
(a list that just lost a row, a calendar that just moved an event) and a
|
|
full-width snackbar would cover it. Placement and timing stay with the caller —
|
|
the bottom inset to clear differs per screen, and what an expiring undo window
|
|
commits is the app's business. Converged from Agendula's swipe-delete undo chip
|
|
and Calendula's drag-to-reschedule confirmation; the shared version keeps the
|
|
polite live region so the chip is announced, takes a `maxWidth` so a message
|
|
can't run into a bottom-end FAB, and takes `color`/`contentColor` so an app can
|
|
put it on the FAB's own fill. A message replaced in place crossfades and the
|
|
pill resizes with it, so an answered confirmation ("Moved" → "Move undone")
|
|
reads as one chip changing rather than two chips swapping.
|
|
|
|
- **`components`** — `GroupedRow` takes an `AnnotatedString` title and summary
|
|
as well as plain `String`s, so a row can carry its own emphasis: marking the
|
|
run a search matched, without every caller having to rebuild the row. The
|
|
`String` overload delegates to it, so existing callers are unchanged.
|
|
|
|
- **`components`** — `GroupedSurface`/`GroupedRow` take an `onLongClick` (with
|
|
the platform long-press haptic), for a list that enters a selection mode from
|
|
a row.
|
|
|
|
- **`components`** — `GroupedListInset`, the 16dp a grouped list keeps from the
|
|
screen edge, exported. It was a private literal, so everything sitting outside
|
|
the cards but belonging to them — section headers, hints, picker descriptions —
|
|
repeated the number and had drifted to 24dp in places, leaving pages with two
|
|
ragged left margins.
|
|
|
|
- **`components`** — `OptionPicker` takes a per-option summary, put under the
|
|
label, for a row that names something it doesn't spell out (a range's dates, a
|
|
reminder's firing time, what "follow the system" resolves to today). Every
|
|
option then shows its effect at once and stays comparable, without the cost of
|
|
a live preview. The KDoc states the three rungs of picker richness — plain
|
|
rows / per-option summary / live preview — and the rule that a preview picker
|
|
must not close on selection, since closing hides the thing it exists to show.
|
|
|
|
- **`components`** — `SelectedCheck`, the trailing check that marks a chosen row
|
|
in a full-screen picker, made public. It was private to `OptionPicker`, so
|
|
every consumer hand-rolled a copy — Calendula alone carried five, all drawing
|
|
a different check than the kit's.
|
|
|
|
- **`components`** — `AboutCard` takes a `Position` and renders through
|
|
`GroupedSurface`, so it can be the top of a group with rows continuing
|
|
underneath rather than only standing alone. Defaults to `Position.Alone`.
|
|
|
|
### Fixed
|
|
|
|
- **`core-time`** — all-day values rendered a day early west of UTC. All-day
|
|
items are date-only in iCalendar and stored as UTC midnight of their calendar
|
|
date, but `formatDate`/`formatDateTime`/`formatDateTimeCompact` resolved every
|
|
instant against `ZoneId.systemDefault()`. `formatDate` now takes an `allDay`
|
|
flag (default `false`, so existing call sites are unaffected) and resolves
|
|
those against UTC; callers must pass it at the call site.
|
|
|
|
- **`components`** — full-screen picker status/navigation-bar icons matched the
|
|
XML theme rather than the running one. A Compose `Dialog` owns its own window,
|
|
seeded from the XML theme, so a picker drawing under the bars showed dark icons
|
|
on a dark surface. `FloretExpressiveTheme` now exposes its resolved light/dark
|
|
decision as `LocalFloretDarkTheme` and the dialog window's bar appearance
|
|
follows it, tracking the in-app choice even when it diverges from the system
|
|
night qualifier.
|
|
|
|
## [0.2.1] - 2026-07-17
|
|
|
|
### Added
|
|
|
|
- **`components`** — `CollapsingScaffold` takes a `scrollable` flag (default
|
|
`true`, so every existing caller is unchanged). Set it to `false` when the
|
|
content brings its own scrolling container: the scaffold's own
|
|
`verticalScroll` composes each row up front and can't host a `LazyColumn`
|
|
(nesting a same-axis scrollable throws), which ruled out any surface with more
|
|
options than fit an eager pass. Opting out hands the content a plain column and
|
|
leaves the insets, IME padding and top-bar collapse as they were.
|
|
`FullScreenPicker` forwards the flag. Consumed by Calendula's ~600-entry
|
|
time-zone picker from 2.16.0.
|
|
|
|
## [0.2.0] - 2026-07-17
|
|
|
|
### Added
|
|
|
|
- **`components`** — `CustomAmountEditor`, the amount + unit editor behind an
|
|
"Custom…" picker option (Calendula's custom snooze duration). Consumed by
|
|
Calendula since 2.15.0.
|
|
- **`core-locale`** — the locale-aware formatting half of the module, so apps
|
|
stop hand-rolling `"$day. $month $year"` templates that bake one language's
|
|
field order (and its separators, and its ordinal dot) into every language they
|
|
ship:
|
|
- `localizedDateFormatter(locale, skeleton)` — a `DateTimeFormatter` for a
|
|
field skeleton ("LLLLy", "dMMMy", "EEEdMMM") laid out in the locale's own
|
|
order, via Android's best-pattern matching. Drop a field from the skeleton to
|
|
drop it from the output — the locale still supplies the arrangement.
|
|
- `currentLocale()` — the display locale, observed from `LocalConfiguration`.
|
|
Since `AppLanguage.apply()` changes the language inside a running process, a
|
|
locale captured once goes stale; this keys recomposition to the change.
|
|
|
|
### Changed
|
|
|
|
- **`core-locale`** now carries Compose (runtime + ui only) for `currentLocale()`.
|
|
The module previously declared itself Compose-free; applying a language
|
|
mid-process is its own API, so the hook that makes the UI notice belongs beside
|
|
it rather than in a Compose module depending back on this one. `core-crash` is
|
|
the precedent for a `core-*` module carrying Compose.
|
|
|
|
### Known gaps
|
|
|
|
- `core-time`'s `Instant.formatDate()` family now overlaps `core-locale`. Its
|
|
private `dateNoYearFormatter` strips the year by regex-ing the pattern string,
|
|
which `localizedDateFormatter(locale, "dMMM")` does properly; and its
|
|
formatters resolve `Locale.getDefault()` once at class-init ("locale changes
|
|
within a running process are rare enough to ignore"), which `AppLanguage.apply()`
|
|
makes untrue. Left alone for now — it is unused by Calendula but Agendula-visible.
|
|
Reconcile when Agendula next re-pins.
|
|
|
|
## [0.1.0] - 2026-07-07
|
|
|
|
### Added
|
|
|
|
- **`core-locale`** (Android library) — per-app language plumbing (`AppLanguage`):
|
|
read the shipped languages from the app's `res/xml/locales_config.xml`, get/set
|
|
the applied language via `AppCompatDelegate`, render each language's autonym.
|
|
The app passes its own `locales_config` resource id; the system-default choice
|
|
is `null`. _(Shipped in 0.1.0 but omitted from this changelog at the time;
|
|
recorded here retroactively.)_
|
|
- **`core-time`** (JVM library) — pure-Kotlin date/time helpers, no Android and
|
|
no third-party dependencies:
|
|
- `DayWindow.today()` — local-day boundaries for smart-list logic.
|
|
- `Instant.formatDate()` / `formatTime()` / `formatDateTime()` — locale- and
|
|
zone-aware display formatting over `kotlin.time.Instant`.
|
|
- `TimeBridge` — `Long` epoch-millis ↔ `Instant`, for content-provider I/O.
|
|
- `LocalDate.isoWeekNumber()` — ISO-8601 week-of-week-based-year, the
|
|
calendar-week number for week/month grids (one scheme, shared).
|
|
- **`core-crash`** (Android library) — privacy-respecting, on-device crash
|
|
capture and reporting. Writes an allowlist-only report (app/Android/device
|
|
version, locale, time, stack trace — nothing else) to private storage and
|
|
chains to the platform handler; uploads nothing. Includes startup crash-loop
|
|
detection, a report dialog that shows the full text before it leaves the
|
|
device, and an issue-tracker hand-off. Per-app specifics (display name, issue
|
|
URLs) come from a `CrashConfig` supplied at `install()`; each app keeps its
|
|
own thin themed `CrashReportActivity`.
|
|
- **`identity`** (Android library) — the family's Material 3 Expressive theme
|
|
factory `FloretExpressiveTheme(lightScheme, darkScheme, …)` (dynamic colour on
|
|
API 31+, system light/dark fallback, the standard motion scheme) plus the
|
|
shared motion helpers — `rememberNavSlideSpec()`, the content transitions,
|
|
`Modifier.predictiveBack()` and `Modifier.animateContentSizeMotion()` (eases a
|
|
block's own height changes, e.g. a text field wrapping to a new line), each
|
|
reduced-motion-aware. Each app passes its own seed-derived colour schemes
|
|
and typography — the mechanics are shared, the look is not.
|
|
- **`components`** (Android library) — the shared Compose component vocabulary:
|
|
- `GroupedSurface` / `GroupedRow` + `Position` / `positionOf` — the canonical
|
|
press-morphing tonal grouped-row primitive (the Android-15 settings pattern).
|
|
- `InlineTextField` — the borderless tonal text input (capitalization is a
|
|
parameter).
|
|
- `OptionCard` — the sanctioned selection-dialog pick.
|
|
- `CollapsingScaffold` — the collapsing settings/sub-screen scaffold; set
|
|
`largeTopBar = false` for a pinned single-line bar (the picker variant).
|
|
- `FullScreenPicker` / `OptionPicker` — the full-screen single-select picker,
|
|
now over a pinned single-line bar (a picker is a short list, so no tall
|
|
collapsing header to scroll past). `FullScreenPicker` takes an optional
|
|
`actions` slot (app-bar trailing items) for pickers that carry a commit or
|
|
extra action — a custom-value **Add**/**OK**, a **Reset**.
|
|
- `ReorderableColumn` — dependency-free drag-to-reorder for the short, fixed
|
|
grouped-card Settings lists; pairs with `GroupedRow(gapBelow = false)`, which
|
|
hands the column uniform control of row spacing.
|
|
- `DebugRibbon` — a stark, un-themed "DEBUG" corner ribbon; gate on
|
|
`BuildConfig.DEBUG` at the call site.
|
|
- `InlineTextField` gained `enabled` (a disabled field dims to a locked value).
|
|
- `pastelize()` — softens a raw provider colour to a theme-fitting pastel.
|
|
|
|
App-agnostic by design: apps compose their own screens and keep their own
|
|
identity chips/icons. String resources here (e.g. `back`) are fallbacks an app
|
|
can override.
|
|
- **`core-reminders`** (JVM library) — the app-agnostic reminder-override model:
|
|
`ReminderOverride` (`Inherit` / `None` / `Minutes`), where `Minutes` carries a
|
|
**list** of lead-times so a target can hold several reminders at once (an app
|
|
that offers a single reminder just uses a one-element list). Map helpers
|
|
(`reminderOverrideFor`, `reminderLeadsFor`, `applyReminderOverride`,
|
|
`reminderOverrideForMinutes`, `normalizeReminders`) plus `ReminderOverrideCodec`
|
|
(three configurable separators; single legacy values round-trip byte-identically)
|
|
and the lead-time unit model (`ReminderUnit`, `decomposeReminderMinutes`). The
|
|
labels/presets and the alarm scheduler stay per-app.
|
|
|
|
### Conventions
|
|
|
|
- **No `foojay` toolchain resolver** anywhere — it can fetch a JDK at build time,
|
|
which reproducible / official F-Droid builds reject. Modules set `jvmTarget`
|
|
directly. See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
- AGP 9.x provides built-in Kotlin compilation, so Android modules apply only the
|
|
Android library + Compose plugins (no separate `kotlin.android`).
|