Add material's entry is now From Jellyfin (Aus Jellyfin), with a play icon rather than a TV, as it plays music too, and shows only once the device is signed in to a server in Settings, as the assistant shows only once switched on; Settings says where it then is. The screen it opens is called Jellyfin, and its search finds music too. The words' panel takes the glow's colour as the scene changes: each copy the glow takes (every 3 s) gives its average, no lighter than 35 % so the text stays readable, as strong as the glow and fading into the next as it does. In the light theme, which has no glow, the panel is tinted from it while the pointer is over it. What lights up in the panel takes a scheme made from the same colour; the episode's thumbnail is no longer used. While the studyset holds none of the video's words, the study button adds the words listed (Add 11 words, as the filter shows them), tagged as a word added alone is; afterwards it studies them, and its menu adds the new ones listed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
62 lines
1.7 KiB
Dart
62 lines
1.7 KiB
Dart
import 'dart:async';
|
|
import 'dart:typed_data';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:halkyon_learn_flutter/src/feature/jellyfin/widget/ambient_glow.dart';
|
|
import 'package:material_ui/material_ui.dart';
|
|
|
|
/// An image one pixel high, of [colors] in turn.
|
|
Future<ui.Image> pixels(List<Color> colors) {
|
|
final bytes = Uint8List.fromList([
|
|
for (final color in colors) ...[
|
|
(color.r * 255).round(),
|
|
(color.g * 255).round(),
|
|
(color.b * 255).round(),
|
|
(color.a * 255).round(),
|
|
],
|
|
]);
|
|
final done = Completer<ui.Image>();
|
|
ui.decodeImageFromPixels(
|
|
bytes,
|
|
colors.length,
|
|
1,
|
|
ui.PixelFormat.rgba8888,
|
|
done.complete,
|
|
);
|
|
return done.future;
|
|
}
|
|
|
|
void main() {
|
|
testWidgets("a picture's colour is its pixels' average, the clear ones "
|
|
'left out', (tester) async {
|
|
final colour = await tester.runAsync(() async {
|
|
final image = await pixels(const [
|
|
Color(0xFFFF0000),
|
|
Color(0xFF0000FF),
|
|
Color(0x00FFFFFF),
|
|
]);
|
|
try {
|
|
return await averageColourOf(image);
|
|
} finally {
|
|
image.dispose();
|
|
}
|
|
});
|
|
|
|
expect(colour, const Color(0xFF7F007F));
|
|
});
|
|
|
|
test('the panel takes the colour no lighter than text stays readable '
|
|
'on, keeping its hue', () {
|
|
final snow = panelColourOf(const Color(0xFFF4F8FF));
|
|
final night = panelColourOf(const Color(0xFF101830));
|
|
|
|
expect(HSLColor.fromColor(snow).lightness, closeTo(0.35, 0.01));
|
|
expect(
|
|
HSLColor.fromColor(snow).hue,
|
|
closeTo(HSLColor.fromColor(const Color(0xFFF4F8FF)).hue, 1),
|
|
);
|
|
// Dark enough already: as it is.
|
|
expect(night, const Color(0xFF101830));
|
|
});
|
|
}
|