fix(player): 使用雪碧图预热首帧兜底

This commit is contained in:
Zhou Weidong committed 2026-10-26 14:21:52 +08:00
1 parent 48b4e67d34
commit 70d8e0f982
13 files changed
+207 -322

No files matched your search

+38 -94
View File
@@ -5,8 +5,9 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/data/services/sprite_thumbnail_asset_loader.dart';
import 'package:fruitshorts/core/widgets/remote_image.dart';
import 'package:fruitshorts/core/data/services/sprite_thumbnail_axis.dart';
import 'package:fruitshorts/pages/player/widgets/player_opening_frame.dart';
import 'package:fruitshorts/pages/player/widgets/scrub_preview_card.dart';
const String _spriteVtt = '''
WEBVTT
@@ -16,49 +17,46 @@ sprite_001.jpg#xywh=0,0,160,90
''';
void main() {
test('should_return_no_opening_frame_when_thumbnails_url_is_empty', () {
expect(playerOpeningFrame(null, posterUrl: ' '), isNull);
expect(playerOpeningFrame(' '), isNull);
testWidgets('should_return_no_opening_frame_when_thumbnails_is_empty', (
tester,
) async {
final service = SpriteThumbnailAxisService(loader: _FakeSpriteLoader());
addTearDown(service.dispose);
expect(playerOpeningFrame(null, spriteSource: service), isNull);
expect(playerOpeningFrame(' ', spriteSource: service), isNull);
});
test('should_keep_opening_frame_when_only_poster_is_available', () {
expect(
playerOpeningFrame(null, posterUrl: 'https://cdn.test/poster.jpg'),
isA<PlayerOpeningFrame>(),
);
});
testWidgets('should_load_and_reuse_first_sprite_frame', (tester) async {
testWidgets('should_render_prewarmed_zero_frame_from_shared_cache', (
tester,
) async {
final loader = _FakeSpriteLoader();
final cache = OpeningFrameCache();
addTearDown(cache.clear);
final service = SpriteThumbnailAxisService(loader: loader);
addTearDown(service.dispose);
const url = 'https://cdn.test/thumbnails.vtt';
await service.prepareAt(url, Duration.zero);
final first = await cache.load(
'https://cdn.test/thumbnails.vtt',
loader: loader,
);
final second = await cache.load(
'https://cdn.test/thumbnails.vtt',
loader: loader,
await tester.pumpWidget(
MaterialApp(
home: PlayerOpeningFrame(thumbnailsUrl: url, spriteSource: service),
),
);
await tester.pump();
expect(first, isNotNull);
expect(second, same(first));
expect(find.byKey(const Key('player-opening-sprite')), findsOneWidget);
expect(loader.vttCalls, 1);
expect(loader.spriteCalls, ['sprite_001.jpg']);
});
testWidgets('should_render_decoded_opening_frame', (tester) async {
final loader = _FakeSpriteLoader();
final cache = OpeningFrameCache();
addTearDown(cache.clear);
testWidgets('should_load_sprite_when_not_prewarmed', (tester) async {
final service = SpriteThumbnailAxisService(loader: _FakeSpriteLoader());
addTearDown(service.dispose);
await tester.pumpWidget(
MaterialApp(
home: PlayerOpeningFrame(
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
loader: loader,
cache: cache,
spriteSource: service,
),
),
);
@@ -67,80 +65,26 @@ void main() {
expect(find.byKey(const Key('player-opening-sprite')), findsOneWidget);
});
testWidgets('should_show_poster_while_sprite_is_loading', (tester) async {
final cache = OpeningFrameCache();
addTearDown(cache.clear);
testWidgets('should_use_same_fit_for_sprite_and_video', (tester) async {
final service = SpriteThumbnailAxisService(loader: _FakeSpriteLoader());
addTearDown(service.dispose);
const url = 'https://cdn.test/thumbnails.vtt';
await service.prepareAt(url, Duration.zero);
await tester.pumpWidget(
MaterialApp(
home: PlayerOpeningFrame(
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
posterUrl: 'https://cdn.test/poster.jpg',
loader: _FakeSpriteLoader(),
cache: cache,
thumbnailsUrl: url,
spriteSource: service,
fit: BoxFit.contain,
),
),
);
expect(find.byKey(const Key('player-opening-poster')), findsOneWidget);
});
testWidgets('should_use_surface_fit_without_extra_frame_constraint', (
tester,
) async {
await tester.pumpWidget(
const MaterialApp(
home: PlayerOpeningFrame(
posterUrl: 'https://cdn.test/poster.jpg',
),
),
final preview = tester.widget<SpriteCropPreview>(
find.byKey(const Key('player-opening-sprite')),
);
final poster = tester.widget<RemoteImage>(
find.byKey(const Key('player-opening-poster')),
);
expect(poster.fit, BoxFit.cover);
expect(find.byType(AspectRatio), findsNothing);
});
test('should_forward_video_fit_to_opening_frame', () {
final frame = playerOpeningFrame(
null,
posterUrl: 'https://cdn.test/poster.jpg',
fit: BoxFit.contain,
);
expect(frame, isA<PlayerOpeningFrame>());
expect((frame! as PlayerOpeningFrame).fit, BoxFit.contain);
});
testWidgets('should_reuse_decoded_sprite_when_parent_rebuilds', (
tester,
) async {
final loader = _FakeSpriteLoader();
final cache = OpeningFrameCache();
addTearDown(cache.clear);
Widget build() => MaterialApp(
home: PlayerOpeningFrame(
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
posterUrl: 'https://cdn.test/poster.jpg',
loader: loader,
cache: cache,
),
);
await tester.pumpWidget(build());
await tester.pumpAndSettle();
expect(loader.vttCalls, 1);
expect(loader.spriteCalls, hasLength(1));
await tester.pumpWidget(build());
await tester.pumpAndSettle();
expect(loader.vttCalls, 1);
expect(loader.spriteCalls, hasLength(1));
expect(find.byKey(const Key('player-opening-sprite')), findsOneWidget);
expect(preview.fit, BoxFit.contain);
});
}
+3 -6
View File
@@ -67,13 +67,11 @@ void main() {
await tester.pump();
expect(loader.calls, 1);
expect(find.byKey(const Key('scrub-preview-poster')), findsOneWidget);
expect(find.byKey(const Key('scrub-preview-background')), findsOneWidget);
expect(find.byKey(const Key('scrub-preview-sprite')), findsNothing);
});
testWidgets('should_keep_poster_when_axis_and_local_frame_both_fail', (
tester,
) async {
testWidgets('should_keep_background_when_frames_both_fail', (tester) async {
final loader = _CountingThumbnailLoader();
final localService = _localService(loader);
final axis = _FakeAxisSource(axisReady: true);
@@ -90,7 +88,7 @@ void main() {
await tester.pump();
expect(loader.calls, 1);
expect(find.byKey(const Key('scrub-preview-poster')), findsOneWidget);
expect(find.byKey(const Key('scrub-preview-background')), findsOneWidget);
expect(find.byKey(const Key('scrub-preview-sprite')), findsNothing);
expect(find.byKey(const Key('scrub-preview-frame')), findsNothing);
});
@@ -109,7 +107,6 @@ Widget _card({
spriteAxisService: axis,
thumbnailsUrl: thumbnailsUrl,
episodeId: 'episode-1',
posterUrl: '',
position: const Duration(seconds: 1),
duration: const Duration(seconds: 10),
),