fix(recommend): 稳定进度拖动与清屏状态

This commit is contained in:
Zhou Weidong committed 2026-10-22 20:01:54 +08:00
1 parent 76c4f1d411
commit 30b55afdd4
9 files changed
+339 -96

No files matched your search

+56 -8
View File
@@ -59,6 +59,7 @@ class PlayerPage extends StatefulWidget {
this.active = true,
this.resumeRequest = 0,
this.backRequest = 0,
this.scrubCancelRequest = 0,
this.onDiscover,
this.onMy,
this.onSearch,
@@ -85,6 +86,7 @@ class PlayerPage extends StatefulWidget {
final bool active;
final int resumeRequest;
final int backRequest;
final int scrubCancelRequest;
final VoidCallback? onDiscover;
final VoidCallback? onMy;
final VoidCallback? onSearch;
@@ -117,6 +119,7 @@ class _PlayerPageState extends State<PlayerPage>
double _playbackSpeed = 1.0;
bool _boosting = false;
bool _scrubbing = false;
bool _clearScreenFromScrub = false;
double? _speedBeforeBoost;
bool? _chromeBeforeBoost;
@@ -135,6 +138,9 @@ class _PlayerPageState extends State<PlayerPage>
downloads: widget.downloads,
);
logic.attach(widget, isMounted: () => mounted);
if (oldWidget.scrubCancelRequest != widget.scrubCancelRequest) {
_cancelFeedScrub();
}
_thumbnailService = PlaybackThumbnailService(
sourceResolver: _resolveThumbnailSource,
);
@@ -266,7 +272,9 @@ class _PlayerPageState extends State<PlayerPage>
}
void _hideChrome() {
if (!_chromeVisible) return;
setState(() => _chromeVisible = false);
widget.onScrubVisibilityChanged?.call(true);
}
/// 长按两侧:切 2 倍速并清屏,记下进入前的状态用于松手恢复。
@@ -281,6 +289,7 @@ class _PlayerPageState extends State<PlayerPage>
_playbackSpeed = _boostPlaybackSpeed;
_chromeVisible = false;
});
widget.onScrubVisibilityChanged?.call(true);
unawaited(logic.setPlaybackSpeed(_boostPlaybackSpeed));
}
@@ -296,6 +305,7 @@ class _PlayerPageState extends State<PlayerPage>
_playbackSpeed = speed;
_chromeVisible = chrome;
});
widget.onScrubVisibilityChanged?.call(!chrome);
unawaited(logic.setPlaybackSpeed(speed));
}
@@ -305,6 +315,39 @@ class _PlayerPageState extends State<PlayerPage>
widget.onScrubVisibilityChanged?.call(value);
}
void _finishFeedScrub() {
setState(() {
_scrubbing = false;
_chromeVisible = false;
_clearScreenFromScrub = true;
});
}
void _cancelFeedScrub() {
logic.cancelScrub();
_scrubbing = false;
_chromeVisible = true;
_clearScreenFromScrub = false;
}
void _restoreFeedChrome() {
setState(() {
_scrubbing = false;
_chromeVisible = true;
_clearScreenFromScrub = false;
});
widget.onScrubVisibilityChanged?.call(false);
}
void _handleFeedSurfaceTap() {
if (_scrubbing) return;
if (!_chromeVisible) {
_restoreFeedChrome();
return;
}
logic.session.setUserWantsPlay(!logic.session.userWantsPlay);
}
/// 收藏状态确认后同步右侧计数(总数没有独立计数接口,按 ±1 跟随)。
void _applyFavoriteDelta(String dramaId, {required bool nowSaved}) {
setState(() {
@@ -374,6 +417,7 @@ class _PlayerPageState extends State<PlayerPage>
if (widget.homeMode &&
widget.showHomeFeedHeader &&
!_scrubbing &&
_chromeVisible &&
!_boosting &&
!logic.pip &&
!logic.pipPreparing)
@@ -479,16 +523,14 @@ class _PlayerPageState extends State<PlayerPage>
controller: videoPort?.controller,
videoUrl: videoPort?.controller.dataSource ?? episode.videoUrl,
theater: theater,
onTap: () =>
logic.session.setUserWantsPlay(!logic.session.userWantsPlay),
onTap: () => _handleFeedSurfaceTap(),
),
if (widget.homeMode && _chromeVisible && !logic.chromeHidden)
Positioned.fill(
child: GestureDetector(
key: const Key('home-feed-video-toggle'),
behavior: HitTestBehavior.opaque,
onTap: () =>
logic.session.setUserWantsPlay(!logic.session.userWantsPlay),
onTap: _handleFeedSurfaceTap,
),
),
// 票据三态之一:起播前正在向后端要签名地址
@@ -595,8 +637,7 @@ class _PlayerPageState extends State<PlayerPage>
boosting: _boosting,
onBoostStart: _startBoost,
onBoostEnd: _endBoost,
onTogglePlay: () =>
logic.session.setUserWantsPlay(!logic.session.userWantsPlay),
onTogglePlay: _handleFeedSurfaceTap,
liked: interactions.isEpisodeLiked(episode.id),
likeCount:
interactions.episodeLikeCount(episode.id) ?? episode.likeCount,
@@ -634,7 +675,9 @@ class _PlayerPageState extends State<PlayerPage>
onEpisodes: () => logic.showEpisodes(context),
onMore: _openCurrentMore,
onScrubStart: ready ? () => logic.beginScrub(videoPort!) : null,
onScrubEnd: _finishFeedScrub,
onScrubVisibilityChanged: _setScrubbing,
cancelScrubRequest: widget.scrubCancelRequest,
onSeek: ready
? (position) => logic.seekTo(context, videoPort!, position)
: null,
@@ -706,18 +749,23 @@ class _PlayerPageState extends State<PlayerPage>
? null
: () => _openUnlockSheet(context, index, episode),
),
if (widget.homeMode && !_chromeVisible && !_boosting && !_scrubbing)
if (widget.homeMode &&
!_chromeVisible &&
!_boosting &&
!_scrubbing &&
!_clearScreenFromScrub)
Positioned(
right: 12,
bottom: 56,
child: ExitClearScreenButton(
key: const Key('home-feed-exit-clear-screen'),
tooltip: l10n.exitClearScreen,
onPressed: () => setState(() => _chromeVisible = true),
onPressed: _restoreFeedChrome,
),
),
if (widget.homeMode &&
!_scrubbing &&
_chromeVisible &&
!logic.chromeHidden &&
selected &&
!logic.session.userWantsPlay)