diff --git a/lib/common/pages_bottom_sheet.dart b/lib/common/pages_bottom_sheet.dart index c64b58b6..54f14654 100644 --- a/lib/common/pages_bottom_sheet.dart +++ b/lib/common/pages_bottom_sheet.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import '../models/common/video_episode_type.dart'; @@ -44,25 +45,38 @@ class EpisodeBottomSheet { title = '第${episode.title}话 ${episode.longTitle!}'; break; } - return ListTile( + return InkWell( onTap: () { SmartDialog.showToast('切换至「$title」'); changeFucCall.call(episode, index); }, - dense: false, - leading: isCurrentIndex - ? Image.asset( - 'assets/images/live.gif', - color: primary, - height: 12, - ) - : null, - title: Text( - title, - style: TextStyle( - fontSize: 14, - color: isCurrentIndex ? primary : onSurface, - ), + child: Padding( + padding: const EdgeInsets.only(left: 14, right: 14, top: 8, bottom: 8), + child: isFullScreen + ? Text( + title, + maxLines: 1, + style: TextStyle( + fontSize: 14, + color: isCurrentIndex ? primary : onSurface, + ), + ) + : Row( + children: [ + NetworkImgLayer(width: 130, height: 75, src: episode.cover), + const SizedBox(width: 10), + Expanded( + child: Text( + title, + maxLines: 2, + style: TextStyle( + fontSize: 14, + color: isCurrentIndex ? primary : onSurface, + ), + ), + ), + ], + ), ), ); } diff --git a/lib/models/model_hot_video_item.dart b/lib/models/model_hot_video_item.dart index db331a4c..ab7e6e04 100644 --- a/lib/models/model_hot_video_item.dart +++ b/lib/models/model_hot_video_item.dart @@ -23,6 +23,7 @@ class HotVideoItemModel { this.dimension, this.shortLinkV2, this.firstFrame, + this.cover, this.pubLocation, this.seasontype, this.isOgv, @@ -50,6 +51,7 @@ class HotVideoItemModel { Dimension? dimension; String? shortLinkV2; String? firstFrame; + String? cover; String? pubLocation; int? seasontype; bool? isOgv; @@ -77,6 +79,7 @@ class HotVideoItemModel { dimension = Dimension.fromMap(json['dimension']); shortLinkV2 = json["short_link_v2"]; firstFrame = json["first_frame"]; + cover = json["first_frame"]; pubLocation = json["pub_location"]; seasontype = json["seasontype"]; isOgv = json["isOgv"]; diff --git a/lib/models/video_detail_res.dart b/lib/models/video_detail_res.dart index a82b6fbb..b7b1b481 100644 --- a/lib/models/video_detail_res.dart +++ b/lib/models/video_detail_res.dart @@ -382,6 +382,7 @@ class Part { String? weblink; Dimension? dimension; String? firstFrame; + String? cover; Part({ this.cid, @@ -393,6 +394,7 @@ class Part { this.weblink, this.dimension, this.firstFrame, + this.cover, }); fromRawJson(String str) => Part.fromJson(json.decode(str)); @@ -411,6 +413,7 @@ class Part { ? null : Dimension.fromJson(json["dimension"]); firstFrame = json["first_frame"]; + cover = json["first_frame"]; } Map toJson() { @@ -634,6 +637,7 @@ class EpisodeItem { this.attribute, this.page, this.bvid, + this.cover, }); int? seasonId; int? sectionId; @@ -644,6 +648,7 @@ class EpisodeItem { int? attribute; Part? page; String? bvid; + String? cover; EpisodeItem.fromJson(Map json) { seasonId = json['season_id']; @@ -655,6 +660,7 @@ class EpisodeItem { attribute = json['attribute']; page = Part.fromJson(json['page']); bvid = json['bvid']; + cover = json['arc']['pic']; } } diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index 575a77de..65cd5dd8 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -215,7 +215,7 @@ class BangumiIntroController extends GetxController { } // 修改分P或番剧分集 - Future changeSeasonOrbangu(bvid, cid, aid) async { + Future changeSeasonOrbangu(bvid, cid, aid, cover) async { // 重新获取视频资源 VideoDetailController videoDetailCtr = Get.find(tag: Get.arguments['heroTag']); @@ -223,6 +223,7 @@ class BangumiIntroController extends GetxController { videoDetailCtr.cid.value = cid; videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.oid.value = aid; + videoDetailCtr.cover.value = cover; videoDetailCtr.queryVideoUrl(); // 重新请求评论 try { @@ -281,7 +282,8 @@ class BangumiIntroController extends GetxController { int cid = episodes[nextIndex].cid!; String bvid = episodes[nextIndex].bvid!; int aid = episodes[nextIndex].aid!; - changeSeasonOrbangu(bvid, cid, aid); + String cover = episodes[nextIndex].cover!; + changeSeasonOrbangu(bvid, cid, aid, cover); } // 播放器底栏 选集 回调 @@ -302,7 +304,7 @@ class BangumiIntroController extends GetxController { sheetHeight: Get.size.height, isFullScreen: true, changeFucCall: (item, index) { - changeSeasonOrbangu(item.bvid, item.cid, item.aid); + changeSeasonOrbangu(item.bvid, item.cid, item.aid, item.cover); SmartDialog.dismiss(); }, ).buildShowContent(Get.context!), diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index e47db480..6876da79 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -322,8 +322,8 @@ class _BangumiInfoState extends State { pages: widget.bangumiDetail!.episodes!, cid: cid! ?? widget.bangumiDetail!.episodes!.first.cid!, sheetHeight: sheetHeight, - changeFuc: (bvid, cid, aid) => - bangumiIntroController.changeSeasonOrbangu(bvid, cid, aid), + changeFuc: (bvid, cid, aid, cover) => bangumiIntroController + .changeSeasonOrbangu(bvid, cid, aid, cover), bangumiDetail: bangumiIntroController.bangumiDetail.value, bangumiIntroController: bangumiIntroController, ) diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index 3e965f34..3df7ce25 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -84,11 +84,12 @@ class _BangumiPanelState extends State { item.bvid, item.cid, item.aid, + item.cover, ); if (_bottomSheetController != null) { _bottomSheetController?.close(); } - currentIndex = i; + currentIndex.value = i; scrollToIndex(); } diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 2737983c..c6c4bef6 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -73,6 +73,7 @@ class VideoDetailController extends GetxController ReplyItemModel? firstFloor; final scaffoldKey = GlobalKey(); RxString bgCover = ''.obs; + RxString cover = ''.obs; PlPlayerController plPlayerController = PlPlayerController.getInstance(); late VideoItem firstVideo; @@ -120,10 +121,12 @@ class VideoDetailController extends GetxController var args = argMap['videoItem']; if (args.pic != null && args.pic != '') { videoItem['pic'] = args.pic; + cover.value = args.pic; } } if (keys.contains('pic')) { videoItem['pic'] = argMap['pic']; + cover.value = argMap['pic']; } } tabCtr = TabController(length: 2, vsync: this); diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 8d602b83..b9a3ef93 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -432,7 +432,7 @@ class VideoIntroController extends GetxController { } // 修改分P或番剧分集 - Future changeSeasonOrbangu(bvid, cid, aid) async { + Future changeSeasonOrbangu(bvid, cid, aid, cover) async { // 重新获取视频资源 final VideoDetailController videoDetailCtr = Get.find(tag: heroTag); @@ -447,6 +447,7 @@ class VideoIntroController extends GetxController { videoDetailCtr.oid.value = aid ?? IdUtils.bv2av(bvid); videoDetailCtr.cid.value = cid; videoDetailCtr.danmakuCid.value = cid; + videoDetailCtr.cover.value = cover; videoDetailCtr.queryVideoUrl(); // 重新请求评论 try { @@ -494,6 +495,7 @@ class VideoIntroController extends GetxController { void nextPlay() { final List episodes = []; bool isPages = false; + late String cover; if (videoDetail.value.ugcSeason != null) { final UgcSeason ugcSeason = videoDetail.value.ugcSeason!; final List sections = ugcSeason.sections!; @@ -510,6 +512,7 @@ class VideoIntroController extends GetxController { final int currentIndex = episodes.indexWhere((e) => e.cid == lastPlayCid.value); int nextIndex = currentIndex + 1; + cover = episodes[nextIndex].cover; final VideoDetailController videoDetailCtr = Get.find(tag: heroTag); final PlayRepeat platRepeat = videoDetailCtr.plPlayerController.playRepeat; @@ -526,7 +529,7 @@ class VideoIntroController extends GetxController { final int cid = episodes[nextIndex].cid!; final String rBvid = isPages ? bvid : episodes[nextIndex].bvid; final int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[nextIndex].aid!; - changeSeasonOrbangu(rBvid, cid, rAid); + changeSeasonOrbangu(rBvid, cid, rAid, cover); } // 设置关注分组 @@ -591,10 +594,11 @@ class VideoIntroController extends GetxController { isFullScreen: true, changeFucCall: (item, index) { if (dataType == VideoEpidoesType.videoEpisode) { - changeSeasonOrbangu(IdUtils.av2bv(item.aid), item.cid, item.aid); + changeSeasonOrbangu( + IdUtils.av2bv(item.aid), item.cid, item.aid, item.cover); } if (dataType == VideoEpidoesType.videoPart) { - changeSeasonOrbangu(bvid, item.cid, null); + changeSeasonOrbangu(bvid, item.cid, null, item.cover); } SmartDialog.dismiss(); }, diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 597b6def..47404658 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -383,11 +383,12 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ? videoIntroController.lastPlayCid.value : widget.videoDetail!.pages!.first.cid, sheetHeight: videoDetailCtr.sheetHeight.value, - changeFuc: (bvid, cid, aid) => + changeFuc: (bvid, cid, aid, cover) => videoIntroController.changeSeasonOrbangu( bvid, cid, aid, + cover, ), videoIntroCtr: videoIntroController, ), @@ -401,10 +402,12 @@ class _VideoInfoState extends State with TickerProviderStateMixin { pages: widget.videoDetail!.pages!, cid: videoIntroController.lastPlayCid.value, sheetHeight: videoDetailCtr.sheetHeight.value, - changeFuc: (cid) => videoIntroController.changeSeasonOrbangu( + changeFuc: (cid, cover) => + videoIntroController.changeSeasonOrbangu( videoIntroController.bvid, cid, null, + cover, ), videoIntroCtr: videoIntroController, ), diff --git a/lib/pages/video/detail/introduction/widgets/page_panel.dart b/lib/pages/video/detail/introduction/widgets/page_panel.dart index 83db2d52..266f5566 100644 --- a/lib/pages/video/detail/introduction/widgets/page_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/page_panel.dart @@ -58,7 +58,7 @@ class _PagesPanelState extends State { } void changeFucCall(item, i) async { - widget.changeFuc?.call(item.cid); + widget.changeFuc?.call(item.cid, item.cover); currentIndex.value = i; _bottomSheetController?.close(); scrollToIndex(); @@ -129,7 +129,7 @@ class _PagesPanelState extends State { ), ), Container( - height: 35, + height: 55, margin: const EdgeInsets.only(bottom: 8), child: ListView.builder( scrollDirection: Axis.horizontal, @@ -163,7 +163,7 @@ class _PagesPanelState extends State { Expanded( child: Text( widget.pages[i].pagePart!, - maxLines: 1, + maxLines: 2, style: TextStyle( fontSize: 13, color: isCurrentIndex diff --git a/lib/pages/video/detail/introduction/widgets/season_panel.dart b/lib/pages/video/detail/introduction/widgets/season_panel.dart index 2afefcb4..fdfec6f9 100644 --- a/lib/pages/video/detail/introduction/widgets/season_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/season_panel.dart @@ -67,6 +67,7 @@ class _SeasonPanelState extends State { IdUtils.av2bv(item.aid), item.cid, item.aid, + item.cover, ); currentIndex.value = i; _bottomSheetController?.close(); diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 0152a2cb..7f1d6039 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -458,11 +458,17 @@ class _VideoDetailPageState extends State onTap: () { handlePlay(); }, - child: NetworkImgLayer( - type: 'emote', - src: vdCtr.videoItem['pic'], - width: Get.width, - height: videoHeight.value, + child: Obx( + () => AnimatedOpacity( + duration: const Duration(milliseconds: 100), // 渐变动画的持续时间 + opacity: 1, // 设置不透明度 + child: NetworkImgLayer( + type: 'emote', + src: vdCtr.cover.value, + width: Get.width, + height: videoHeight.value, + ), + ), ), ), Positioned(