2026-10-18 21:46:55 +02:00
|
|
|
# halkyon_ui
|
|
|
|
|
|
|
|
|
|
Halkyon's look, shared by its apps (Learn, Todo, Train): one theme around the
|
|
|
|
|
kingfisher's cobalt and copper, the bundled Noto Sans, Material 3's window
|
|
|
|
|
sizes, and the widgets every app's screens are built of, with their texts in
|
|
|
|
|
British English, American English and German.
|
|
|
|
|
|
|
|
|
|
Written as the apps are: Dart 3.13's primary constructors, Material from
|
|
|
|
|
`package:material_ui` (never `package:flutter/material.dart`), Lucide icons,
|
|
|
|
|
LeanCode's lints.
|
|
|
|
|
|
|
|
|
|
## What it holds
|
|
|
|
|
|
|
|
|
|
- **Theme** (`lib/src/theme/`): `appTheme(brightness, extensions: …)`, Material
|
|
|
|
|
3 with hand-written light and dark schemes (primary cobalt, tertiary copper,
|
|
|
|
|
cobalt-tinted neutrals), Material 3 Expressive's 64 dp navigation bar, flat
|
|
|
|
|
app bars, floating snack bars; `Brand`; `ThemeExtras`, the status colours
|
|
|
|
|
Material has no role for (`Theme.of(context).extras`); `PaletteColor`, the
|
|
|
|
|
20 colours a person can give content, each with a text colour held to WCAG
|
|
|
|
|
AA by a test; `FittedSnackBars`.
|
|
|
|
|
- **Fonts**: Noto Sans for Latin, Greek and Cyrillic, every weight in one
|
|
|
|
|
variable file, as `appFontFamily` (`packages/halkyon_ui/Noto Sans`). Chinese,
|
|
|
|
|
Japanese and Korean fall back to `Noto Sans JP`, `SC`, `TC` and `KR`, which
|
|
|
|
|
an app bundles itself if it needs them (`appFontFallbackFor` puts a
|
|
|
|
|
language's own first).
|
|
|
|
|
- **Layout** (`lib/src/layout/`): `WindowSize` (`context.windowSize`) and
|
|
|
|
|
`readableContentMaxWidth`.
|
|
|
|
|
- **Widgets** (`lib/src/widget/`): `showAdaptiveSheet` with `SheetScaffold`;
|
|
|
|
|
`TopGradient`, `ScreenTint`, `ScreenColor`, `TintFrame`, `FramedScreen`
|
feat(learn,todo,train,meditate,ui): the navigation bar flush with the foot, a fade above it
Below medium windows the frame's bar is Material 3 Expressive's again,
flush with the window's foot (decided 7 Nov 2026 by the developer): the
theme's NavigationBar across the whole width, 64 dp in its own colour,
running on beneath the system's bar as Material's does. Right above it a
fade 32 dp high, from the background of the screen in view (the
ScreenTint's, the theme's surface before a screen claims one) made
see-through to that background, so what scrolls on beneath the bar fades
out rather than being cut off; taps pass through it. The rail of wider
windows stays as it was.
halkyon_ui's FloatingNavigationBar becomes FlushNavigationBar, its side
margin, lift and rounded card gone. Its coverOf is now the whole room
content leaves at its end, the system's bar included (the body's bottom
padding: bar, fade and system's bar inside the frame, the system's bar
alone outside it), and floating buttons rise by buttonLiftOf, the same
without the system's bar, which a Scaffold keeps them clear of itself.
Lists, Todo's hour grid and the Plan's sheet keep using coverOf; the
Profile's list no longer adds the system's bar a second time.
Whats-New: The navigation bar sits at the bottom edge again, with a soft fade above it.
Whats-New-De: Die Navigationsleiste sitzt wieder am unteren Rand, mit einem sanften Übergang darüber.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 00:04:18 +01:00
|
|
|
and `TabVisibility`; `FlushNavigationBar`, and `NavigationFrame`, every
|
|
|
|
|
app's frame around its tabs (the rail with the app's icon, the bar flush
|
|
|
|
|
with the foot with a fade above it, a tick on every choice, a status such as a recording under way above
|
2026-10-31 12:12:55 +01:00
|
|
|
the bar), whichever router drives it;
|
2026-10-30 23:52:39 +01:00
|
|
|
`AppLoadingIndicator`, `ButtonLoadingIndicator`, `AppRefreshIndicator`;
|
|
|
|
|
`SectionCard`, `SliverCentered`, `EmptyListMessage`, `CountBadge`,
|
feat(learn): Explore by what a licence allows, a skeleton while the library loads, and an assistant's agreement per provider (ADR 0005, rule 12; ADR 0021, D66)
- Explore filters by what a studyset's licence lets a learner do: adapt
it (no NoDerivatives) and use it commercially (no NonCommercial),
which the instance reads from the release's licence
(ExploreQuery.adaptable, commercial) and the app the same way
(LicenseUse). An instance from before ignores both.
- While the studysets are read, the Library shows shimmering skeletons
of their cards rather than a spinner: halkyon_ui's new Shimmer and
SkeletonBox, still where the system asks for no animations.
- The scope's "Include private studysets" is offered only while the
person has a private studyset.
- An agreement to what goes where is per provider (protocol and host):
agreeing to one assistant agrees to every assistant of that provider,
those granted later too, and the agreement sheet says so. No
migration: it is written on every grant of the provider, so taking
one back keeps it for the others, and read per provider from any of
them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-02 01:09:04 +01:00
|
|
|
`TitleWithKicker`, `CollapsingRow`, `ScrollHidingFab`, `Shimmer` and `SkeletonBox`, `liftWhileDragged`,
|
2026-10-30 23:52:39 +01:00
|
|
|
`ReorderToggle`, `ReorderGrip`; `ChevronField`, `requiredDecoration`,
|
|
|
|
|
`FieldInfoButton`, `CountStepper`, `PaletteColorPicker`, `TextLimits` with
|
2026-10-18 21:46:55 +02:00
|
|
|
`nearLimitCounter`; `confirmDestructiveAction`, `showUndoSnackBar`,
|
|
|
|
|
`showMoreInfoSheet`; `FoundById`; `KeyboardBackOnResume`; `BrandWordmark`
|
|
|
|
|
and `LaunchScreen`, which take the app's word and icon.
|
|
|
|
|
|
|
|
|
|
What belongs to one app stays in it: its own colours (an extension passed to
|
|
|
|
|
`appTheme`), routes, repositories, editors and texts.
|
|
|
|
|
|
|
|
|
|
## Using it in an app
|
|
|
|
|
|
2026-10-19 20:39:09 +02:00
|
|
|
Depend on it by path, within the repository's workspace (an app's packages sit in
|
|
|
|
|
`apps/<app>/`), so a change to the package and to the apps using it is one commit:
|
2026-10-18 21:46:55 +02:00
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
dependencies:
|
|
|
|
|
halkyon_ui:
|
2026-10-19 20:39:09 +02:00
|
|
|
path: ../../../packages/halkyon_ui
|
2026-10-18 21:46:55 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Then set the app up as `example/lib/main.dart` does:
|
|
|
|
|
|
|
|
|
|
```dart
|
|
|
|
|
MaterialApp(
|
|
|
|
|
theme: appTheme(Brightness.light, extensions: [MyColors.light]),
|
|
|
|
|
darkTheme: appTheme(Brightness.dark, extensions: [MyColors.dark]),
|
|
|
|
|
localizationsDelegates: const [
|
|
|
|
|
AppLocalizations.delegate,
|
|
|
|
|
HalkyonUiLocalizations.delegate,
|
|
|
|
|
// material_ui's: flutter_localizations' serve only the SDK's Material.
|
|
|
|
|
...GlobalMaterialLocalizations.delegates,
|
|
|
|
|
],
|
|
|
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
|
|
|
builder: (context, child) => FittedSnackBars(child: child!),
|
|
|
|
|
…
|
|
|
|
|
);
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
and call `registerFontLicenses()` at start. An app bundling the CJK fonts
|
|
|
|
|
declares them in its own `pubspec.yaml` under exactly the names
|
|
|
|
|
`appFontFallback` lists (no `packages/` prefix) and registers their licence
|
|
|
|
|
itself.
|
|
|
|
|
|
|
|
|
|
## Texts
|
|
|
|
|
|
|
|
|
|
`lib/l10n/halkyon_ui_en.arb` is the template (British English, also the
|
|
|
|
|
fallback); `halkyon_ui_de.arb` German, informal "du"; `halkyon_ui_en_US.arb`
|
|
|
|
|
only what American English spells differently; `halkyon_ui_en_GB.arb` empty. A
|
|
|
|
|
new text goes into the template and German together (`test/l10n/` fails
|
|
|
|
|
otherwise). `flutter pub get` writes `lib/l10n/halkyon_ui_localizations*.dart`,
|
2026-10-19 20:39:09 +02:00
|
|
|
which are committed and never edited or
|
2026-10-18 21:46:55 +02:00
|
|
|
formatted by hand.
|
|
|
|
|
|
|
|
|
|
## Checks
|
|
|
|
|
|
|
|
|
|
From the workspace root: `dart analyze --fatal-infos`; then `flutter test` in
|
|
|
|
|
`packages/halkyon_ui` and in `packages/halkyon_ui/example`, whose tests check
|
|
|
|
|
what only an app sees (the font under the name an app finds it by, its
|
|
|
|
|
licence).
|