feat(jellyfin): the player as players are, with the settings under a cog
The Watch screen's player takes the shape people know from players, YouTube's first: the picture set in from every side with rounded corners, so the glow of its colours shows all around it, and over it play or pause in the middle with 10 seconds back and on beside it, and along its foot where the video is (0:05 ──── 23:47) and a cog. The controls fade out while it plays and the pointer rests, and come back as it moves, on a tap with a finger, on a jump and while paused. The cog opens a panel inside the picture, so nothing runs off the window: Pause after each line, the subtitles, the translation and the sound, each track named by its language in the app's words, and the keyboard shortcuts. The buttons for the line before, again and the next sit beside the subtitles they act on, no longer looking like a player's skip to the next video. Keys are YouTube's (Space or K, J and L, the arrows, 0 to 9, Home, End) with Shift and the arrows for lines, R, P and Esc; ? lists them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
96cbd912de
commit
48a9564231
1 changed files with 1032 additions and 299 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:halkyon_learn_flutter/src/core/content/rich_content.dart';
|
||||
|
|
@ -187,8 +188,9 @@ void main() {
|
|||
expect(find.text('A form of 待つ'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('the next line, the one before and the same again play from '
|
||||
'their start; a line can end with a pause', (tester) async {
|
||||
testWidgets('the next line and the one before play from their start, the '
|
||||
'one shown from its start once under way; a line can end with a '
|
||||
'pause', (tester) async {
|
||||
await watch(tester);
|
||||
await playTo(tester, const Duration(seconds: 7));
|
||||
|
||||
|
|
@ -197,7 +199,9 @@ void main() {
|
|||
expect(players.last!.state.value.position, const Duration(seconds: 11));
|
||||
expect(players.last!.state.value.playing, isTrue);
|
||||
|
||||
await tester.tap(find.byTooltip('Repeat line'));
|
||||
// Under way: the one shown again, from its start.
|
||||
await playTo(tester, const Duration(seconds: 14));
|
||||
await tester.tap(find.byTooltip('Previous line'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(players.last!.state.value.position, const Duration(seconds: 11));
|
||||
|
||||
|
|
@ -205,6 +209,8 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
expect(players.last!.state.value.position, const Duration(seconds: 6));
|
||||
|
||||
await tester.tap(find.byTooltip('Settings'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('Pause after each line'));
|
||||
await tester.pumpAndSettle();
|
||||
await playTo(tester, const Duration(milliseconds: 9900));
|
||||
|
|
@ -277,8 +283,10 @@ void main() {
|
|||
);
|
||||
expect(players.last!.selectedAudio?.id, 'c');
|
||||
|
||||
await tester.tap(find.byTooltip('Audio and subtitles'));
|
||||
await tester.tap(find.byTooltip('Settings'));
|
||||
await tester.pumpAndSettle();
|
||||
// Tracks are named by their language, plainly.
|
||||
expect(find.text('Japanese'), findsWidgets);
|
||||
await tester.tap(find.text('Audio'));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text('German'));
|
||||
|
|
@ -364,6 +372,83 @@ void main() {
|
|||
expect(playing.state.value.position, const Duration(minutes: 2));
|
||||
});
|
||||
|
||||
testWidgets('the player has play or pause with 10 seconds back and on '
|
||||
'beside it, and where it is from 0:00 to its length', (tester) async {
|
||||
await watch(tester);
|
||||
await playTo(tester, const Duration(minutes: 1));
|
||||
expect(find.text('1:00'), findsOneWidget);
|
||||
expect(find.text('24:00'), findsOneWidget);
|
||||
|
||||
await tester.tap(find.byTooltip('10 seconds on'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(players.last!.state.value.position, const Duration(seconds: 70));
|
||||
await tester.tap(find.byTooltip('10 seconds back'));
|
||||
await tester.tap(find.byTooltip('10 seconds back'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(players.last!.state.value.position, const Duration(seconds: 50));
|
||||
});
|
||||
|
||||
testWidgets("YouTube's keys work, the lines' too, and ? lists them", (
|
||||
tester,
|
||||
) async {
|
||||
await watch(tester);
|
||||
await playTo(tester, const Duration(minutes: 1));
|
||||
Duration at() => players.last!.state.value.position;
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.keyL);
|
||||
expect(at(), const Duration(seconds: 70));
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.keyJ);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowLeft);
|
||||
expect(at(), const Duration(seconds: 55));
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.digit5);
|
||||
expect(at(), const Duration(minutes: 12));
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.home);
|
||||
expect(at(), Duration.zero);
|
||||
|
||||
await playTo(tester, const Duration(seconds: 7));
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft);
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight);
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft);
|
||||
await tester.pumpAndSettle();
|
||||
expect(at(), const Duration(seconds: 11));
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.keyP);
|
||||
await tester.pumpAndSettle();
|
||||
await playTo(tester, const Duration(milliseconds: 14900));
|
||||
expect(players.last!.state.value.playing, isFalse);
|
||||
|
||||
await tester.sendKeyDownEvent(LogicalKeyboardKey.slash, character: '?');
|
||||
await tester.sendKeyUpEvent(LogicalKeyboardKey.slash);
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Keyboard shortcuts'), findsOneWidget);
|
||||
expect(find.text('Previous or next line'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('the controls fade out while it plays and the pointer rests, '
|
||||
'and come back while paused', (tester) async {
|
||||
await watch(tester);
|
||||
double shown() => tester
|
||||
.widget<AnimatedOpacity>(
|
||||
find
|
||||
.ancestor(
|
||||
of: find.byTooltip('10 seconds on'),
|
||||
matching: find.byType(AnimatedOpacity),
|
||||
)
|
||||
.first,
|
||||
)
|
||||
.opacity;
|
||||
expect(shown(), 1);
|
||||
|
||||
await tester.tap(find.byTooltip('Play'));
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(seconds: 4));
|
||||
expect(shown(), 0);
|
||||
|
||||
await tester.sendKeyEvent(LogicalKeyboardKey.space);
|
||||
await tester.pump();
|
||||
expect(shown(), 1);
|
||||
});
|
||||
|
||||
testWidgets('on a phone the words are below the video', (tester) async {
|
||||
await watch(tester, size: const Size(412, 915));
|
||||
await playTo(tester, const Duration(seconds: 2));
|
||||
|
|
|
|||
Loading…
Reference in a new issue