422 lines
24 KiB
Markdown
422 lines
24 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.7.0`). Entries are grouped by module.
|
|
|
|
## [Unreleased]
|
|
|
|
### Fixed
|
|
|
|
- **`core-locale`** — picking a language did nothing on Android 13+. AppCompat's
|
|
`setApplicationLocales` only reaches the platform through a live
|
|
`AppCompatActivity`, and every app uses `ComponentActivity`. `AppLanguage`
|
|
now calls `LocaleManager` directly there: `apply(context, tag)` and
|
|
`currentTag(context[, supported])`. The context-free versions are deprecated.
|
|
`LanguagePickerRow` uses the new ones; apps that call `AppLanguage` themselves
|
|
(Agendula's settings row) need to pass a context.
|
|
|
|
### Changed
|
|
|
|
- **Build** — dependencies to the newest stable releases: AGP 9.4.1, Kotlin
|
|
2.4.20, Gradle 9.8.0, Compose BOM 2026.09.00, core-ktx 1.19.1, appcompat
|
|
1.8.0, JUnit 6.1.3; material3 to `1.5.0-alpha29` (still no stable 1.5 with the
|
|
Expressive APIs). AGP must match across a composite build, so a consuming app
|
|
re-pinning to this needs AGP 9.4.1 itself.
|
|
|
|
### Added
|
|
|
|
- **`components`** — picker-row helpers lifted from Calendula's pickers and
|
|
settings, all additive. `GroupedRow` takes `checked` (default `false`): it
|
|
implies `selected` and fills an empty trailing slot with `SelectedCheck`,
|
|
replacing the hand-written `if (selected) { { SelectedCheck() } } else null`.
|
|
`OptionPicker` takes `dismissOnSelect` (default `true`, today's behaviour) for
|
|
preview pickers that stay open, and its rows are public as `OptionRows` for a
|
|
picker that composes its own `FullScreenPicker`. `CustomExpandRow` is the
|
|
"Custom…" row of a presets-plus-custom picker, revealing its editor
|
|
(typically `CustomAmountEditor`) as one connected container.
|
|
`GroupedSwitchRow` is the settings toggle row where the whole row flips the
|
|
switch. `GroupedHint` is the muted text beside the cards (settings hints,
|
|
picker descriptions), and `ExpandIcon` the turning chevron, now also used by
|
|
`InstructionSteps`.
|
|
- **`components`** — `IconInfoCard`, the tonal icon-plus-content card behind
|
|
Calendula's event detail and edit screens (optionally clickable, a top-aligned
|
|
icon for multi-line fields, a `header` line the icon centres on).
|
|
- **`components`** — `OnboardingScaffold` takes `headline` and `supporting`,
|
|
the centred title and muted explanation most steps open `body` with; `body`
|
|
now defaults to empty. `OnboardingPrimaryButton` is the full-width 56dp
|
|
call-to-action, with an optional trailing icon. Existing calls are unchanged.
|
|
- **`components`** — `LanguagePickerRow` takes `header` and `predictiveBack`,
|
|
forwarded to its `OptionPicker`, so an app with a "help translate" row above
|
|
the languages can drop its own copy of the row. Both default to today's
|
|
behaviour.
|
|
- **`core-locale`** — `relativeTimeAgo(epochMillis, nowMillis, minResolution)`,
|
|
the platform-localised "5 minutes ago" Calendula's backup and special-dates
|
|
status lines build through `DateUtils.getRelativeTimeSpanString`.
|
|
|
|
- **`identity`** — a pure-black (AMOLED) dark theme. `ColorScheme.toPureBlack()`
|
|
sets `background`, `surface`, `surfaceDim` and `surfaceContainerLowest` to
|
|
#000 and pulls the other containers down towards black, keeping their hue
|
|
tint, so grid tiles drawn as containers over `surface` still show their
|
|
gaps. `FloretExpressiveTheme` gains `pureBlack` (default `false`), which
|
|
applies it to the dark scheme, dynamic or app-supplied.
|
|
- **`core-prefs`** — `ThemeMode.BLACK`, dark with pure-black surfaces.
|
|
`isDark` treats it as dark, and the new `ThemeMode.isPureBlack` is what an
|
|
app passes to the theme's `pureBlack`. It's stored as `"BLACK"` under the
|
|
same `theme_mode` key; a build without it reads that as `SYSTEM`.
|
|
|
|
- **`glance`** (new module) — the family's shared home-screen-widget plumbing
|
|
and M3 Expressive widget vocabulary, built on Jetpack Glance:
|
|
`FloretGlanceTheme` (dynamic colour on API 31+, app-supplied fallback
|
|
schemes otherwise, a per-widget `WidgetThemeMode` override), `WidgetSurface`
|
|
(solid/tinted/transparent root backgrounds with the system corner radius),
|
|
`WidgetHeader` + `WidgetActionButton` (a 48dp tonal/filled pill, extendable
|
|
with a label), `WidgetGroupedRow` (the Glance counterpart of `components`'
|
|
`GroupedSurface`, built from four position-shaped drawables since Glance's
|
|
`cornerRadius` has no per-corner overload), `WidgetMessage`, and the
|
|
`WidgetRollover` + `FloretWidgetUpdateReceiver` midnight-rollover plumbing.
|
|
Converged from Agendula's widget package, written for the M3 Expressive
|
|
widget pass (calendula#71); Calendula adopts it when its own widget overhaul
|
|
lands.
|
|
|
|
## [0.7.0] - 2026-09-12
|
|
|
|
### Added
|
|
|
|
- **`components`** — `CollapsingScaffold` takes `floatingActionButton` and
|
|
`floatingActionButtonPosition`, forwarded to the underlying `Scaffold`. Both
|
|
default to the bare scaffold, so every existing call site in every app is
|
|
unchanged, and they sit after `snackbarHost` so no positional call shifts.
|
|
The driver is Clockula's alarms tab: three of its four tabs need an "add"
|
|
affordance on a scaffold the kit owns, and the alternative — a `Box` wrapping
|
|
the scaffold with a bottom-end FAB — re-derives the window-inset and
|
|
position maths `Scaffold` already does, once per tab and again in every
|
|
sibling app.
|
|
|
|
## [0.6.0] - 2026-09-11
|
|
|
|
### Changed
|
|
|
|
- **`components`** — `CollapsingScaffold`'s `onBack` is now nullable and
|
|
defaults to null. A null `onBack` draws no navigation icon and wires no
|
|
predictive-back handler; every existing call site, which passes a lambda,
|
|
is unchanged. The driver is Clockula's four tabs: a top-level destination
|
|
wants exactly this scaffold — the large title that shrinks into the bar over
|
|
a scrolling column — and nothing behind it to go back to, and a back arrow
|
|
that pops nothing is worse than no arrow at all. Cheaper and truer than each
|
|
app hand-rolling a second, arrow-less scaffold beside this one.
|
|
|
|
## [0.5.0] - 2026-09-11
|
|
|
|
### Added
|
|
|
|
- **`core-prefs`** — the family's typed DataStore layer, extracted now that
|
|
Clockula is the third app that would have written it again. `Pref<T>` is one
|
|
preference as data — its on-disk key name, its default and its codec — built
|
|
by `booleanPref`/`intPref`/`longPref`/`floatPref`/`stringPref`/`stringSetPref`,
|
|
the nullable pair (`nullableStringPref`/`nullableLongPref`, where writing
|
|
`null` *removes* the key rather than storing a sentinel), `enumPref`, and
|
|
`map()` for a view of the same slot as another type. `PrefStore` wraps a
|
|
`DataStore<Preferences>` with `get`/`set`/`update`/`clear`/`clearAll`, a raw
|
|
`edit` escape hatch, and `flow(pref)` — which is `distinctUntilChanged`, so an
|
|
unrelated key's write no longer re-emits every screen's setting, the bug both
|
|
siblings' hand-rolled `data.map { … }` carried. `String?.toEnum(default)` is
|
|
the read path for every enum-valued preference: unknown, empty and wrong-case
|
|
values degrade to the default instead of throwing. Also the shared appearance
|
|
slice — `ThemeMode` (with `isDark(systemDark)`, the `when` block that was
|
|
duplicated in both siblings' `MainActivity`), `Appearance` and
|
|
`AppearancePrefs`. The stored key names are byte-identical to what Calendula
|
|
and Agendula already write (`theme_mode`, `dynamic_color`), so adopting the
|
|
module is a code change with **no data migration**. The store's *name* and its
|
|
construction stay with the app. Consumed by Clockula.
|
|
|
|
- **`core-di`** — the family's shared DI vocabulary: the `@IoDispatcher`,
|
|
`@DefaultDispatcher` and `@ApplicationScope` qualifiers and the
|
|
`CoroutinesModule` that provides them (the application scope on a
|
|
`SupervisorJob`, so one failing collector can't take its siblings down). Every
|
|
app in the family had re-declared the same qualifier and the same provider.
|
|
The kit's only module that knows about Dagger, and its only one carrying an
|
|
annotation processor — a `@Module @InstallIn(...)` reaches a consuming app's
|
|
component only if the library itself is run through `hilt-compiler`. Consumed
|
|
by Clockula.
|
|
|
|
## [0.4.0] - 2026-09-24
|
|
|
|
### 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.
|
|
|
|
- **`components`** — `InstructionSteps`, a numbered, connected list for a
|
|
procedure the user carries out somewhere else. Collapsible, so it can come
|
|
back as a reference once it has had a screen of its own.
|
|
|
|
- **`components`** — `InlineTextField` takes a `visualTransformation`, so a
|
|
password can be masked. `KeyboardType.Password` only drops IME suggestions;
|
|
without this the field rendered the secret in the clear.
|
|
|
|
- **`components`** — `ReorderableColumn` takes a `rowHeight` (default
|
|
`ReorderableRowHeight`), so rows keep their normal height while reordering.
|
|
The drag shadow now follows the card's shape, and a row resists being dragged
|
|
past either end.
|
|
|
|
- **`core-time`** — `formatTime`, `formatDateTime` and `formatDateTimeCompact`
|
|
take an optional `is24Hour`, for an app-level 12/24-hour setting. `null`
|
|
keeps following the system.
|
|
|
|
### Fixed
|
|
|
|
- **`identity`** — A committed predictive back no longer snaps the surface back
|
|
to full size before it leaves. `Modifier.predictiveBack()` now holds the
|
|
preview transform after `onBack`, and the new `predictiveBackExit()` exit
|
|
fades and keeps shrinking from there; pair them on the surface's
|
|
`AnimatedVisibility` instead of a full-size slide-out. Pass that
|
|
`AnimatedVisibility`'s `visible` to `predictiveBack(visible = …)` (or
|
|
`CollapsingScaffold(visible = …)`) so the preview is dropped as soon as the
|
|
surface is shown again — reopened mid-exit it no longer appears shrunk — and
|
|
settles back when a back leaves it in place. Without it the preview is held
|
|
for a fixed second.
|
|
- **`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`).
|