From 1e47be2526f1d17c7d4b8af6a5b5f4a3534de9a5 Mon Sep 17 00:00:00 2001 From: HelloZeroNick <2835103520@qq.com> Date: Tue, 21 Jul 2026 12:12:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(audio=5Fservice):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E9=B8=BF=E8=92=99=E6=92=AD=E6=8E=A7=E4=B8=AD=E5=BF=83=E4=B8=8A?= =?UTF-8?q?=E4=B8=80=E9=9B=86/=E4=B8=8B=E4=B8=80=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原先 VideoPlayerServiceHandler 未重写 skipToNext/skipToPrevious, 播控中心上一集/下一集按钮无响应。 通过在 VideoPlayerServiceHandler 中新增 onSkipToNext/onSkipToPrevious 回调字段,各页面控制器在 onInit 中注册对应逻辑: - UgcIntroController: prevPlay/nextPlay(分P/合集切换) - PgcIntroController: prevPlay/nextPlay(番剧切换) - AudioController: playPrev/playNext(音频列表切换) onClose 中清理回调,避免内存泄漏。 --- lib/pages/audio/controller.dart | 26 ++++++++++++------- .../video/introduction/pgc/controller.dart | 4 +++ .../video/introduction/ugc/controller.dart | 4 +++ lib/services/audio_handler.dart | 22 ++++++++++++++++ 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/lib/pages/audio/controller.dart b/lib/pages/audio/controller.dart index a424c5137e..9de81ab4f2 100644 --- a/lib/pages/audio/controller.dart +++ b/lib/pages/audio/controller.dart @@ -132,10 +132,14 @@ class AudioController extends GetxController _queryPlayUrl(); } }); - videoPlayerServiceHandler - ?..onPlay = onPlay - ..onPause = onPause - ..onSeek = onSeek; + final handler = videoPlayerServiceHandler; + if (handler != null) { + handler.onPlay = onPlay; + handler.onPause = onPause; + handler.onSeek = onSeek; + handler.onSkipToPrevious = () async => playPrev(); + handler.onSkipToNext = () async => playNext(); + } animController = AnimationController( vsync: this, @@ -780,11 +784,15 @@ class AudioController extends GetxController ..onPause = null ..isPlaying = null ..reset(); - videoPlayerServiceHandler - ?..onPlay = null - ..onPause = null - ..onSeek = null - ..onVideoDetailDispose(hashCode.toString()); + videoPlayerServiceHandler?.onVideoDetailDispose(hashCode.toString()); + final handler = videoPlayerServiceHandler; + if (handler != null) { + handler.onPlay = null; + handler.onPause = null; + handler.onSeek = null; + handler.onSkipToPrevious = null; + handler.onSkipToNext = null; + } _subscriptions?.forEach((e) => e.cancel()); _subscriptions?.clear(); _subscriptions = null; diff --git a/lib/pages/video/introduction/pgc/controller.dart b/lib/pages/video/introduction/pgc/controller.dart index 6426cc5f92..80a29ccaed 100644 --- a/lib/pages/video/introduction/pgc/controller.dart +++ b/lib/pages/video/introduction/pgc/controller.dart @@ -63,6 +63,10 @@ class PgcIntroController extends CommonIntroController { super.onInit(); + // 注册播控中心上一集/下一集回调 + videoPlayerServiceHandler?.onSkipToPrevious = () async => prevPlay(); + videoPlayerServiceHandler?.onSkipToNext = () async => nextPlay(); + if (isPgc) { if (isLogin) { queryIsFollowed(); diff --git a/lib/pages/video/introduction/ugc/controller.dart b/lib/pages/video/introduction/ugc/controller.dart index 21566eeb8a..b98064ed24 100644 --- a/lib/pages/video/introduction/ugc/controller.dart +++ b/lib/pages/video/introduction/ugc/controller.dart @@ -82,6 +82,10 @@ class UgcIntroController extends CommonIntroController with ReloadMixin { } videoDetail.value.title = Get.arguments['title'] ?? ''; + + // 注册播控中心上一集/下一集回调 + videoPlayerServiceHandler?.onSkipToPrevious = () async => prevPlay(); + videoPlayerServiceHandler?.onSkipToNext = () async => nextPlay(); } // 获取视频简介&分p diff --git a/lib/services/audio_handler.dart b/lib/services/audio_handler.dart index a1bebebe38..5a5ff05786 100644 --- a/lib/services/audio_handler.dart +++ b/lib/services/audio_handler.dart @@ -46,6 +46,8 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { Future? Function()? onPlay; Future? Function()? onPause; Future? Function(Duration position)? onSeek; + Future? Function()? onSkipToNext; + Future? Function()? onSkipToPrevious; @override Future play() { @@ -73,6 +75,16 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { // await player.seekTo(position); } + @override + Future skipToNext() async { + await onSkipToNext?.call(); + } + + @override + Future skipToPrevious() async { + await onSkipToPrevious?.call(); + } + void setMediaItem(MediaItem newMediaItem) { if (!enableBackgroundPlay) return; // if (kDebugMode) { @@ -115,7 +127,15 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { MediaControl.rewind.copyWith( androidIcon: 'drawable/ic_baseline_replay_10_24', ), + if (!isLive) + MediaControl.skipToPrevious.copyWith( + androidIcon: 'drawable/ic_skip_previous', + ), if (playing) MediaControl.pause else MediaControl.play, + if (!isLive) + MediaControl.skipToNext.copyWith( + androidIcon: 'drawable/ic_skip_next', + ), if (!isLive) MediaControl.fastForward.copyWith( androidIcon: 'drawable/ic_baseline_forward_10_24', @@ -124,6 +144,8 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler { playing: playing, systemActions: const { MediaAction.seek, + MediaAction.skipToNext, + MediaAction.skipToPrevious, }, ), );