From c11c5695a244580a61cd7cf2c4efad00cc78e47c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 8 Nov 2023 23:02:13 +0800 Subject: [PATCH] =?UTF-8?q?mod:=20=E5=90=88=E9=9B=86=E8=BF=9E=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bangumi/introduction/controller.dart | 28 ++++++++ lib/pages/video/detail/controller.dart | 8 +-- .../video/detail/introduction/controller.dart | 46 ++++++++++++ .../video/detail/widgets/header_control.dart | 70 +++++++++++++++++-- lib/plugin/pl_player/controller.dart | 15 ++++ lib/plugin/pl_player/models/play_repeat.dart | 25 +++++++ lib/utils/storage.dart | 2 + 7 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 lib/plugin/pl_player/models/play_repeat.dart diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index c027f8af..7406ef56 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -9,6 +9,7 @@ import 'package:pilipala/models/bangumi/info.dart'; import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/reply/index.dart'; +import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; @@ -292,4 +293,31 @@ class BangumiIntroController extends GetxController { } return result; } + + /// 列表循环或者顺序播放时,自动播放下一个 + void nextPlay() { + late List episodes; + if (bangumiDetail.value.episodes != null) { + episodes = bangumiDetail.value.episodes!; + } + VideoDetailController videoDetailCtr = + Get.find(tag: Get.arguments['heroTag']); + int currentIndex = + episodes.indexWhere((e) => e.cid == videoDetailCtr.cid.value); + int nextIndex = currentIndex + 1; + PlayRepeat platRepeat = videoDetailCtr.plPlayerController.playRepeat; + // 列表循环 + if (platRepeat == PlayRepeat.listCycle) { + if (nextIndex == episodes.length - 1) { + nextIndex = 0; + } + } + if (nextIndex <= episodes.length - 1 && + platRepeat == PlayRepeat.listOrder) {} + + int cid = episodes[nextIndex].cid!; + String bvid = episodes[nextIndex].bvid!; + int aid = episodes[nextIndex].aid!; + changeSeasonOrbangu(bvid, cid, aid); + } } diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index b4dc9ae8..86b10f80 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -20,7 +20,7 @@ class VideoDetailController extends GetxController with GetSingleTickerProviderStateMixin { /// 路由传参 String bvid = Get.parameters['bvid']!; - int cid = int.parse(Get.parameters['cid']!); + RxInt cid = int.parse(Get.parameters['cid']!).obs; RxInt danmakuCid = 0.obs; String heroTag = Get.arguments['heroTag']; // 视频详情 @@ -103,7 +103,7 @@ class VideoDetailController extends GetxController localCache.get(LocalCacheKey.historyPause) == true) { enableHeart = false; } - danmakuCid.value = cid; + danmakuCid.value = cid.value; } showReplyReplyPanel() { @@ -202,7 +202,7 @@ class VideoDetailController extends GetxController // 默认1倍速 speed: 1.0, bvid: bvid, - cid: cid, + cid: cid.value, enableHeart: enableHeart, isFirstTime: isFirstTime, autoplay: autoplay, @@ -211,7 +211,7 @@ class VideoDetailController extends GetxController // 视频链接 Future queryVideoUrl() async { - var result = await VideoHttp.videoUrl(cid: cid, bvid: bvid); + var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid); if (result['status']) { data = result['data']; diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 71b63c71..b72fbd74 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -11,6 +11,7 @@ import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/reply/index.dart'; +import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; @@ -58,10 +59,14 @@ class VideoIntroController extends GetxController { RxString total = '1'.obs; Timer? timer; bool isPaused = false; + String heroTag = ''; @override void onInit() { super.onInit(); + try { + heroTag = Get.arguments['heroTag']; + } catch (_) {} userInfo = userInfoCache.get('userInfoCache'); if (Get.arguments.isNotEmpty) { if (Get.arguments.containsKey('videoItem')) { @@ -486,4 +491,45 @@ class VideoIntroController extends GetxController { } super.onClose(); } + + /// 列表循环或者顺序播放时,自动播放下一个 + void nextPlay() { + late List episodes; + bool isPages = false; + if (videoDetail.value.ugcSeason != null) { + UgcSeason ugcSeason = videoDetail.value.ugcSeason!; + List sections = ugcSeason.sections!; + episodes = []; + + for (int i = 0; i < sections.length; i++) { + List episodesList = sections[i].episodes!; + episodes.addAll(episodesList); + } + } else if (videoDetail.value.pages != null) { + isPages = true; + List pages = videoDetail.value.pages!; + episodes = []; + episodes.addAll(pages); + } + + int currentIndex = episodes.indexWhere((e) => e.cid == lastPlayCid.value); + int nextIndex = currentIndex + 1; + VideoDetailController videoDetailCtr = + Get.find(tag: heroTag); + PlayRepeat platRepeat = videoDetailCtr.plPlayerController.playRepeat; + + // 列表循环 + if (nextIndex >= episodes.length) { + if (platRepeat == PlayRepeat.listCycle) { + nextIndex = 0; + } + if (platRepeat == PlayRepeat.listOrder) { + return; + } + } + int cid = episodes[nextIndex].cid!; + String rBvid = isPages ? bvid : episodes[nextIndex].bvid; + int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[nextIndex].aid!; + changeSeasonOrbangu(rBvid, cid, rAid); + } } diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 1697b4d4..7a4b3ced 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -13,6 +13,7 @@ import 'package:pilipala/models/video/play/url.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; +import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/utils/storage.dart'; class HeaderControl extends StatefulWidget implements PreferredSizeWidget { @@ -149,13 +150,14 @@ class _HeaderControlState extends State { '当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}', style: subTitleStyle), ), - // ListTile( - // onTap: () {}, - // dense: true, - // enabled: false, - // leading: const Icon(Icons.play_circle_outline, size: 20), - // title: Text('播放设置', style: titleStyle), - // ), + ListTile( + onTap: () => {Get.back(), showSetRepeat()}, + dense: true, + leading: const Icon(Icons.repeat, size: 20), + title: Text('播放顺序', style: titleStyle), + subtitle: Text(widget.controller!.playRepeat.description, + style: subTitleStyle), + ), ListTile( onTap: () => {Get.back(), showSetDanmaku()}, dense: true, @@ -704,6 +706,60 @@ class _HeaderControlState extends State { ); } + /// 播放顺序 + void showSetRepeat() async { + showModalBottomSheet( + context: context, + elevation: 0, + backgroundColor: Colors.transparent, + builder: (BuildContext context) { + return Container( + width: double.infinity, + height: 250, + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.background, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + child: Column( + children: [ + SizedBox( + height: 45, + child: Center(child: Text('选择播放顺序', style: titleStyle))), + Expanded( + child: Material( + child: ListView( + children: [ + for (var i in PlayRepeat.values) ...[ + ListTile( + onTap: () { + widget.controller!.setPlayRepeat(i); + Get.back(); + }, + dense: true, + contentPadding: + const EdgeInsets.only(left: 20, right: 20), + title: Text(i.description), + trailing: widget.controller!.playRepeat == i + ? Icon( + Icons.done, + color: Theme.of(context).colorScheme.primary, + ) + : const SizedBox(), + ) + ], + ], + ), + ), + ), + ], + ), + ); + }, + ); + } + @override Widget build(BuildContext context) { final _ = widget.controller!; diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 6a2ffaa2..57c3508b 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -13,6 +13,7 @@ import 'package:media_kit_video/media_kit_video.dart'; import 'package:ns_danmaku/ns_danmaku.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; +import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:screen_brightness/screen_brightness.dart'; @@ -209,6 +210,9 @@ class PlPlayerController { late double fontSizeVal; late double danmakuSpeedVal; + // 播放顺序相关 + PlayRepeat playRepeat = PlayRepeat.pause; + // 添加一个私有构造函数 PlPlayerController._() { _videoType = videoType; @@ -226,6 +230,12 @@ class PlPlayerController { // 弹幕速度 danmakuSpeedVal = localCache.get(LocalCacheKey.danmakuSpeed, defaultValue: 4.0); + playRepeat = PlayRepeat.values.toList().firstWhere( + (e) => + e.value == + videoStorage.get(VideoBoxKey.playRepeat, + defaultValue: PlayRepeat.pause.value), + ); // _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) { // if (status == PlayerStatus.playing) { // WakelockPlus.enable(); @@ -902,6 +912,11 @@ class PlPlayerController { } } + setPlayRepeat(PlayRepeat type) { + playRepeat = type; + videoStorage.put(VideoBoxKey.playRepeat, type.value); + } + Future dispose({String type = 'single'}) async { // 每次减1,最后销毁 if (type == 'single' && playerCount.value > 1) { diff --git a/lib/plugin/pl_player/models/play_repeat.dart b/lib/plugin/pl_player/models/play_repeat.dart new file mode 100644 index 00000000..e68196c7 --- /dev/null +++ b/lib/plugin/pl_player/models/play_repeat.dart @@ -0,0 +1,25 @@ +enum PlayRepeat { + pause, + listOrder, + singleCycle, + listCycle, +} + +extension PlayRepeatExtension on PlayRepeat { + static final List _descList = [ + '播完暂停', + '顺序播放', + '单个循环', + '列表循环', + ]; + get description => _descList[index]; + + static final List _valueList = [ + 1, + 2, + 3, + 4, + ]; + get value => _valueList[index]; + get defaultValue => _valueList[1]; +} diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 6ecd6083..eef42a58 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -156,4 +156,6 @@ class VideoBoxKey { static const String videoBrightness = 'videoBrightness'; // 倍速 static const String videoSpeed = 'videoSpeed'; + // 播放顺序 + static const String playRepeat = 'playRepeat'; }