halkyon/packages/halkyon_ui/README.md
Tizian 「ティツィアーン」 60d53ed262
feat(ui,learn): the navigation bar in the colour of the screen in view
The developer's review of 8 Nov 2026: the bar follows the screen in view
rather than one colour per app, so a Todo project of its own colour gives
the bar that colour while it shows. The wave, the chosen destination's
icon and label and its indicator take ScreenTint.color, the colour the
screen in view claims through its TopGradient; the frame's accent, the
app's colour, stays only for the moment before any screen claims one,
since ScreenTint itself starts at cobalt, which would be wrong for Todo,
Train and Meditate. Learn's tabs claim cobalt, their wash, so its bar is
cobalt there now, not purple.

A colour changing on the same tab (a project opening) passes into the
next over 300 ms, at once with animations off. A wave paints in that
colour as it goes: it starts in the colour of the screen being left, as
the arriving one claims its own only once it shows, a frame later, and
passes into it with the rest of the bar.

A person's colours may be light, so the chosen destination's colour is
made legible (readableTone, halkyon_ui): a palette colour starts from its
own text tone as Todo's dates take it (its outline in light mode, its
fill in dark), any other colour from itself, then darkens towards black
in light mode and lightens towards white in dark, only until it reads at
4.5:1 on the bar and on its indicator. Every palette colour is tested in
both themes, on the neutral and the tinted surface. This also lifts
Learn's label, which read at about 3:1.

The debug section gains Bar surface, neutral or tinted: tinted mixes 6 %
of the screen's colour into the bar's own surface in light mode and 8 %
in dark, changing with it. Neutral by default, and in the shipping style.

Whats-New: The navigation bar takes the colour of the screen you're on, such as a project's own.
Whats-New-De: Die Navigationsleiste nimmt die Farbe des Bildschirms an, auf dem du bist, etwa die eines Projekts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-08 11:48:38 +01:00

4.5 KiB

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 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, its rounded top corners and the wave a tap sends over it in the colour of the screen in view, the tab chosen in that colour made legible (readableTone), shippingNavigationBarStyle, switched live in a debug build's NavigationBarDebugSection, a tick on every choice, a status such as a recording under way above the bar), whichever router drives it; AppLoadingIndicator, ButtonLoadingIndicator, AppRefreshIndicator; SectionCard, SliverCentered, EmptyListMessage, CountBadge, TitleWithKicker, CollapsingRow, ScrollHidingFab, Shimmer and SkeletonBox, liftWhileDragged, ReorderToggle, ReorderGrip; ChevronField, requiredDecoration, FieldInfoButton, CountStepper, PaletteColorPicker, TextLimits with 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

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:

dependencies:
  halkyon_ui:
    path: ../../../packages/halkyon_ui

Then set the app up as example/lib/main.dart does:

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, which are committed and never edited or 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).