Files
sync_replay_project/apps/desktop/test/video_view_test.dart
T
foxyzandClaude Opus 5.5 5bc252bf02 Player: sharp video and subtitles at screen size; dev tools: danmaku preview, subtitle lift with a stand-in chat line
- "Sharp video and subtitles" (Settings → Player and the player settings
  card, on by default): the video output renders at the view's physical
  size (debounced, GPU rendering only), so libass, mpv's scaler and the
  shaders work at screen resolution; re-sent after media_kit's own reset
  on new video params, redrawn while paused.
- Dev builds only (Settings → About → Developer): a danmaku preview
  (DanmakuLayer: free lanes in an upper band, density cap with a queue,
  equal crossing time, outlined text, avatars, own-line frame) over the
  real player or a stand-in picture, with samples, a random stream, live
  toasts, every knob and mock subtitles; and "Lift subtitles above the
  chat line and controls": Enter opens a stand-in chat line, bottom
  subtitles move up via mpv sub-pos while it or the control bar is up.
- tool/make_sub_test.sh: a test video with a top \an8 sign, bottom
  dialogue and an SRT track.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 02:19:40 +03:00

55 lines
2.6 KiB
Dart

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:starsync/src/platform/ports/player_host.dart' show RenderMode;
import 'package:starsync/src/screens/home/ui.dart' show devToolsFor;
import 'package:starsync/src/shell/video_view.dart';
// The video view's asks of mpv: the output size ("Sharp video and
// subtitles") and the dev experiment's subtitle lift.
void main() {
group('videoOutputSize', () {
test('the view in physical pixels on the GPU', () {
expect(videoOutputSize(const Size(1280, 720), 1.5, on: true, mode: RenderMode.gpu), (1920, 1080));
expect(videoOutputSize(const Size(384, 216), 2, on: true, mode: RenderMode.gpu), (768, 432));
});
test("the video's own size when off, not on the GPU yet, or in software", () {
expect(videoOutputSize(const Size(1280, 720), 1, on: false, mode: RenderMode.gpu), isNull);
for (final m in [RenderMode.unknown, RenderMode.software, RenderMode.softwareGl]) {
expect(videoOutputSize(const Size(1280, 720), 1, on: true, mode: m), isNull, reason: m.name);
}
expect(videoOutputSize(const Size(4, 4), 1, on: true, mode: RenderMode.gpu), isNull);
});
});
group('subtitleLiftPos', () {
test('a picture filling the view lifts by the controls', () {
// 108 px of controls + 8 px gap in a 1080 px picture: 10.74 %.
final pos = subtitleLiftPos(view: const Size(1920, 1080), videoW: 1920, videoH: 1080, controls: 108);
expect(pos, closeTo(100 - 116 / 1080 * 100, 1e-9));
});
test('a letterbox under the picture counts toward the room', () {
// 2.39:1 in 16:9: 803 px picture, 138 px bar below it.
final none = subtitleLiftPos(view: const Size(1920, 1080), videoW: 1920, videoH: 803, controls: 100);
expect(none, 100);
final some = subtitleLiftPos(view: const Size(1920, 1080), videoW: 1920, videoH: 803, controls: 200);
expect(some, lessThan(100));
});
test('unknown video size: as if it filled the view; never past half', () {
expect(subtitleLiftPos(view: const Size(800, 450), controls: 90), closeTo(100 - 98 / 450 * 100, 1e-9));
expect(subtitleLiftPos(view: const Size(800, 100), controls: 500), 50);
expect(subtitleLiftPos(view: Size.zero, controls: 90), 100);
});
});
test('dev tools: dev versions and debug runs only', () {
expect(devToolsFor(version: '1.3.3-dev.2', debug: false), isTrue);
expect(devToolsFor(version: '0.0.0-dev', debug: false), isTrue);
expect(devToolsFor(version: '1.3.2', debug: true), isTrue);
expect(devToolsFor(version: '1.3.2', debug: false), isFalse);
});
}