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

+43 -4
View File
@@ -146,7 +146,9 @@ class _PlayerPageState extends State<PlayerPage>
_thumbnailService = PlaybackThumbnailService(
sourceResolver: _resolveThumbnailSource,
);
_spriteAxisService = SpriteThumbnailAxisService();
_spriteAxisService = SpriteThumbnailAxisService(
spriteCacheCapacity: 8,
)..addListener(_handleSpriteFrameChanged);
WidgetsBinding.instance.addObserver(this);
logic.start(
factory: context.read<PlayerFactory>(),
@@ -266,7 +268,9 @@ class _PlayerPageState extends State<PlayerPage>
void dispose() {
WidgetsBinding.instance.removeObserver(this);
appRouteObserver.unsubscribe(this);
_spriteAxisService.dispose();
_spriteAxisService
..removeListener(_handleSpriteFrameChanged)
..dispose();
_thumbnailService.dispose();
logic.dispose();
super.dispose();
@@ -369,6 +373,30 @@ class _PlayerPageState extends State<PlayerPage>
_chromeVisible = true;
}
void _handleSpriteFrameChanged() {
if (mounted) setState(() {});
}
void _prewarmAdjacentThumbnails() {
final current = logic.session.currentIndex;
final indices = <int?>[
current,
logic.previousVisibleIndex(current),
logic.nextVisibleIndex(current),
];
for (final index in indices) {
if (index == null || index < 0 || index >= logic.sessionEpisodes.length) {
continue;
}
final thumbnailsUrl = logic.sessionEpisodes[index].thumbnailsUrl;
if (thumbnailsUrl != null) {
unawaited(
_spriteAxisService.prepareAt(thumbnailsUrl, Duration.zero),
);
}
}
}
void _restoreFeedChrome() {
if (!mounted) return;
setState(() {
@@ -451,6 +479,7 @@ class _PlayerPageState extends State<PlayerPage>
final content = AnimatedBuilder(
animation: logic.session,
builder: (context, _) {
_prewarmAdjacentThumbnails();
final pages = NotificationListener<ScrollNotification>(
onNotification: _handlePageScroll,
child: PageView.builder(
@@ -590,6 +619,15 @@ class _PlayerPageState extends State<PlayerPage>
final videoFit = theater ? BoxFit.contain : BoxFit.cover;
final preparedFrameAvailable =
selected && logic.session.reusedWarmAt(index);
final thumbnailsUrl = episode.thumbnailsUrl;
final openingFrameReady =
thumbnailsUrl != null &&
_spriteAxisService.cachedFrameAt(thumbnailsUrl, Duration.zero) != null;
if (thumbnailsUrl != null) {
unawaited(
_spriteAxisService.prepareAt(thumbnailsUrl, Duration.zero),
);
}
final locked = logic.session.isLocked || episode.locked;
if (selected &&
videoPort != null &&
@@ -617,9 +655,10 @@ class _PlayerPageState extends State<PlayerPage>
theater: theater,
holdOpeningUntilFirstFrame: logic.session.userWantsPlay,
preparedFrameAvailable: preparedFrameAvailable,
openingFrameReady: openingFrameReady,
openingFrame: playerOpeningFrame(
episode.thumbnailsUrl,
posterUrl: drama.posterUrl,
thumbnailsUrl,
spriteSource: _spriteAxisService,
fit: videoFit,
),
),