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

+46 -9
View File
@@ -127,6 +127,7 @@ class _PlayerPageState extends State<PlayerPage>
DateTime? _lastDoubleTapAt;
DateTime? _swipeStartedAt;
bool _swipePrewarmCaptured = false;
final Set<String> _precachedPosterUrls = {};
/// 收藏切换后的本地增量:基准是详情快照,切换成功按服务端状态 ±1。
final Map<String, int> _favoriteDelta = {};
@@ -376,7 +377,7 @@ class _PlayerPageState extends State<PlayerPage>
if (mounted) setState(() {});
}
void _prewarmAdjacentThumbnails() {
void _prewarmAdjacentFrames() {
final current = logic.session.currentIndex;
final indices = <int?>[
current,
@@ -387,9 +388,24 @@ class _PlayerPageState extends State<PlayerPage>
if (index == null || index < 0 || index >= logic.sessionEpisodes.length) {
continue;
}
final thumbnailsUrl = logic.sessionEpisodes[index].thumbnailsUrl;
if (thumbnailsUrl != null &&
!logic.isEpisodeLocked(logic.sessionEpisodes[index])) {
final episode = logic.sessionEpisodes[index];
if (logic.isEpisodeLocked(episode)) continue;
final posterUrl = episode.posterUrl?.trim() ?? '';
if (posterUrl.isNotEmpty) {
final imageUrl = AppConfig.mediaUrl(posterUrl);
if (_precachedPosterUrls.add(imageUrl)) {
unawaited(
precacheImage(NetworkImage(imageUrl), context).catchError((
Object _,
) {
_precachedPosterUrls.remove(imageUrl);
}),
);
}
continue;
}
final thumbnailsUrl = episode.thumbnailsUrl;
if (thumbnailsUrl != null && thumbnailsUrl.isNotEmpty) {
unawaited(_spriteAxisService.prepareAt(thumbnailsUrl, Duration.zero));
}
}
@@ -477,7 +493,7 @@ class _PlayerPageState extends State<PlayerPage>
final content = AnimatedBuilder(
animation: logic.session,
builder: (context, _) {
_prewarmAdjacentThumbnails();
_prewarmAdjacentFrames();
final pages = NotificationListener<ScrollNotification>(
onNotification: _handlePageScroll,
child: PageView.builder(
@@ -592,12 +608,17 @@ class _PlayerPageState extends State<PlayerPage>
final displayed = widget.homeMode
? logic.displayEpisode(drama, sessionEpisode)
: sessionEpisode;
final episode =
final needsSessionThumbnails =
(displayed.thumbnailsUrl == null || displayed.thumbnailsUrl!.isEmpty) &&
sessionEpisode.thumbnailsUrl != null
sessionEpisode.thumbnailsUrl != null;
final needsSessionPoster =
(displayed.posterUrl == null || displayed.posterUrl!.isEmpty) &&
sessionEpisode.posterUrl != null;
final episode = needsSessionThumbnails || needsSessionPoster
? displayed.withVideoUrl(
displayed.videoUrl,
thumbnailsUrl: sessionEpisode.thumbnailsUrl,
posterUrl: sessionEpisode.posterUrl,
)
: displayed;
final selected = index == logic.session.currentIndex;
@@ -621,12 +642,19 @@ class _PlayerPageState extends State<PlayerPage>
final theater = logic.pip || logic.pipPreparing;
final videoFit = theater ? BoxFit.contain : BoxFit.cover;
final preparedFrameAvailable =
selected && !locked && logic.session.reusedWarmAt(index);
!locked &&
videoReady &&
(selected
? logic.session.reusedWarmAt(index)
: logic.session.preparedPlayerAt(index) != null);
final warmSlotReused = logic.session.reusedWarmAt(index);
final thumbnailsUrl = episode.thumbnailsUrl;
final posterUrl = episode.posterUrl;
final posterReady = posterUrl?.trim().isNotEmpty ?? false;
final openingFrameReady =
thumbnailsUrl != null &&
_spriteAxisService.cachedFrameAt(thumbnailsUrl, Duration.zero) != null;
if (thumbnailsUrl != null) {
if (!posterReady && thumbnailsUrl != null) {
unawaited(_spriteAxisService.prepareAt(thumbnailsUrl, Duration.zero));
}
if (selected &&
@@ -654,7 +682,15 @@ class _PlayerPageState extends State<PlayerPage>
videoUrl: videoPort?.controller.dataSource ?? episode.videoUrl,
theater: theater,
warmFrameAvailable: preparedFrameAvailable,
warmSlotReused: warmSlotReused,
thumbnailReady: openingFrameReady,
posterReady: posterReady,
fallback: handoffPort != null
? PlayerOpeningFallback.handoff
: playerOpeningFallback(
posterUrl: posterUrl,
thumbnailsUrl: thumbnailsUrl,
),
waitForPlaybackFrame: logic.session.userWantsPlay,
placeholder: locked
? null
@@ -665,6 +701,7 @@ class _PlayerPageState extends State<PlayerPage>
)
: playerOpeningFrame(
thumbnailsUrl,
posterUrl: posterUrl,
spriteSource: _spriteAxisService,
fit: videoFit,
),