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>
99 lines
3.1 KiB
Dart
99 lines
3.1 KiB
Dart
import 'dart:convert';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:halkyon_ui/halkyon_ui.dart';
|
|
import 'package:halkyon_ui_example/main.dart';
|
|
import 'package:material_ui/material_ui.dart';
|
|
|
|
/// How many pixels [text] inks in [family] at [weight]: heavier strokes ink
|
|
/// more.
|
|
Future<int> ink(String text, String family, FontWeight weight) async {
|
|
final painter = TextPainter(
|
|
text: TextSpan(
|
|
text: text,
|
|
style: TextStyle(
|
|
fontFamily: family,
|
|
fontSize: 40,
|
|
fontWeight: weight,
|
|
color: const Color(0xFF000000),
|
|
),
|
|
),
|
|
textDirection: TextDirection.ltr,
|
|
)..layout();
|
|
final recorder = ui.PictureRecorder();
|
|
painter.paint(Canvas(recorder), Offset.zero);
|
|
final image = await recorder.endRecording().toImage(
|
|
painter.width.ceil(),
|
|
painter.height.ceil(),
|
|
);
|
|
final pixels = (await image.toByteData())!;
|
|
var inked = 0;
|
|
for (var alpha = 3; alpha < pixels.lengthInBytes; alpha += 4) {
|
|
if (pixels.getUint8(alpha) > 128) {
|
|
inked++;
|
|
}
|
|
}
|
|
return inked;
|
|
}
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test("an app finds the package's Noto Sans under the theme's name, and "
|
|
'draws every weight with it', () async {
|
|
final manifest = jsonDecode(
|
|
await rootBundle.loadString('FontManifest.json'),
|
|
) as List<Object?>;
|
|
final noto = manifest.cast<Map<String, Object?>>().singleWhere(
|
|
(font) => font['family'] == appFontFamily,
|
|
);
|
|
final assets = [
|
|
for (final font
|
|
in (noto['fonts']! as List<Object?>).cast<Map<String, Object?>>())
|
|
font['asset']! as String,
|
|
];
|
|
expect(
|
|
assets,
|
|
contains('packages/halkyon_ui/assets/fonts/NotoSans-Variable.ttf'),
|
|
);
|
|
|
|
// Loaded as the engine loads an app's fonts as it starts: by the
|
|
// manifest's family and files.
|
|
final loader = FontLoader(appFontFamily);
|
|
for (final asset in assets) {
|
|
loader.addFont(rootBundle.load(asset));
|
|
}
|
|
await loader.load();
|
|
const text = 'Ἀθῆναι Halkyon';
|
|
final regular = await ink(text, appFontFamily, FontWeight.w400);
|
|
final bold = await ink(text, appFontFamily, FontWeight.w700);
|
|
expect(bold, greaterThan(regular * 1.2));
|
|
});
|
|
|
|
test("Noto Sans's licence joins the app's licence list", () async {
|
|
registerFontLicenses();
|
|
|
|
final notices = [
|
|
await for (final entry in LicenseRegistry.licenses)
|
|
if (entry.packages.contains('Noto Sans')) entry,
|
|
];
|
|
expect(notices, hasLength(1));
|
|
expect(
|
|
notices.single.paragraphs.map((paragraph) => paragraph.text).join(),
|
|
contains('SIL OPEN FONT LICENSE'),
|
|
);
|
|
});
|
|
|
|
testWidgets("the app speaks German with the package's texts", (tester) async {
|
|
await tester.pumpWidget(const ExampleApp(locale: Locale('de')));
|
|
|
|
expect(find.text('Halkyon'), findsOneWidget);
|
|
expect(find.text('Example'), findsOneWidget);
|
|
await tester.tap(find.text('Delete'));
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('Abbrechen'), findsOneWidget);
|
|
});
|
|
}
|