feat(jellyfin): From Jellyfin once signed in, the panel in the glow's colour, adding the words listed
All checks were successful
CI / check (push) Successful in 16m0s
CI / deploy (push) Successful in 1m13s

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>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-13 21:03:37 +02:00
commit d552f8bea0
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -0,0 +1,62 @@
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));
});
}