feat(player): 保持屏幕常亮并自动恢复播放

This commit is contained in:
Zhou Weidong committed 2026-10-22 10:17:43 +08:00
1 parent 5bf10221a8
commit a25c500371
7 files changed
+273 -1

No files matched your search

@@ -92,6 +92,7 @@ class PlaybackSession extends ChangeNotifier {
}
return slot.player;
}
bool get loading => _loading;
bool get userWantsPlay => _userWantsPlay;
bool get canAutoAdvance => _mayPlay && !_loading && active != null;
@@ -103,6 +104,10 @@ class PlaybackSession extends ChangeNotifier {
Future<void> get playbackSettled => _operations;
Future<void> get preloadSettled => _preloadTask;
/// 当前页面可见、无浮层遮挡且存在可用播放器时可安全恢复。
bool get canResumeAfterBackground =>
!_closed && _routeVisible && !_overlayOpen && active != null;
bool get _visible => !_closed && _appResumed && _routeVisible;
bool get _mayPlay => _visible && !_overlayOpen && _userWantsPlay;
+36 -1
View File
@@ -512,6 +512,7 @@ class PlayerLogic extends ChangeNotifier {
void onLifecycle(AppLifecycleState state) {
if (state != AppLifecycleState.resumed) unawaited(saveCurrentProgress());
if (state == AppLifecycleState.resumed) {
final wasInPip = pip || pipPreparing;
// 部分机型退出画中画不会回调 onPipChanged(false):回前台先兜底复位,
// 否则 chromeHidden 恒为 true,播放浮层与首页底栏都会消失。
if (pip || pipPreparing) {
@@ -523,8 +524,17 @@ class PlayerLogic extends ChangeNotifier {
// 签名地址有有效期:回前台时若票据已过期,重新取一张再起播,
// 否则会撞上 403(契约 §1.4)
final episode = trackedEpisode;
final shouldAutoResume = !wasInPip && _canAutoResume(episode);
if (episode != null && !playback.isFresh(episode.id)) {
unawaited(selectEpisode(session.currentIndex));
unawaited(
_refreshTicketThenResume(
episode,
session.currentIndex,
shouldAutoResume,
),
);
} else if (shouldAutoResume) {
session.setUserWantsPlay(true);
}
}
session.setAppResumed(
@@ -533,6 +543,31 @@ class PlayerLogic extends ChangeNotifier {
if (state != AppLifecycleState.resumed) cancelScrub();
}
Future<void> _refreshTicketThenResume(
Episode episode,
int index,
bool shouldResume,
) async {
await selectEpisode(index);
if (!shouldResume ||
!isMounted() ||
trackedEpisode?.id != episode.id ||
!_canAutoResume(episode)) {
return;
}
session.setUserWantsPlay(true);
}
bool _canAutoResume(Episode? episode) {
return episode != null &&
ticketError == null &&
blockedEpisodeId != episode.id &&
unlockingEpisodeId == null &&
!session.isLocked &&
session.error == null &&
session.canResumeAfterBackground;
}
@override
void dispose() {
if (_disposed) return;