diff --git a/lib/pages/common/common_intro_controller.dart b/lib/pages/common/common_intro_controller.dart index fd861148e..6cbedd6e5 100644 --- a/lib/pages/common/common_intro_controller.dart +++ b/lib/pages/common/common_intro_controller.dart @@ -1,12 +1,16 @@ +import 'dart:async' show Timer; + import 'package:PiliPlus/http/fav.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/models_new/fav/fav_folder/data.dart'; +import 'package:PiliPlus/models_new/video/video_detail/data.dart'; import 'package:PiliPlus/models_new/video/video_detail/stat_detail.dart'; import 'package:PiliPlus/models_new/video/video_tag/data.dart'; import 'package:PiliPlus/services/account_service.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; @@ -17,6 +21,8 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; abstract class CommonIntroController extends GetxController { + String heroTag = Get.arguments['heroTag']; + String bvid = Get.parameters['bvid']!; // 是否点赞 @@ -27,6 +33,8 @@ abstract class CommonIntroController extends GetxController { bool get hasCoin => coinNum.value != 0; // 是否收藏 final RxBool hasFav = false.obs; + // 是否稍后再看 + final RxBool hasLater = false.obs; final Rx?> videoTags = Rx?>(null); @@ -39,6 +47,62 @@ abstract class CommonIntroController extends GetxController { StatDetail? getStat(); + final Rx videoDetail = VideoDetailData().obs; + + Future queryVideoIntro(); + + bool prevPlay(); + bool nextPlay(); + + // 同时观看 + final bool isShowOnlineTotal = Pref.enableOnlineTotal; + late final RxString total = '1'.obs; + Timer? timer; + + final RxInt cid = int.parse(Get.parameters['cid']!).obs; + + @override + void onInit() { + super.onInit(); + queryVideoIntro(); + startTimer(); + } + + void startTimer() { + if (isShowOnlineTotal) { + queryOnlineTotal(); + timer ??= Timer.periodic(const Duration(seconds: 10), (Timer timer) { + queryOnlineTotal(); + }); + } + } + + void canelTimer() { + timer?.cancel(); + timer = null; + } + + // 查看同时在看人数 + Future queryOnlineTotal() async { + if (!isShowOnlineTotal) { + return; + } + var result = await VideoHttp.onlineTotal( + aid: IdUtils.bv2av(bvid), + bvid: bvid, + cid: cid.value, + ); + if (result['status']) { + total.value = result['data']; + } + } + + @override + void onClose() { + canelTimer(); + super.onClose(); + } + Future> queryVideoInFolder() async { favIds = null; final (rid, type) = getFavRidType(); @@ -197,4 +261,12 @@ abstract class CommonIntroController extends GetxController { videoTags.value = null; } } + + Future viewLater() async { + var res = await (hasLater.value + ? UserHttp.toViewDel(aids: [IdUtils.bv2av(bvid)]) + : await UserHttp.toViewLater(bvid: bvid)); + if (res['status']) hasLater.value = !hasLater.value; + SmartDialog.showToast(res['msg']); + } } diff --git a/lib/pages/episode_panel/view.dart b/lib/pages/episode_panel/view.dart index ac6968942..384f7d957 100644 --- a/lib/pages/episode_panel/view.dart +++ b/lib/pages/episode_panel/view.dart @@ -41,7 +41,7 @@ class EpisodePanel extends CommonSlidePage { const EpisodePanel({ super.key, super.enableSlide, - required this.videoIntroController, + required this.ugcIntroController, required this.heroTag, required this.type, // required this.count, @@ -57,11 +57,11 @@ class EpisodePanel extends CommonSlidePage { this.isSupportReverse, this.isReversed, this.onReverse, - required this.changeFucCall, + required this.onChangeEpisode, this.onClose, - }); + }) : assert(type == EpisodeType.pgc || ugcIntroController != null); - final VideoIntroController videoIntroController; + final UgcIntroController? ugcIntroController; final String heroTag; final EpisodeType type; // final int count; @@ -76,7 +76,7 @@ class EpisodePanel extends CommonSlidePage { final int initialTabIndex; final bool? isSupportReverse; final bool? isReversed; - final Function changeFucCall; + final Function onChangeEpisode; final VoidCallback? onReverse; final VoidCallback? onClose; @@ -315,7 +315,7 @@ class _EpisodePanelState extends CommonSlidePageState { : episode.pages, cover: episode.arc?.pic, heroTag: widget.heroTag, - videoIntroController: widget.videoIntroController, + ugcIntroController: widget.ugcIntroController!, bvid: IdUtils.av2bv(episode.aid), ), ), @@ -401,7 +401,7 @@ class _EpisodePanelState extends CommonSlidePageState { _currentItemIndex = index; } final isEpisode = episode is ugc.BaseEpisodeItem; - widget.changeFucCall( + widget.onChangeEpisode( episode is pgc.EpisodeItem ? episode.epId : null, isEpisode ? episode.bvid : widget.bvid, episode.cid, @@ -411,7 +411,7 @@ class _EpisodePanelState extends CommonSlidePageState { if (widget.type == EpisodeType.season) { try { Get.find( - tag: widget.videoIntroController.heroTag, + tag: widget.ugcIntroController!.heroTag, ).seasonCid = episode.cid; } catch (_) {} } diff --git a/lib/pages/save_panel/view.dart b/lib/pages/save_panel/view.dart index 3ee84a323..5ad4e6870 100644 --- a/lib/pages/save_panel/view.dart +++ b/lib/pages/save_panel/view.dart @@ -89,7 +89,7 @@ class _SavePanelState extends State { if (currentRoute.startsWith('/video')) { try { final heroTag = Get.arguments?['heroTag']; - late final ctr = Get.find(tag: heroTag); + late final ctr = Get.find(tag: heroTag); final videoDetail = ctr.videoDetail.value; cover = videoDetail.pic; title = videoDetail.title; diff --git a/lib/pages/video/ai_conclusion/view.dart b/lib/pages/video/ai_conclusion/view.dart index ca50023c3..93185eeb2 100644 --- a/lib/pages/video/ai_conclusion/view.dart +++ b/lib/pages/video/ai_conclusion/view.dart @@ -19,6 +19,14 @@ class AiConclusionPanel extends CommonCollapseSlidePage { } class _AiDetailState extends CommonCollapseSlidePageState { + final _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget buildPage(ThemeData theme) { return Material( @@ -53,7 +61,7 @@ class _AiDetailState extends CommonCollapseSlidePageState { @override Widget buildList(ThemeData theme) { return CustomScrollView( - controller: ScrollController(), + controller: _controller, physics: const AlwaysScrollableScrollPhysics(), slivers: [ if (widget.item.summary?.isNotEmpty == true) ...[ diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 7e18b7086..b20ebe1d1 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -68,11 +68,11 @@ class VideoDetailController extends GetxController /// 路由传参 String bvid = Get.parameters['bvid']!; final RxInt cid = int.parse(Get.parameters['cid']!).obs; - final RxInt danmakuCid = 0.obs; final heroTag = Get.arguments['heroTag']; final RxString cover = ''.obs; // 视频类型 默认投稿视频 - final SearchType videoType = Get.arguments['videoType'] ?? SearchType.video; + final isUgc = + (Get.arguments['videoType'] ?? SearchType.video) == SearchType.video; /// tabs相关配置 late TabController tabCtr; @@ -114,7 +114,7 @@ class VideoDetailController extends GetxController late String cacheDecode; late String cacheSecondDecode; - bool get showReply => videoType == SearchType.video + bool get showReply => isUgc ? plPlayerController.showVideoReply : plPlayerController.showBangumiReply; @@ -283,7 +283,6 @@ class VideoDetailController extends GetxController ); autoPlay.value = Pref.autoPlayEnable; if (autoPlay.value) isShowCover.value = false; - danmakuCid.value = cid.value; // 预设的解码格式 cacheDecode = Pref.defaultDecode; @@ -336,9 +335,9 @@ class VideoDetailController extends GetxController try { for (var item in mediaList) { if (item.cid != null) { - Get.find( + Get.find( tag: heroTag, - ).changeSeasonOrbangu( + ).onChangeEpisode( null, item.bvid, item.cid, @@ -367,9 +366,9 @@ class VideoDetailController extends GetxController mediaList: mediaList, changeMediaList: (bvid, cid, aid, cover) { try { - Get.find( + Get.find( tag: heroTag, - ).changeSeasonOrbangu(null, bvid, cid, aid, cover); + ).onChangeEpisode(null, bvid, cid, aid, cover); } catch (_) {} }, panelTitle: watchLaterTitle, @@ -901,11 +900,11 @@ class VideoDetailController extends GetxController onTap: (_) { if (item is int) { try { - VideoIntroController videoIntroController = - Get.find(tag: heroTag); + UgcIntroController ugcIntroController = + Get.find(tag: heroTag); Part part = - videoIntroController.videoDetail.value.pages![item]; - videoIntroController.changeSeasonOrbangu( + ugcIntroController.videoDetail.value.pages![item]; + ugcIntroController.onChangeEpisode( null, bvid, part.cid, @@ -1137,9 +1136,9 @@ class VideoDetailController extends GetxController bvid: bvid, cid: cid.value, autoplay: autoplay ?? autoPlay.value, - epid: videoType == SearchType.media_bangumi ? epId : null, - seasonId: videoType == SearchType.media_bangumi ? seasonId : null, - subType: videoType == SearchType.media_bangumi ? subType : null, + epid: isUgc ? null : epId, + seasonId: isUgc ? null : seasonId, + subType: isUgc ? null : subType, callback: () { if (videoState.value is! Success) { videoState.value = const Success(null); @@ -1496,9 +1495,9 @@ class VideoDetailController extends GetxController if (res['status']) { PlayInfoData playInfo = res['data']; // interactive video - if (graphVersion == null) { + if (isUgc && graphVersion == null) { try { - final introCtr = Get.find(tag: heroTag); + final introCtr = Get.find(tag: heroTag); if (introCtr.videoDetail.value.rights?.isSteinGate == 1) { graphVersion = playInfo.interaction?.graphVersion; getSteinEdgeInfo(); @@ -1508,16 +1507,17 @@ class VideoDetailController extends GetxController } } - if (continuePlayingPart) { + if (isUgc && continuePlayingPart) { continuePlayingPart = false; try { - VideoIntroController videoIntroController = - Get.find(tag: heroTag); - if ((videoIntroController.videoDetail.value.pages?.length ?? 0) > 1 && + UgcIntroController ugcIntroController = Get.find( + tag: heroTag, + ); + if ((ugcIntroController.videoDetail.value.pages?.length ?? 0) > 1 && playInfo.lastPlayCid != null && playInfo.lastPlayCid != 0) { if (playInfo.lastPlayCid != cid.value) { - int index = videoIntroController.videoDetail.value.pages! + int index = ugcIntroController.videoDetail.value.pages! .indexWhere((item) => item.cid == playInfo.lastPlayCid); if (index != -1) { onAddItem(index); @@ -1598,9 +1598,9 @@ class VideoDetailController extends GetxController isManual: true, bvid: bvid, cid: cid.value, - epid: videoType == SearchType.media_bangumi ? epId : null, - seasonId: videoType == SearchType.media_bangumi ? seasonId : null, - subType: videoType == SearchType.media_bangumi ? subType : null, + epid: isUgc ? null : epId, + seasonId: isUgc ? null : seasonId, + subType: isUgc ? null : subType, ); } catch (_) {} } @@ -1683,7 +1683,7 @@ class VideoDetailController extends GetxController void showNoteList(BuildContext context) { String? title; try { - title = Get.find( + title = Get.find( tag: heroTag, ).videoDetail.value.title; } catch (_) {} diff --git a/lib/pages/video/introduction/pgc/controller.dart b/lib/pages/video/introduction/pgc/controller.dart index 227b4646e..61dd8abf1 100644 --- a/lib/pages/video/introduction/pgc/controller.dart +++ b/lib/pages/video/introduction/pgc/controller.dart @@ -10,14 +10,15 @@ import 'package:PiliPlus/models/pgc_lcf.dart'; import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart'; import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart'; import 'package:PiliPlus/models_new/triple/pgc_triple.dart'; +import 'package:PiliPlus/models_new/video/video_detail/data.dart'; import 'package:PiliPlus/models_new/video/video_detail/stat_detail.dart'; import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/dynamics_repost/view.dart'; import 'package:PiliPlus/pages/video/controller.dart'; -import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart'; import 'package:PiliPlus/pages/video/pay_coins/view.dart'; import 'package:PiliPlus/pages/video/reply/controller.dart'; import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart'; +import 'package:PiliPlus/services/service_locator.dart'; import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/global_data.dart'; import 'package:PiliPlus/utils/page_utils.dart'; @@ -257,7 +258,7 @@ class PgcIntroController extends CommonIntroController { } // 修改分P或番剧分集 - void changeSeasonOrbangu(dynamic epId, bvid, cid, aid, cover) { + void onChangeEpisode(dynamic epId, bvid, cid, aid, cover) { // 重新获取视频资源 this.epId = epId; this.bvid = bvid; @@ -270,7 +271,6 @@ class PgcIntroController extends CommonIntroController { ..epId = epId ..bvid = bvid ..cid.value = cid - ..danmakuCid.value = cid ..queryVideoUrl(); if (cover is String && cover.isNotEmpty) { videoDetailCtr.cover.value = cover; @@ -289,13 +289,9 @@ class PgcIntroController extends CommonIntroController { queryPgcLikeCoinFav(); } - try { - Get.find(tag: Get.arguments['heroTag']) - ..bvid = bvid - ..lastPlayCid.value = cid - ..queryVideoIntro() - ..queryOnlineTotal(); - } catch (_) {} + this.cid.value = cid; + queryVideoIntro(); + queryOnlineTotal(); } // 追番 @@ -328,6 +324,7 @@ class PgcIntroController extends CommonIntroController { SmartDialog.showToast(result['msg']); } + @override bool prevPlay() { final episodes = pgcItem.episodes!; VideoDetailController videoDetailCtr = Get.find( @@ -346,7 +343,7 @@ class PgcIntroController extends CommonIntroController { } } final episode = episodes[prevIndex]; - changeSeasonOrbangu( + onChangeEpisode( episode.epId, episode.bvid, episode.cid, @@ -357,6 +354,7 @@ class PgcIntroController extends CommonIntroController { } /// 列表循环或者顺序播放时,自动播放下一个;自动连播时,播放相关视频 + @override bool nextPlay() { try { final episodes = pgcItem.episodes!; @@ -380,7 +378,7 @@ class PgcIntroController extends CommonIntroController { } } final episode = episodes[nextIndex]; - changeSeasonOrbangu( + onChangeEpisode( episode.epId, episode.bvid, episode.cid, @@ -456,4 +454,14 @@ class PgcIntroController extends CommonIntroController { } }); } + + @override + Future queryVideoIntro() async { + var res = await VideoHttp.videoIntro(bvid: bvid); + if (res.isSuccess) { + VideoDetailData data = res.data; + videoPlayerServiceHandler.onVideoDetailChange(data, data.cid!, heroTag); + videoDetail.value = data; + } + } } diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart index cd1251445..f9d53b79f 100644 --- a/lib/pages/video/introduction/pgc/view.dart +++ b/lib/pages/video/introduction/pgc/view.dart @@ -252,7 +252,7 @@ class _PgcIntroPageState extends State heroTag: widget.heroTag, pages: item.episodes!, cid: videoDetailCtr.cid.value, - changeFuc: pgcIntroController.changeSeasonOrbangu, + onChangeEpisode: pgcIntroController.onChangeEpisode, showEpisodes: widget.showEpisodes, newEp: item.newEp, ), @@ -326,13 +326,15 @@ class _PgcIntroPageState extends State needAnim: true, ), ), - ActionItem( - icon: const Icon(FontAwesomeIcons.comment), - selectIcon: const Icon(FontAwesomeIcons.reply), - onTap: () => videoDetailCtr.tabCtr.animateTo(1), - selectStatus: false, - semanticsLabel: '评论', - text: NumUtil.numFormat(item.stat!.reply), + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.clock), + selectIcon: const Icon(FontAwesomeIcons.solidClock), + onTap: () => handleState(pgcIntroController.viewLater), + selectStatus: pgcIntroController.hasLater.value, + semanticsLabel: '再看', + text: '再看', + ), ), ActionItem( icon: const Icon(FontAwesomeIcons.shareFromSquare), diff --git a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart index ef1843d6b..0b252d5e7 100644 --- a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart +++ b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart @@ -94,94 +94,99 @@ class _IntroDetailState extends CommonCollapseSlidePageState { fontSize: 12, color: theme.colorScheme.onSurface, ); - return ListView( - controller: _controller, - physics: const AlwaysScrollableScrollPhysics(), - padding: EdgeInsets.only( - left: 14, - right: 14, - top: 14, - bottom: MediaQuery.paddingOf(context).bottom + 80, - ), - children: [ - SelectableText( - widget.item.title!, - style: const TextStyle(fontSize: 16), + final TextStyle textStyle = TextStyle( + color: theme.colorScheme.onSurfaceVariant, + ); + return SelectionArea( + child: ListView( + controller: _controller, + physics: const AlwaysScrollableScrollPhysics(), + padding: EdgeInsets.only( + left: 14, + right: 14, + top: 14, + bottom: MediaQuery.paddingOf(context).bottom + 80, ), - const SizedBox(height: 4), - Row( - spacing: 6, - children: [ - StatWidget( - type: StatType.play, - value: widget.item.stat!.view, - ), - StatWidget( - type: StatType.danmaku, - value: widget.item.stat!.danmaku, - ), - ], - ), - const SizedBox(height: 4), - Row( - children: [ - Text( - widget.item.areas!.first.name!, - style: smallTitle, - ), - const SizedBox(width: 6), - Text( - widget.item.publish!.pubTimeShow!, - style: smallTitle, - ), - const SizedBox(width: 6), - Text( - widget.item.newEp!.desc!, - style: smallTitle, - ), - ], - ), - const SizedBox(height: 20), - Text( - '简介:', - style: theme.textTheme.titleMedium, - ), - const SizedBox(height: 4), - SelectableText( - widget.item.evaluate!, - style: smallTitle.copyWith(fontSize: 14), - ), - const SizedBox(height: 20), - Text( - '声优:', - style: theme.textTheme.titleMedium, - ), - const SizedBox(height: 4), - SelectableText( - widget.item.actors!, - style: smallTitle.copyWith(fontSize: 14), - ), - if (widget.videoTags?.isNotEmpty == true) ...[ - const SizedBox(height: 10), - Wrap( - spacing: 8, - runSpacing: 8, - children: widget.videoTags! - .map( - (item) => SearchText( - fontSize: 13, - text: item.tagName!, - onTap: (tagName) => Get.toNamed( - '/searchResult', - parameters: {'keyword': tagName}, - ), - onLongPress: Utils.copyText, - ), - ) - .toList(), + children: [ + Text( + widget.item.title!, + style: const TextStyle(fontSize: 16), ), + const SizedBox(height: 4), + Row( + spacing: 6, + children: [ + StatWidget( + type: StatType.play, + value: widget.item.stat!.view, + ), + StatWidget( + type: StatType.danmaku, + value: widget.item.stat!.danmaku, + ), + ], + ), + const SizedBox(height: 4), + Row( + children: [ + Text( + widget.item.areas!.first.name!, + style: smallTitle, + ), + const SizedBox(width: 6), + Text( + widget.item.publish!.pubTimeShow!, + style: smallTitle, + ), + const SizedBox(width: 6), + Text( + widget.item.newEp!.desc!, + style: smallTitle, + ), + ], + ), + const SizedBox(height: 20), + Text( + '简介:', + style: theme.textTheme.titleMedium, + ), + const SizedBox(height: 4), + Text( + widget.item.evaluate!, + style: textStyle, + ), + const SizedBox(height: 20), + Text( + '演职人员:', + style: theme.textTheme.titleMedium, + ), + const SizedBox(height: 4), + Text( + widget.item.actors!, + style: textStyle, + ), + if (widget.videoTags?.isNotEmpty == true) ...[ + const SizedBox(height: 10), + Wrap( + spacing: 8, + runSpacing: 8, + children: widget.videoTags! + .map( + (item) => SearchText( + fontSize: 13, + text: item.tagName!, + onTap: (tagName) => Get.toNamed( + '/searchResult', + parameters: {'keyword': tagName}, + ), + onLongPress: Utils.copyText, + ), + ) + .toList(), + ), + ], ], - ], + ), ); } } diff --git a/lib/pages/video/introduction/pgc/widgets/pgc_panel.dart b/lib/pages/video/introduction/pgc/widgets/pgc_panel.dart index 3dada8c4b..bd6f0013d 100644 --- a/lib/pages/video/introduction/pgc/widgets/pgc_panel.dart +++ b/lib/pages/video/introduction/pgc/widgets/pgc_panel.dart @@ -15,7 +15,7 @@ class PgcPanel extends StatefulWidget { super.key, required this.pages, this.cid, - required this.changeFuc, + required this.onChangeEpisode, required this.showEpisodes, required this.heroTag, this.newEp, @@ -23,7 +23,7 @@ class PgcPanel extends StatefulWidget { final List pages; final int? cid; - final Function changeFuc; + final Function onChangeEpisode; final Function showEpisodes; final String heroTag; final NewEp? newEp; @@ -154,7 +154,7 @@ class _PgcPanelState extends State { vipStatus != 1) { SmartDialog.showToast('需要大会员'); } - widget.changeFuc( + widget.onChangeEpisode( item.epId, item.bvid, item.cid, diff --git a/lib/pages/video/introduction/ugc/controller.dart b/lib/pages/video/introduction/ugc/controller.dart index 86438a843..435ea5ac9 100644 --- a/lib/pages/video/introduction/ugc/controller.dart +++ b/lib/pages/video/introduction/ugc/controller.dart @@ -43,13 +43,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -class VideoIntroController extends CommonIntroController with ReloadMixin { - String heroTag = ''; - +class UgcIntroController extends CommonIntroController with ReloadMixin { late ExpandableController expandableCtr; final RxBool status = true.obs; - final Rx videoDetail = VideoDetailData().obs; // up主粉丝数 final Rx userStat = MemberCardInfoData().obs; @@ -60,16 +57,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { // 是否点踩 final RxBool hasDislike = false.obs; - // 是否稍后再看 - final RxBool hasLater = false.obs; - - final RxInt lastPlayCid = 0.obs; - - // 同时观看 - final bool isShowOnlineTotal = Pref.enableOnlineTotal; - late final RxString total = '1'.obs; - Timer? timer; - late final showArgueMsg = Pref.showArgueMsg; late final enableAi = Pref.enableAi; late final horizontalMemberPage = Pref.horizontalMemberPage; @@ -92,11 +79,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { }); } - try { - if (heroTag.isEmpty) { - heroTag = Get.arguments['heroTag']; - } - } catch (_) {} try { var videoItem = Get.arguments['videoItem']; if (videoItem != null) { @@ -110,12 +92,10 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { } } } catch (_) {} - lastPlayCid.value = int.parse(Get.parameters['cid']!); - startTimer(); - queryVideoIntro(); } // 获取视频简介&分p + @override Future queryVideoIntro() async { queryVideoTags(); var res = await VideoHttp.videoIntro(bvid: bvid); @@ -152,8 +132,8 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { } } catch (_) {} final pages = videoDetail.value.pages; - if (pages != null && pages.isNotEmpty && lastPlayCid.value == 0) { - lastPlayCid.value = pages.first.cid!; + if (pages != null && pages.isNotEmpty && cid.value == 0) { + cid.value = pages.first.cid!; } queryUserStat(data.staff); } else { @@ -298,14 +278,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { } } - Future viewLater() async { - var res = await (hasLater.value - ? UserHttp.toViewDel(aids: [IdUtils.bv2av(bvid)]) - : await UserHttp.toViewLater(bvid: bvid)); - if (res['status']) hasLater.value = !hasLater.value; - SmartDialog.showToast(res['msg']); - } - // 投币 Future actionCoinVideo() async { if (!accountService.isLogin.value) { @@ -493,7 +465,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { } // 修改分P或番剧分集 - bool changeSeasonOrbangu(dynamic epid, bvid, cid, aid, cover, [isStein]) { + bool onChangeEpisode(dynamic epid, bvid, cid, aid, cover, [isStein]) { // 重新获取视频资源 final videoDetailCtr = Get.find(tag: heroTag); @@ -519,7 +491,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { ..bvid = bvid ..oid.value = aid ?? IdUtils.bv2av(bvid) ..cid.value = cid - ..danmakuCid.value = cid ..queryVideoUrl(); if (this.bvid != bvid) { @@ -553,48 +524,19 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { queryVideoIntro(); } - lastPlayCid.value = cid; + this.cid.value = cid; queryOnlineTotal(); return true; } - void startTimer() { - if (isShowOnlineTotal) { - queryOnlineTotal(); - timer ??= Timer.periodic(const Duration(seconds: 10), (Timer timer) { - queryOnlineTotal(); - }); - } - } - - void canelTimer() { - timer?.cancel(); - timer = null; - } - - // 查看同时在看人数 - Future queryOnlineTotal() async { - if (!isShowOnlineTotal) { - return; - } - var result = await VideoHttp.onlineTotal( - aid: IdUtils.bv2av(bvid), - bvid: bvid, - cid: lastPlayCid.value, - ); - if (result['status']) { - total.value = result['data']; - } - } - @override void onClose() { - canelTimer(); expandableCtr.dispose(); super.onClose(); } /// 播放上一个 + @override bool prevPlay([bool skipPages = false]) { final List episodes = []; bool isPages = false; @@ -624,7 +566,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { ? videoDetail.isPageReversed == true ? videoDetail.pages!.last.cid : videoDetail.pages!.first.cid - : lastPlayCid.value), + : this.cid.value), ); int prevIndex = currentIndex - 1; final PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat; @@ -644,11 +586,12 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { final int cid = episodes[prevIndex].cid!; final String rBvid = isPages ? bvid : episodes[prevIndex].bvid; final int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[prevIndex].aid!; - changeSeasonOrbangu(null, rBvid, cid, rAid, null); + onChangeEpisode(null, rBvid, cid, rAid, null); return true; } /// 列表循环或者顺序播放时,自动播放下一个 + @override bool nextPlay([bool skipPages = false]) { try { final List episodes = []; @@ -731,7 +674,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { final String rBvid = isPages ? bvid : episodes[nextIndex].bvid; final int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[nextIndex].aid!; - changeSeasonOrbangu(null, rBvid, cid, rAid, null); + onChangeEpisode(null, rBvid, cid, rAid, null); return true; } catch (_) { return false; @@ -762,7 +705,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { final firstItem = relatedCtr.loadingState.value.data!.first; try { if (firstItem.cid != null) { - changeSeasonOrbangu( + onChangeEpisode( null, firstItem.bvid, firstItem.cid, @@ -771,7 +714,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { ); } else { SearchHttp.ab2c(aid: firstItem.aid, bvid: firstItem.bvid).then( - (cid) => changeSeasonOrbangu( + (cid) => onChangeEpisode( null, firstItem.bvid, cid, @@ -791,7 +734,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin { SmartDialog.showLoading(msg: '正在获取AI总结'); final res = await VideoHttp.aiConclusion( bvid: bvid, - cid: lastPlayCid.value, + cid: cid.value, upMid: videoDetail.value.owner?.mid, ); SmartDialog.dismiss(); diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart index b9084ee2e..2db91d512 100644 --- a/lib/pages/video/introduction/ugc/view.dart +++ b/lib/pages/video/introduction/ugc/view.dart @@ -35,8 +35,8 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; -class VideoIntroPanel extends StatefulWidget { - const VideoIntroPanel({ +class UgcIntroPanel extends StatefulWidget { + const UgcIntroPanel({ super.key, required this.heroTag, required this.showAiBottomSheet, @@ -49,12 +49,12 @@ class VideoIntroPanel extends StatefulWidget { final ValueChanged onShowMemberPage; @override - State createState() => _VideoIntroPanelState(); + State createState() => _UgcIntroPanelState(); } -class _VideoIntroPanelState extends State +class _UgcIntroPanelState extends State with AutomaticKeepAliveClientMixin { - late VideoIntroController introController; + late UgcIntroController ugcIntroController; late final VideoDetailController videoDetailCtr = Get.find(tag: widget.heroTag); @@ -66,7 +66,7 @@ class _VideoIntroPanelState extends State @override void initState() { super.initState(); - introController = Get.put(VideoIntroController(), tag: widget.heroTag) + ugcIntroController = Get.put(UgcIntroController(), tag: widget.heroTag) ..heroTag = widget.heroTag; } @@ -96,7 +96,8 @@ class _VideoIntroPanelState extends State ), sliver: Obx( () { - VideoDetailData videoDetail = introController.videoDetail.value; + VideoDetailData videoDetail = + ugcIntroController.videoDetail.value; bool isLoading = videoDetail.bvid == null; int? mid = videoDetail.owner?.mid; return SliverToBoxAdapter( @@ -107,7 +108,7 @@ class _VideoIntroPanelState extends State return; } feedBack(); - introController.expandableCtr.toggle(); + ugcIntroController.expandableCtr.toggle(); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -127,7 +128,7 @@ class _VideoIntroPanelState extends State if (mid != null) { feedBack(); if (!isPortrait && - introController + ugcIntroController .horizontalMemberPage) { widget.onShowMemberPage(mid); } else { @@ -146,7 +147,7 @@ class _VideoIntroPanelState extends State child: SingleChildScrollView( scrollDirection: Axis.horizontal, physics: ReloadScrollPhysics( - controller: introController, + controller: ugcIntroController, ), child: Row( spacing: 25, @@ -170,7 +171,7 @@ class _VideoIntroPanelState extends State context, isLoading, videoDetail, - introController, + ugcIntroController, ), ), ], @@ -182,7 +183,7 @@ class _VideoIntroPanelState extends State _buildVideoTitle(theme, videoDetail) else ExpandablePanel( - controller: introController.expandableCtr, + controller: ugcIntroController.expandableCtr, collapsed: GestureDetector( onLongPress: () { Feedback.forLongPress(context); @@ -208,11 +209,11 @@ class _VideoIntroPanelState extends State clipBehavior: Clip.none, children: [ _buildInfo(theme, videoDetail), - if (introController.enableAi) _aiBtn, + if (ugcIntroController.enableAi) _aiBtn, ], ), if (videoDetail.argueInfo?.argueMsg?.isNotEmpty == true && - introController.showArgueMsg) ...[ + ugcIntroController.showArgueMsg) ...[ const SizedBox(height: 2), Text.rich( TextSpan( @@ -238,7 +239,7 @@ class _VideoIntroPanelState extends State ), ], ExpandablePanel( - controller: introController.expandableCtr, + controller: ugcIntroController.expandableCtr, collapsed: const SizedBox.shrink(), expanded: Column( mainAxisSize: MainAxisSize.min, @@ -270,7 +271,8 @@ class _VideoIntroPanelState extends State ), ], Obx(() { - final videoTags = introController.videoTags.value; + final videoTags = + ugcIntroController.videoTags.value; if (videoTags.isNullOrEmpty) { return const SizedBox.shrink(); } @@ -281,14 +283,15 @@ class _VideoIntroPanelState extends State theme: expandTheme, ), Obx( - () => introController.status.value + () => ugcIntroController.status.value ? const SizedBox.shrink() : Center( child: TextButton.icon( icon: const Icon(Icons.refresh), onPressed: () { - introController.status.value = true; - introController.queryVideoIntro(); + ugcIntroController + ..status.value = true + ..queryVideoIntro(); if (videoDetailCtr.videoUrl.isNullOrEmpty && !videoDetailCtr.isQuerying) { videoDetailCtr.queryVideoUrl(); @@ -305,7 +308,7 @@ class _VideoIntroPanelState extends State context, isLoading, videoDetail, - introController, + ugcIntroController, ), ], // 合集 @@ -317,9 +320,9 @@ class _VideoIntroPanelState extends State .horizontalSeasonPanel)) SeasonPanel( heroTag: widget.heroTag, - changeFuc: introController.changeSeasonOrbangu, + onChangeEpisode: ugcIntroController.onChangeEpisode, showEpisodes: widget.showEpisodes, - videoIntroController: introController, + ugcIntroController: ugcIntroController, ), if (!isLoading && videoDetail.pages != null && @@ -330,8 +333,8 @@ class _VideoIntroPanelState extends State .horizontalSeasonPanel)) ...[ PagesPanel( heroTag: widget.heroTag, - videoIntroController: introController, - bvid: introController.bvid, + ugcIntroController: ugcIntroController, + bvid: ugcIntroController.bvid, showEpisodes: widget.showEpisodes, ), ], @@ -484,9 +487,9 @@ class _VideoIntroPanelState extends State Widget followButton(BuildContext context, ThemeData t) { return Obx( () { - int attr = introController.followStatus['attribute'] ?? 0; + int attr = ugcIntroController.followStatus['attribute'] ?? 0; return TextButton( - onPressed: () => introController.actionRelationMod(context), + onPressed: () => ugcIntroController.actionRelationMod(context), style: TextButton.styleFrom( tapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity(vertical: -2.8), @@ -517,7 +520,7 @@ class _VideoIntroPanelState extends State BuildContext context, bool isLoading, VideoDetailData videoDetail, - VideoIntroController videoIntroController, + UgcIntroController ugcIntroController, ) { return SizedBox( height: 48, @@ -527,19 +530,18 @@ class _VideoIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.thumbsUp), selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), - onTap: () => handleState(videoIntroController.actionLikeVideo), - onLongPress: () => - handleState(videoIntroController.actionOneThree), - selectStatus: videoIntroController.hasLike.value, + onTap: () => handleState(ugcIntroController.actionLikeVideo), + onLongPress: () => handleState(ugcIntroController.actionOneThree), + selectStatus: ugcIntroController.hasLike.value, semanticsLabel: '点赞', text: !isLoading ? NumUtil.numFormat(videoDetail.stat!.like) : null, needAnim: true, hasTriple: - videoIntroController.hasLike.value && - videoIntroController.hasCoin && - videoIntroController.hasFav.value, + ugcIntroController.hasLike.value && + ugcIntroController.hasCoin && + ugcIntroController.hasFav.value, callBack: (start) { if (start) { HapticFeedback.lightImpact(); @@ -556,8 +558,8 @@ class _VideoIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.thumbsDown), selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown), - onTap: () => handleState(videoIntroController.actionDislikeVideo), - selectStatus: videoIntroController.hasDislike.value, + onTap: () => handleState(ugcIntroController.actionDislikeVideo), + selectStatus: ugcIntroController.hasDislike.value, semanticsLabel: '点踩', text: "点踩", ), @@ -567,8 +569,8 @@ class _VideoIntroPanelState extends State key: _coinKey, icon: const Icon(FontAwesomeIcons.b), selectIcon: const Icon(FontAwesomeIcons.b), - onTap: () => handleState(videoIntroController.actionCoinVideo), - selectStatus: videoIntroController.hasCoin, + onTap: () => handleState(ugcIntroController.actionCoinVideo), + selectStatus: ugcIntroController.hasCoin, semanticsLabel: '投币', text: !isLoading ? NumUtil.numFormat(videoDetail.stat!.coin) @@ -581,12 +583,12 @@ class _VideoIntroPanelState extends State key: _favKey, icon: const Icon(FontAwesomeIcons.star), selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => videoIntroController.showFavBottomSheet(context), - onLongPress: () => videoIntroController.showFavBottomSheet( + onTap: () => ugcIntroController.showFavBottomSheet(context), + onLongPress: () => ugcIntroController.showFavBottomSheet( context, isLongPress: true, ), - selectStatus: videoIntroController.hasFav.value, + selectStatus: ugcIntroController.hasFav.value, semanticsLabel: '收藏', text: !isLoading ? NumUtil.numFormat(videoDetail.stat!.favorite) @@ -598,15 +600,15 @@ class _VideoIntroPanelState extends State () => ActionItem( icon: const Icon(FontAwesomeIcons.clock), selectIcon: const Icon(FontAwesomeIcons.solidClock), - onTap: () => handleState(videoIntroController.viewLater), - selectStatus: videoIntroController.hasLater.value, + onTap: () => handleState(ugcIntroController.viewLater), + selectStatus: ugcIntroController.hasLater.value, semanticsLabel: '再看', text: '再看', ), ), ActionItem( icon: const Icon(FontAwesomeIcons.shareFromSquare), - onTap: () => videoIntroController.actionShareVideo(context), + onTap: () => ugcIntroController.actionShareVideo(context), selectStatus: false, semanticsLabel: '分享', text: !isLoading @@ -717,7 +719,7 @@ class _VideoIntroPanelState extends State onTap: () { if (item.mid == ownerMid && !isPortrait && - introController.horizontalMemberPage) { + ugcIntroController.horizontalMemberPage) { widget.onShowMemberPage(ownerMid); } else { Get.toNamed( @@ -761,8 +763,9 @@ class _VideoIntroPanelState extends State right: -6, child: Obx( () => - introController.staffRelations['status'] == true && - introController.staffRelations['${item.mid}'] == null + ugcIntroController.staffRelations['status'] == true && + ugcIntroController.staffRelations['${item.mid}'] == + null ? Material( type: MaterialType.transparency, shape: const CircleBorder(), @@ -773,7 +776,8 @@ class _VideoIntroPanelState extends State mid: item.mid, isFollow: false, callback: (val) { - introController.staffRelations['${item.mid}'] = + ugcIntroController + .staffRelations['${item.mid}'] = true; }, ), @@ -834,7 +838,7 @@ class _VideoIntroPanelState extends State behavior: HitTestBehavior.opaque, child: Obx( () { - final userStat = introController.userStat.value; + final userStat = ugcIntroController.userStat.value; final isVip = (userStat.card?.vip?.status ?? 0) > 0; return Row( mainAxisSize: MainAxisSize.min, @@ -904,10 +908,10 @@ class _VideoIntroPanelState extends State color: theme.colorScheme.outline, semanticLabel: '无痕', ), - if (introController.isShowOnlineTotal) + if (ugcIntroController.isShowOnlineTotal) Obx( () => Text( - '${introController.total.value}人在看', + '${ugcIntroController.total.value}人在看', style: TextStyle( fontSize: 12, color: theme.colorScheme.outline, @@ -926,15 +930,15 @@ class _VideoIntroPanelState extends State label: 'AI总结', child: GestureDetector( onTap: () async { - if (introController.aiConclusionResult == null) { - await introController.aiConclusion(); + if (ugcIntroController.aiConclusionResult == null) { + await ugcIntroController.aiConclusion(); } - if (introController.aiConclusionResult == null) { + if (ugcIntroController.aiConclusionResult == null) { return; } - if (introController.aiConclusionResult!.summary?.isNotEmpty == + if (ugcIntroController.aiConclusionResult!.summary?.isNotEmpty == true || - introController.aiConclusionResult!.outline?.isNotEmpty == + ugcIntroController.aiConclusionResult!.outline?.isNotEmpty == true) { widget.showAiBottomSheet(); } else { diff --git a/lib/pages/video/introduction/ugc/widgets/page.dart b/lib/pages/video/introduction/ugc/widgets/page.dart index b3c225e4b..9faa35ae7 100644 --- a/lib/pages/video/introduction/ugc/widgets/page.dart +++ b/lib/pages/video/introduction/ugc/widgets/page.dart @@ -16,7 +16,7 @@ class PagesPanel extends StatefulWidget { required this.bvid, required this.heroTag, this.showEpisodes, - required this.videoIntroController, + required this.ugcIntroController, }); final List? list; @@ -25,7 +25,7 @@ class PagesPanel extends StatefulWidget { final String bvid; final String heroTag; final Function? showEpisodes; - final VideoIntroController videoIntroController; + final UgcIntroController ugcIntroController; @override State createState() => _PagesPanelState(); @@ -39,7 +39,7 @@ class _PagesPanelState extends State { StreamSubscription? _listener; List get pages => - widget.list ?? widget.videoIntroController.videoDetail.value.pages!; + widget.list ?? widget.ugcIntroController.videoDetail.value.pages!; @override void initState() { @@ -48,7 +48,7 @@ class _PagesPanelState extends State { tag: widget.heroTag, ); if (widget.list == null) { - cid = widget.videoIntroController.lastPlayCid.value; + cid = widget.ugcIntroController.cid.value; pageIndex = pages.indexWhere((Part e) => e.cid == cid); _listener = _videoDetailController.cid.listen((int cid) { this.cid = cid; @@ -156,7 +156,7 @@ class _PagesPanelState extends State { if (widget.showEpisodes == null) { Get.back(); } - widget.videoIntroController.changeSeasonOrbangu( + widget.ugcIntroController.onChangeEpisode( null, widget.bvid, item.cid, @@ -165,7 +165,7 @@ class _PagesPanelState extends State { ); if (widget.list != null && widget - .videoIntroController + .ugcIntroController .videoDetail .value .ugcSeason != diff --git a/lib/pages/video/introduction/ugc/widgets/season.dart b/lib/pages/video/introduction/ugc/widgets/season.dart index c031944d9..277e06546 100644 --- a/lib/pages/video/introduction/ugc/widgets/season.dart +++ b/lib/pages/video/introduction/ugc/widgets/season.dart @@ -11,17 +11,17 @@ import 'package:get/get.dart'; class SeasonPanel extends StatefulWidget { const SeasonPanel({ super.key, - required this.changeFuc, + required this.onChangeEpisode, required this.heroTag, required this.showEpisodes, this.onTap, - required this.videoIntroController, + required this.ugcIntroController, }); - final Function changeFuc; + final Function onChangeEpisode; final String heroTag; final Function showEpisodes; final bool? onTap; - final VideoIntroController videoIntroController; + final UgcIntroController ugcIntroController; @override State createState() => _SeasonPanelState(); @@ -33,9 +33,9 @@ class _SeasonPanelState extends State { StreamSubscription? _listener; List episodes = []; - VideoIntroController get videoIntroController => widget.videoIntroController; + UgcIntroController get ugcIntroController => widget.ugcIntroController; VideoDetailData get videoDetail => - widget.videoIntroController.videoDetail.value; + widget.ugcIntroController.videoDetail.value; @override void initState() { @@ -44,13 +44,12 @@ class _SeasonPanelState extends State { tag: widget.heroTag, ); - _videoDetailController.seasonCid = - videoIntroController.lastPlayCid.value != 0 + _videoDetailController.seasonCid = ugcIntroController.cid.value != 0 ? (videoDetail.pages?.isNotEmpty == true ? videoDetail.isPageReversed ? videoDetail.pages!.last.cid : videoDetail.pages!.first.cid - : videoIntroController.lastPlayCid.value) + : ugcIntroController.cid.value) : videoDetail.isPageReversed ? videoDetail.pages!.last.cid : videoDetail.pages!.first.cid; diff --git a/lib/pages/video/member/view.dart b/lib/pages/video/member/view.dart index 2ee38e584..4924e89d8 100644 --- a/lib/pages/video/member/view.dart +++ b/lib/pages/video/member/view.dart @@ -30,12 +30,12 @@ class HorizontalMemberPage extends StatefulWidget { super.key, required this.mid, required this.videoDetailController, - required this.videoIntroController, + required this.ugcIntroController, }); final dynamic mid; final VideoDetailController videoDetailController; - final VideoIntroController videoIntroController; + final UgcIntroController ugcIntroController; @override State createState() => _HorizontalMemberPageState(); @@ -200,8 +200,8 @@ class _HorizontalMemberPageState extends State { videoItem: videoItem, bvid: _bvid, onTap: () { - final status = widget.videoIntroController - .changeSeasonOrbangu( + final status = widget.ugcIntroController + .onChangeEpisode( null, videoItem.bvid, videoItem.cid, diff --git a/lib/pages/video/post_panel/view.dart b/lib/pages/video/post_panel/view.dart index 61e77f117..8c774d37e 100644 --- a/lib/pages/video/post_panel/view.dart +++ b/lib/pages/video/post_panel/view.dart @@ -51,6 +51,14 @@ class _PostPanelState extends CommonCollapseSlidePageState { double get currentPos => plPlayerController.position.value.inMilliseconds / 1000; + final _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget buildPage(ThemeData theme) { return Scaffold( @@ -104,7 +112,7 @@ class _PostPanelState extends CommonCollapseSlidePageState { clipBehavior: Clip.none, children: [ SingleChildScrollView( - controller: ScrollController(), + controller: _controller, physics: const AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only(bottom: 88 + bottom), child: Column( diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 84b0545ad..94e316aa1 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -11,12 +11,12 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/main.dart'; import 'package:PiliPlus/models/common/episode_panel_type.dart'; -import 'package:PiliPlus/models/common/search_type.dart'; import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart' as pgc; import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart'; import 'package:PiliPlus/models_new/video/video_detail/episode.dart'; import 'package:PiliPlus/models_new/video/video_detail/page.dart'; import 'package:PiliPlus/models_new/video/video_tag/data.dart'; +import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/danmaku/view.dart'; import 'package:PiliPlus/pages/episode_panel/view.dart'; import 'package:PiliPlus/pages/video/ai_conclusion/view.dart'; @@ -77,12 +77,18 @@ class VideoDetailPageV extends StatefulWidget { class _VideoDetailPageVState extends State with TickerProviderStateMixin, RouteAware, WidgetsBindingObserver { - late VideoDetailController videoDetailController; - late VideoReplyController _videoReplyController; + late final VideoDetailController videoDetailController; + late final VideoReplyController _videoReplyController; PlPlayerController? plPlayerController; - late VideoIntroController videoIntroController; - late PgcIntroController pgcIntroController; - late final _introController = ScrollController(); + late final CommonIntroController introController = videoDetailController.isUgc + ? ugcIntroController + : pgcIntroController; + late final UgcIntroController ugcIntroController; + late final PgcIntroController pgcIntroController; + ScrollController? _introScrollController; + ScrollController get introScrollController => + _introScrollController ??= ScrollController(); + late String heroTag; bool get autoExitFullscreen => @@ -100,7 +106,10 @@ class _VideoDetailPageVState extends State bool get isFullScreen => plPlayerController?.isFullScreen.value ?? false; bool get _shouldShowSeasonPanel { - late final videoDetail = videoIntroController.videoDetail.value; + if (!videoDetailController.isUgc) { + return false; + } + late final videoDetail = ugcIntroController.videoDetail.value; return videoDetailController.plPlayerController.horizontalSeasonPanel && (videoDetail.ugcSeason != null || ((videoDetail.pages?.length ?? 0) > 1)) && @@ -135,8 +144,9 @@ class _VideoDetailPageVState extends State tag: heroTag, ); } - videoIntroController = Get.put(VideoIntroController(), tag: heroTag); - if (videoDetailController.videoType == SearchType.media_bangumi) { + if (videoDetailController.isUgc) { + ugcIntroController = Get.put(UgcIntroController(), tag: heroTag); + } else { pgcIntroController = Get.put(PgcIntroController(), tag: heroTag); } @@ -180,7 +190,7 @@ class _VideoDetailPageVState extends State @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.resumed) { - videoIntroController.startTimer(); + introController.startTimer(); videoDetailController.plPlayerController.showDanmaku = true; // 修复从后台恢复时全屏状态下屏幕方向错误的问题 @@ -200,7 +210,7 @@ class _VideoDetailPageVState extends State }); } } else if (state == AppLifecycleState.paused) { - videoIntroController.canelTimer(); + introController.canelTimer(); videoDetailController.plPlayerController.showDanmaku = false; } } @@ -256,11 +266,9 @@ class _VideoDetailPageVState extends State /// 顺序播放 列表循环 if (plPlayerController!.playRepeat != PlayRepeat.pause && plPlayerController!.playRepeat != PlayRepeat.singleCycle) { - if (videoDetailController.isPlayAll || - videoDetailController.videoType == SearchType.video) { - notExitFlag = videoIntroController.nextPlay(); - } else if (videoDetailController.videoType == - SearchType.media_bangumi) { + if (videoDetailController.isUgc) { + notExitFlag = ugcIntroController.nextPlay(); + } else { notExitFlag = pgcIntroController.nextPlay(); } } @@ -346,10 +354,16 @@ class _VideoDetailPageVState extends State ScreenBrightness.instance.resetApplicationScreenBrightness(); PlPlayerController.setPlayCallBack(null); } - videoDetailController.positionSubscription?.cancel(); - videoIntroController.canelTimer(); - videoIntroController.videoDetail.close(); - videoDetailController.cid.close(); + videoDetailController + ..positionSubscription?.cancel() + ..cid.close(); + if (videoDetailController.isUgc) { + ugcIntroController + ..canelTimer() + ..videoDetail.close(); + } else { + pgcIntroController.canelTimer(); + } if (!videoDetailController.horizontalScreen) { AutoOrientation.portraitUpMode(); } @@ -359,14 +373,16 @@ class _VideoDetailPageVState extends State } if (plPlayerController != null) { videoDetailController.makeHeartBeat(); - plPlayerController!.removeStatusLister(playerListener); - plPlayerController!.removePositionListener(positionListener); - plPlayerController!.dispose(); + plPlayerController! + ..removeStatusLister(playerListener) + ..removePositionListener(positionListener) + ..dispose(); } else { PlPlayerController.updatePlayCount(); } VideoDetailPageV.routeObserver.unsubscribe(this); showStatusBar(); + _introScrollController?.dispose(); super.dispose(); } @@ -382,7 +398,8 @@ class _VideoDetailPageVState extends State ScreenBrightness.instance.resetApplicationScreenBrightness(); videoDetailController.positionSubscription?.cancel(); - videoIntroController.canelTimer(); + + introController.canelTimer(); videoDetailController ..playerStatus = plPlayerController?.playerStatus.status.value @@ -416,7 +433,9 @@ class _VideoDetailPageVState extends State isShowing = true; PlPlayerController.setPlayCallBack(playCallBack); - videoIntroController.startTimer(); + + introController.startTimer(); + if (mounted) { if (videoDetailController.brightness != null) { plPlayerController?.setCurrBrightness( @@ -769,11 +788,10 @@ class _VideoDetailPageVState extends State .colorScheme .onSurface, ), - onSelected: (String type) async { + onSelected: (String type) { switch (type) { case 'later': - await videoIntroController - .viewLater(); + introController.viewLater(); break; case 'report': if (!Accounts.main.isLogin) { @@ -1127,7 +1145,7 @@ class _VideoDetailPageVState extends State buildTabbar( introText: '相关视频', showIntro: - videoDetailController.videoType == SearchType.video && + videoDetailController.isUgc && videoDetailController .plPlayerController .showRelatedVideo, @@ -1137,13 +1155,12 @@ class _VideoDetailPageVState extends State child: videoTabBarView( controller: videoDetailController.tabCtr, children: [ - if (videoDetailController.videoType == - SearchType.video && + if (videoDetailController.isUgc && videoDetailController .plPlayerController .showRelatedVideo) CustomScrollView( - controller: _introController, + controller: introScrollController, slivers: [ RelatedVideoPanel( key: relatedVideoPanelKey, @@ -1215,14 +1232,12 @@ class _VideoDetailPageVState extends State key: Key(heroTag), plPlayerController: plPlayerController!, videoDetailController: videoDetailController, - videoIntroController: - videoDetailController.videoType == SearchType.video - ? videoIntroController - : null, - pgcIntroController: - videoDetailController.videoType == SearchType.media_bangumi - ? pgcIntroController + ugcIntroController: videoDetailController.isUgc + ? ugcIntroController : null, + pgcIntroController: videoDetailController.isUgc + ? null + : pgcIntroController, headerControl: HeaderControl( controller: plPlayerController!, videoDetailCtr: videoDetailController, @@ -1232,11 +1247,9 @@ class _VideoDetailPageVState extends State ? null : Obx( () => PlDanmaku( - key: Key( - videoDetailController.danmakuCid.value.toString(), - ), + key: Key(videoDetailController.cid.value.toString()), isPipMode: true, - cid: videoDetailController.danmakuCid.value, + cid: videoDetailController.cid.value, playerController: plPlayerController!, ), ), @@ -1321,10 +1334,10 @@ class _VideoDetailPageVState extends State ), ], ), - onSelected: (String type) async { + onSelected: (String type) { switch (type) { case 'later': - await videoIntroController.viewLater(); + introController.viewLater(); break; case 'report': if (!Accounts.main.isLogin) { @@ -1400,14 +1413,12 @@ class _VideoDetailPageVState extends State key: Key(heroTag), plPlayerController: plPlayerController!, videoDetailController: videoDetailController, - videoIntroController: - videoDetailController.videoType == SearchType.video - ? videoIntroController - : null, - pgcIntroController: - videoDetailController.videoType == SearchType.media_bangumi - ? pgcIntroController + ugcIntroController: videoDetailController.isUgc + ? ugcIntroController : null, + pgcIntroController: videoDetailController.isUgc + ? null + : pgcIntroController, headerControl: HeaderControl( key: videoDetailController.headerCtrKey, controller: videoDetailController.plPlayerController, @@ -1416,8 +1427,8 @@ class _VideoDetailPageVState extends State ), danmuWidget: Obx( () => PlDanmaku( - key: Key(videoDetailController.danmakuCid.value.toString()), - cid: videoDetailController.danmakuCid.value, + key: Key(videoDetailController.cid.value.toString()), + cid: videoDetailController.cid.value, playerController: plPlayerController!, ), ), @@ -1507,7 +1518,7 @@ class _VideoDetailPageVState extends State } String text = tabs[value]; if (text == '简介' || text == '相关视频') { - _introController.animToTop(); + _introScrollController?.animToTop(); } else if (text.startsWith('评论')) { _videoReplyController.animateToTop(); } @@ -1759,7 +1770,7 @@ class _VideoDetailPageVState extends State MaterialTapTargetSize.shrinkWrap, ), onPressed: () { - videoIntroController.changeSeasonOrbangu( + ugcIntroController.onChangeEpisode( null, videoDetailController.bvid, item.cid, @@ -1795,13 +1806,13 @@ class _VideoDetailPageVState extends State final bottom = MediaQuery.paddingOf(context).bottom; Widget introPanel() => CustomScrollView( key: const PageStorageKey('简介'), - controller: needCtr ? _introController : null, + controller: needCtr ? introScrollController : null, physics: !needCtr ? const AlwaysScrollableScrollPhysics(parent: ClampingScrollPhysics()) : null, slivers: [ - if (videoDetailController.videoType == SearchType.video) ...[ - VideoIntroPanel( + if (videoDetailController.isUgc) ...[ + UgcIntroPanel( key: ugcPanelKey, heroTag: heroTag, showAiBottomSheet: showAiBottomSheet, @@ -1828,7 +1839,7 @@ class _VideoDetailPageVState extends State height: bottom + StyleString.safeSpace, ), ), - ] else if (videoDetailController.videoType == SearchType.media_bangumi) + ] else Obx( () => PgcIntroPage( key: pgcPanelKey, @@ -1901,7 +1912,7 @@ class _VideoDetailPageVState extends State } Widget get seasonPanel { - final videoDetail = videoIntroController.videoDetail.value; + final videoDetail = ugcIntroController.videoDetail.value; return Column( children: [ if ((videoDetail.pages?.length ?? 0) > 1) @@ -1910,8 +1921,8 @@ class _VideoDetailPageVState extends State padding: const EdgeInsets.symmetric(horizontal: 14), child: PagesPanel( heroTag: heroTag, - videoIntroController: videoIntroController, - bvid: videoIntroController.bvid, + ugcIntroController: ugcIntroController, + bvid: ugcIntroController.bvid, showEpisodes: showEpisodes, ), ) @@ -1921,7 +1932,9 @@ class _VideoDetailPageVState extends State () => EpisodePanel( heroTag: heroTag, enableSlide: false, - videoIntroController: videoIntroController, + ugcIntroController: videoDetailController.isUgc + ? ugcIntroController + : null, type: EpisodeType.part, list: [videoDetail.pages!], cover: videoDetailController.cover.value, @@ -1929,15 +1942,11 @@ class _VideoDetailPageVState extends State aid: IdUtils.bv2av(videoDetailController.bvid), cid: videoDetailController.cid.value, isReversed: videoDetail.isPageReversed, - changeFucCall: - videoDetailController.videoType == - SearchType.media_bangumi - ? pgcIntroController.changeSeasonOrbangu - : videoIntroController.changeSeasonOrbangu, + onChangeEpisode: videoDetailController.isUgc + ? ugcIntroController.onChangeEpisode + : pgcIntroController.onChangeEpisode, showTitle: false, - isSupportReverse: - videoDetailController.videoType != - SearchType.media_bangumi, + isSupportReverse: videoDetailController.isUgc, onReverse: () => onReversePlay( bvid: videoDetailController.bvid, aid: IdUtils.bv2av(videoDetailController.bvid), @@ -1959,9 +1968,9 @@ class _VideoDetailPageVState extends State child: SeasonPanel( heroTag: heroTag, onTap: false, - changeFuc: videoIntroController.changeSeasonOrbangu, + onChangeEpisode: ugcIntroController.onChangeEpisode, showEpisodes: showEpisodes, - videoIntroController: videoIntroController, + ugcIntroController: ugcIntroController, ), ), Expanded( @@ -1969,7 +1978,9 @@ class _VideoDetailPageVState extends State () => EpisodePanel( heroTag: heroTag, enableSlide: false, - videoIntroController: videoIntroController, + ugcIntroController: videoDetailController.isUgc + ? ugcIntroController + : null, type: EpisodeType.season, initialTabIndex: videoDetailController.seasonIndex.value, cover: videoDetailController.cover.value, @@ -1978,19 +1989,17 @@ class _VideoDetailPageVState extends State bvid: videoDetailController.bvid, aid: IdUtils.bv2av(videoDetailController.bvid), cid: videoDetailController.seasonCid ?? 0, - isReversed: videoIntroController + isReversed: ugcIntroController .videoDetail .value .ugcSeason! .sections![videoDetailController.seasonIndex.value] .isReversed, - changeFucCall: - videoDetailController.videoType == SearchType.media_bangumi - ? pgcIntroController.changeSeasonOrbangu - : videoIntroController.changeSeasonOrbangu, + onChangeEpisode: videoDetailController.isUgc + ? ugcIntroController.onChangeEpisode + : pgcIntroController.onChangeEpisode, showTitle: false, - isSupportReverse: - videoDetailController.videoType != SearchType.media_bangumi, + isSupportReverse: videoDetailController.isUgc, onReverse: () => onReversePlay( bvid: videoDetailController.bvid, aid: IdUtils.bv2av(videoDetailController.bvid), @@ -2051,7 +2060,7 @@ class _VideoDetailPageVState extends State videoDetailController.childKey.currentState?.showBottomSheet( backgroundColor: Colors.transparent, (context) => - AiConclusionPanel(item: videoIntroController.aiConclusionResult!), + AiConclusionPanel(item: ugcIntroController.aiConclusionResult!), ); } @@ -2075,7 +2084,9 @@ class _VideoDetailPageVState extends State } Widget listSheetContent([bool? enableSlide]) => EpisodePanel( heroTag: heroTag, - videoIntroController: videoIntroController, + ugcIntroController: videoDetailController.isUgc + ? ugcIntroController + : null, type: season != null ? EpisodeType.season : episodes is List @@ -2089,21 +2100,20 @@ class _VideoDetailPageVState extends State cid: cid, seasonId: season?.id, list: season != null ? season.sections : [episodes], - isReversed: videoDetailController.videoType == SearchType.media_bangumi + isReversed: !videoDetailController.isUgc ? null : season != null - ? videoIntroController + ? ugcIntroController .videoDetail .value .ugcSeason! .sections![videoDetailController.seasonIndex.value] .isReversed - : videoIntroController.videoDetail.value.isPageReversed, - isSupportReverse: - videoDetailController.videoType != SearchType.media_bangumi, - changeFucCall: videoDetailController.videoType == SearchType.media_bangumi - ? pgcIntroController.changeSeasonOrbangu - : videoIntroController.changeSeasonOrbangu, + : ugcIntroController.videoDetail.value.isPageReversed, + isSupportReverse: videoDetailController.isUgc, + onChangeEpisode: videoDetailController.isUgc + ? ugcIntroController.onChangeEpisode + : pgcIntroController.onChangeEpisode, onClose: Get.back, onReverse: () { Get.back(); @@ -2143,10 +2153,10 @@ class _VideoDetailPageVState extends State return; } - void changeEpisode(episode) { + void onChangeEpisode(episode) { final isEpisode = episode is BaseEpisodeItem; final isPgc = episode is pgc.EpisodeItem; - videoIntroController.changeSeasonOrbangu( + ugcIntroController.onChangeEpisode( isPgc ? episode.epId : null, isEpisode ? episode.bvid : bvid, episode.cid, @@ -2159,7 +2169,7 @@ class _VideoDetailPageVState extends State ); } - final videoDetail = videoIntroController.videoDetail.value; + final videoDetail = ugcIntroController.videoDetail.value; if (isSeason) { // reverse season final item = videoDetail @@ -2176,7 +2186,7 @@ class _VideoDetailPageVState extends State ..cid.refresh(); } else { // switch to first episode - var episode = videoIntroController + var episode = ugcIntroController .videoDetail .value .ugcSeason! @@ -2184,7 +2194,7 @@ class _VideoDetailPageVState extends State .episodes! .first; if (episode.cid != videoDetailController.cid.value) { - changeEpisode(episode); + onChangeEpisode(episode); videoDetailController.seasonCid = episode.cid; } else { videoDetailController @@ -2204,7 +2214,7 @@ class _VideoDetailPageVState extends State // switch to first episode var episode = videoDetail.pages!.first; if (episode.cid != videoDetailController.cid.value) { - changeEpisode(episode); + onChangeEpisode(episode); } else { videoDetailController.cid.refresh(); } @@ -2264,7 +2274,7 @@ class _VideoDetailPageVState extends State return HorizontalMemberPage( mid: mid, videoDetailController: videoDetailController, - videoIntroController: videoIntroController, + ugcIntroController: ugcIntroController, ); }, ); diff --git a/lib/pages/video/view_point/view.dart b/lib/pages/video/view_point/view.dart index 4e361bea0..66baa9014 100644 --- a/lib/pages/video/view_point/view.dart +++ b/lib/pages/video/view_point/view.dart @@ -32,6 +32,14 @@ class _ViewPointsPageState int currentIndex = -1; + final _controller = ScrollController(); + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + @override Widget buildPage(ThemeData theme) { return Scaffold( @@ -92,7 +100,7 @@ class _ViewPointsPageState color: theme.dividerColor.withValues(alpha: 0.1), ); return ListView.separated( - controller: ScrollController(), + controller: _controller, physics: const AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only( bottom: MediaQuery.paddingOf(context).bottom + 80, diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index b74957411..17ea8121c 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -4,13 +4,13 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; -import 'package:PiliPlus/models/common/search_type.dart'; import 'package:PiliPlus/models/common/super_resolution_type.dart'; import 'package:PiliPlus/models/common/video/audio_quality.dart'; import 'package:PiliPlus/models/common/video/cdn_type.dart'; import 'package:PiliPlus/models/common/video/video_decode_type.dart'; import 'package:PiliPlus/models/common/video/video_quality.dart'; import 'package:PiliPlus/models/video/play/url.dart'; +import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart'; import 'package:PiliPlus/pages/setting/widgets/switch_item.dart'; import 'package:PiliPlus/pages/video/controller.dart'; @@ -64,12 +64,17 @@ class HeaderControl extends StatefulWidget { } class HeaderControlState extends State { - PlayUrlModel get videoInfo => videoDetailCtr.data; + late final PlPlayerController plPlayerController = widget.controller; + late final VideoDetailController videoDetailCtr = widget.videoDetailCtr; + late final PlayUrlModel videoInfo = videoDetailCtr.data; static const TextStyle subTitleStyle = TextStyle(fontSize: 12); static const TextStyle titleStyle = TextStyle(fontSize: 14); String get heroTag => widget.heroTag; - late VideoIntroController videoIntroController; - late PgcIntroController pgcIntroController; + late final UgcIntroController ugcIntroController; + late final PgcIntroController pgcIntroController; + late final CommonIntroController introController = videoDetailCtr.isUgc + ? ugcIntroController + : pgcIntroController; bool get horizontalScreen => videoDetailCtr.horizontalScreen; RxString now = ''.obs; Timer? clock; @@ -78,14 +83,12 @@ class HeaderControlState extends State { late final _coinKey = GlobalKey(); late final _favKey = GlobalKey(); - PlPlayerController get plPlayerController => widget.controller; - VideoDetailController get videoDetailCtr => widget.videoDetailCtr; - @override void initState() { super.initState(); - videoIntroController = Get.find(tag: heroTag); - if (videoDetailCtr.videoType != SearchType.video) { + if (videoDetailCtr.isUgc) { + ugcIntroController = Get.find(tag: heroTag); + } else { pgcIntroController = Get.find(tag: heroTag); } } @@ -130,7 +133,7 @@ class HeaderControlState extends State { dense: true, onTap: () { Get.back(); - videoIntroController.viewLater(); + introController.viewLater(); }, leading: const Icon(Icons.watch_later_outlined, size: 20), title: const Text('添加至「稍后再看」', style: titleStyle), @@ -874,7 +877,7 @@ class HeaderControlState extends State { ); if (res.statusCode == 200) { final name = - '${videoIntroController.videoDetail.value.title}-${videoDetailCtr.bvid}-${videoDetailCtr.cid.value}-${item.lanDoc}.json'; + '${introController.videoDetail.value.title}-${videoDetailCtr.bvid}-${videoDetailCtr.cid.value}-${item.lanDoc}.json'; try { DocumentFileSavePlusPlatform.instance .saveMultipleFiles( @@ -1897,7 +1900,7 @@ class HeaderControlState extends State { }, ), ), - if ((videoIntroController.videoDetail.value.title != null) && + if ((introController.videoDetail.value.title != null) && (isFullScreen || (!isFullScreen && !horizontalScreen && @@ -1914,7 +1917,7 @@ class HeaderControlState extends State { () { String title; final videoDetail = - videoIntroController.videoDetail.value; + introController.videoDetail.value; if (videoDetail.videos == 1) { title = videoDetail.title!; } else { @@ -1984,10 +1987,10 @@ class HeaderControlState extends State { ); }, ), - if (videoIntroController.isShowOnlineTotal) + if (introController.isShowOnlineTotal) Obx( () => Text( - '${videoIntroController.total.value}人正在看', + '${introController.total.value}人正在看', style: const TextStyle( color: Colors.white, fontSize: 11, @@ -2226,7 +2229,7 @@ class HeaderControlState extends State { ? Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - if (videoDetailCtr.videoType == SearchType.video) ...[ + if (videoDetailCtr.isUgc) ...[ SizedBox( width: 42, height: 34, @@ -2240,20 +2243,20 @@ class HeaderControlState extends State { selectIcon: const Icon( FontAwesomeIcons.solidThumbsUp, ), - onTap: videoIntroController.actionLikeVideo, + onTap: ugcIntroController.actionLikeVideo, onLongPress: () { - videoIntroController.actionOneThree(); + ugcIntroController.actionOneThree(); plPlayerController ..isTriple = null ..hideTaskControls(); }, - selectStatus: videoIntroController.hasLike.value, + selectStatus: ugcIntroController.hasLike.value, semanticsLabel: '点赞', needAnim: true, hasTriple: - videoIntroController.hasLike.value && - videoIntroController.hasCoin && - videoIntroController.hasFav.value, + ugcIntroController.hasLike.value && + ugcIntroController.hasCoin && + ugcIntroController.hasFav.value, callBack: (start) { if (start) { HapticFeedback.lightImpact(); @@ -2284,8 +2287,8 @@ class HeaderControlState extends State { selectIcon: const Icon( FontAwesomeIcons.solidThumbsDown, ), - onTap: videoIntroController.actionDislikeVideo, - selectStatus: videoIntroController.hasDislike.value, + onTap: ugcIntroController.actionDislikeVideo, + selectStatus: ugcIntroController.hasDislike.value, semanticsLabel: '点踩', ), ), @@ -2302,8 +2305,8 @@ class HeaderControlState extends State { color: Colors.white, ), selectIcon: const Icon(FontAwesomeIcons.b), - onTap: videoIntroController.actionCoinVideo, - selectStatus: videoIntroController.hasCoin, + onTap: ugcIntroController.actionCoinVideo, + selectStatus: ugcIntroController.hasCoin, semanticsLabel: '投币', needAnim: true, ), @@ -2321,11 +2324,11 @@ class HeaderControlState extends State { color: Colors.white, ), selectIcon: const Icon(FontAwesomeIcons.solidStar), - onTap: () => videoIntroController - .showFavBottomSheet(context), - onLongPress: () => videoIntroController + onTap: () => + ugcIntroController.showFavBottomSheet(context), + onLongPress: () => ugcIntroController .showFavBottomSheet(context, isLongPress: true), - selectStatus: videoIntroController.hasFav.value, + selectStatus: ugcIntroController.hasFav.value, semanticsLabel: '收藏', needAnim: true, ), @@ -2341,7 +2344,7 @@ class HeaderControlState extends State { color: Colors.white, ), onTap: () => - videoIntroController.actionShareVideo(context), + ugcIntroController.actionShareVideo(context), semanticsLabel: '分享', ), ), diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 8dfa47342..0bb63a672 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -10,6 +10,7 @@ import 'package:PiliPlus/models_new/video/video_detail/episode.dart'; import 'package:PiliPlus/models_new/video/video_detail/page.dart'; import 'package:PiliPlus/models_new/video/video_detail/section.dart'; import 'package:PiliPlus/models_new/video/video_shot/data.dart'; +import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/video/controller.dart'; import 'package:PiliPlus/pages/video/introduction/pgc/controller.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart'; @@ -48,7 +49,7 @@ class PLVideoPlayer extends StatefulWidget { const PLVideoPlayer({ required this.plPlayerController, this.videoDetailController, - this.videoIntroController, + this.ugcIntroController, this.pgcIntroController, required this.headerControl, this.bottomControl, @@ -64,7 +65,7 @@ class PLVideoPlayer extends StatefulWidget { final PlPlayerController plPlayerController; final VideoDetailController? videoDetailController; - final VideoIntroController? videoIntroController; + final UgcIntroController? ugcIntroController; final PgcIntroController? pgcIntroController; final Widget headerControl; final Widget? bottomControl; @@ -86,8 +87,12 @@ class _PLVideoPlayerState extends State with TickerProviderStateMixin { late AnimationController animationController; late VideoController videoController; - VideoIntroController? videoIntroController; + UgcIntroController? ugcIntroController; PgcIntroController? pgcIntroController; + late final CommonIntroController introController = + widget.videoDetailController!.isUgc + ? ugcIntroController! + : pgcIntroController!; final GlobalKey _playerKey = GlobalKey(); final GlobalKey key = GlobalKey(); @@ -170,7 +175,7 @@ class _PLVideoPlayerState extends State duration: const Duration(milliseconds: 100), ); videoController = plPlayerController.videoController!; - videoIntroController = widget.videoIntroController; + ugcIntroController = widget.ugcIntroController; pgcIntroController = widget.pgcIntroController; Future.microtask(() async { try { @@ -250,9 +255,9 @@ class _PLVideoPlayerState extends State // 动态构建底部控制条 Widget buildBottomControl() { - final videoDetail = videoIntroController?.videoDetail.value; - bool isSeason = videoDetail?.ugcSeason != null; - bool isPage = videoDetail?.pages != null && videoDetail!.pages!.length > 1; + final videoDetail = introController.videoDetail.value; + bool isSeason = videoDetail.ugcSeason != null; + bool isPage = videoDetail.pages != null && videoDetail.pages!.length > 1; bool isPgc = pgcIntroController != null; bool anySeason = isSeason || isPage || isPgc; double widgetWidth = isFullScreen && context.isLandscape ? 42 : 35; @@ -270,14 +275,7 @@ class _PLVideoPlayerState extends State color: Colors.white, ), onTap: () { - bool? res; - if (videoIntroController != null) { - res = videoIntroController!.prevPlay(); - } - if (pgcIntroController != null) { - res = pgcIntroController!.prevPlay(); - } - if (res == false) { + if (!introController.prevPlay()) { SmartDialog.showToast('已经是第一集了'); } }, @@ -302,14 +300,7 @@ class _PLVideoPlayerState extends State color: Colors.white, ), onTap: () { - bool? res; - if (videoIntroController != null) { - res = videoIntroController!.nextPlay(); - } - if (pgcIntroController != null) { - res = pgcIntroController!.nextPlay(); - } - if (res == false) { + if (!introController.nextPlay()) { SmartDialog.showToast('已经是最后一集了'); } }, @@ -477,7 +468,7 @@ class _PLVideoPlayerState extends State int currentCid = plPlayerController.cid; String bvid = plPlayerController.bvid; List episodes = []; - final videoDetail = videoIntroController!.videoDetail.value; + final videoDetail = introController.videoDetail.value; if (isSeason) { final List sections = videoDetail.ugcSeason!.sections!;