fix(player): 使用高清首帧并稳定切集占位

This commit is contained in:
Zhou Weidong committed 2026-10-26 14:58:00 +08:00
1 parent 0cb0ab0613
commit 2fef7470e0
10 files changed
+258 -33

No files matched your search

+6
View File
@@ -1037,6 +1037,8 @@ void main() {
accessible: false,
accessType: PlayTicket.coinRequired,
unlockCoin: 30,
posterUrl: '/files/locked-first-frame.jpg',
thumbnailsUrl: '/files/locked-thumbnails.vtt',
),
),
);
@@ -1049,6 +1051,8 @@ void main() {
expect(find.byKey(const Key('progress-inactive')), findsOneWidget);
expect(find.byType(Slider), findsNothing);
expect(find.byKey(const Key('player-single-placeholder')), findsNothing);
expect(find.byKey(const Key('player-opening-poster')), findsNothing);
expect(find.byKey(const Key('player-opening-sprite')), findsNothing);
expect(find.byKey(const Key('player-video-crossfade')), findsNothing);
expect(find.byKey(const Key('player-video-layer')), findsNothing);
expect(
@@ -1487,6 +1491,8 @@ const _lockedDrama = Drama(
isFree: false,
locked: true,
videoUrl: 'https://example.test/locked-demo-1.mp4',
posterUrl: '/files/locked-first-frame.jpg',
thumbnailsUrl: '/files/locked-thumbnails.vtt',
),
Episode(
id: 'locked-demo-2',
+29
View File
@@ -393,6 +393,35 @@ void main() {
expect(logic.sessionEpisodes.first.videoUrl, 'file:///local/signal-1.mp4');
});
test('should_write_ticket_poster_url_into_session_episode', () async {
final logic = _logic(
FakeWatchHistory(),
playback: FakePlaybackRepository(
ticket: const PlayTicket(
episodeId: 'signal-1',
accessible: true,
accessType: PlayTicket.free,
playUrl: '/files/signal-1.mp4',
posterUrl: '/files/transcoded/signal-1/poster.jpg',
),
),
);
logic.attach(
PlayerPage(drama: _drama('signal'), initialIndex: 0),
isMounted: () => true,
);
logic.start(factory: _RecordingFactory().create, coordinator: PlaybackCoordinator());
await _drain(logic);
expect(
logic.sessionEpisodes.first.posterUrl,
'/files/transcoded/signal-1/poster.jpg',
);
logic.dispose();
await _drain(logic);
});
group('surface flags', () {
test('should_set_immersive_when_picture_in_picture_callback_fires', () async {
final factory = _RecordingFactory();
@@ -17,6 +17,53 @@ sprite_001.jpg#xywh=0,0,160,90
''';
void main() {
test('should_choose_poster_before_thumbnails_when_both_are_available', () {
final service = SpriteThumbnailAxisService(loader: _FakeSpriteLoader());
addTearDown(service.dispose);
final frame =
playerOpeningFrame(
'https://cdn.test/thumbnails.vtt',
posterUrl: 'https://cdn.test/poster.jpg',
spriteSource: service,
fit: BoxFit.cover,
)
as PlayerOpeningFrame;
expect(frame.posterUrl, 'https://cdn.test/poster.jpg');
expect(frame.thumbnailsUrl, 'https://cdn.test/thumbnails.vtt');
expect(frame.fit, BoxFit.cover);
expect(
playerOpeningFallback(
posterUrl: frame.posterUrl,
thumbnailsUrl: frame.thumbnailsUrl,
),
PlayerOpeningFallback.poster,
);
});
testWidgets('should_use_poster_without_decoding_sprite_when_poster_exists', (
tester,
) async {
final loader = _FakeSpriteLoader();
final service = SpriteThumbnailAxisService(loader: loader);
addTearDown(service.dispose);
await tester.pumpWidget(
MaterialApp(
home: PlayerOpeningFrame(
posterUrl: 'https://cdn.test/poster.jpg',
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
spriteSource: service,
),
),
);
expect(find.byKey(const Key('player-opening-poster')), findsOneWidget);
expect(find.byKey(const Key('player-opening-sprite')), findsNothing);
expect(loader.vttCalls, 0);
});
testWidgets('should_return_no_opening_frame_when_thumbnails_is_empty', (
tester,
) async {