Halkyon's shared packages
A pub workspace of the Dart packages Halkyon's apps share: halkyon_ui, Halkyon's look (the theme, fonts, layout and shared widgets, with texts in English and German), halkyon_core's low-level primitives and halkyon_interop's cross-app contracts. Dart 3.13 with LeanCode's lints, configured once at the root; apps take a package by git, pinned to a signed commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
commit
80fa7b9628
1 changed files with 6762 additions and 0 deletions
99
packages/halkyon_ui/test/theme/theme_test.dart
Normal file
99
packages/halkyon_ui/test/theme/theme_test.dart
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
/// WCAG's contrast ratio of two colours, from 1 (none) to 21.
|
||||
double _contrast(Color a, Color b) {
|
||||
final (lighter, darker) = (
|
||||
max(a.computeLuminance(), b.computeLuminance()),
|
||||
min(a.computeLuminance(), b.computeLuminance()),
|
||||
);
|
||||
return (lighter + 0.05) / (darker + 0.05);
|
||||
}
|
||||
|
||||
/// An app's own colours, beside the shared ones.
|
||||
final class const _AppColors(final Color special)
|
||||
extends ThemeExtension<_AppColors> {
|
||||
@override
|
||||
_AppColors copyWith({Color? special}) => _AppColors(special ?? this.special);
|
||||
|
||||
@override
|
||||
_AppColors lerp(_AppColors? other, double t) =>
|
||||
other == null ? this : _AppColors(Color.lerp(special, other.special, t)!);
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('the picker palette', () {
|
||||
test('has the 20 colours content can be given', () {
|
||||
expect(PaletteColor.values, hasLength(20));
|
||||
});
|
||||
|
||||
for (final color in PaletteColor.values) {
|
||||
test(
|
||||
'${color.name}: its text colour is readable on its fill (WCAG AA)',
|
||||
() {
|
||||
expect(
|
||||
_contrast(color.foreground, color.background),
|
||||
greaterThanOrEqualTo(4.5),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
test(
|
||||
'finds a colour by its stored name, and nothing for an unknown one',
|
||||
() {
|
||||
expect(PaletteColor.byName('cobalt'), PaletteColor.cobalt);
|
||||
expect(PaletteColor.byName('ultraviolet'), isNull);
|
||||
expect(PaletteColor.byName(null), isNull);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('the theme', () {
|
||||
for (final brightness in Brightness.values) {
|
||||
test('$brightness: Material 3, with the status colours', () {
|
||||
final theme = appTheme(brightness);
|
||||
|
||||
expect(theme.useMaterial3, isTrue);
|
||||
expect(theme.colorScheme.brightness, brightness);
|
||||
expect(theme.extras, isA<ThemeExtras>());
|
||||
});
|
||||
}
|
||||
|
||||
test("takes an app's own extensions beside the shared ones", () {
|
||||
const colors = _AppColors(Color(0xFF123456));
|
||||
|
||||
final theme = appTheme(Brightness.light, extensions: [colors]);
|
||||
|
||||
expect(theme.extension<_AppColors>(), colors);
|
||||
expect(theme.extras, ThemeExtras.light);
|
||||
});
|
||||
|
||||
test('light: cobalt is the primary colour, copper the accent', () {
|
||||
final scheme = appTheme(Brightness.light).colorScheme;
|
||||
|
||||
expect(scheme.primary, Brand.primary);
|
||||
expect(scheme.tertiary, Brand.accent);
|
||||
});
|
||||
|
||||
test("dark: the primary colour's text stays readable", () {
|
||||
final scheme = appTheme(Brightness.dark).colorScheme;
|
||||
|
||||
expect(
|
||||
_contrast(scheme.onPrimary, scheme.primary),
|
||||
greaterThanOrEqualTo(4.5),
|
||||
);
|
||||
expect(
|
||||
_contrast(scheme.onSurface, scheme.surface),
|
||||
greaterThanOrEqualTo(4.5),
|
||||
);
|
||||
});
|
||||
|
||||
test("the navigation bar is Material 3 Expressive's shorter one", () {
|
||||
expect(appTheme(Brightness.light).navigationBarTheme.height, 64);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue