From f113cdc364b3d03c2f2993ad5e88742c18132909 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 24 Jun 2023 12:14:25 +0800 Subject: [PATCH] =?UTF-8?q?mod:=20=E5=90=88=E9=9B=86season=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/video_detail_res.dart | 113 ++++++++++++++++++ .../widgets/media_bangumi_panel.dart | 6 +- lib/pages/video/detail/controller.dart | 1 - .../video/detail/introduction/controller.dart | 2 +- lib/pages/video/detail/introduction/view.dart | 9 ++ .../detail/introduction/widgets/season.dart | 99 +++++++++++++++ lib/pages/video/detail/view.dart | 6 +- 7 files changed, 231 insertions(+), 5 deletions(-) create mode 100644 lib/pages/video/detail/introduction/widgets/season.dart diff --git a/lib/models/video_detail_res.dart b/lib/models/video_detail_res.dart index 8b5180f3..5b16d70c 100644 --- a/lib/models/video_detail_res.dart +++ b/lib/models/video_detail_res.dart @@ -60,6 +60,7 @@ class VideoDetailData { List? pages; Subtitle? subtitle; // Label? label; + UgcSeason? ugcSeason; bool? isSeasonDisplay; UserGarb? userGarb; HonorReply? honorReply; @@ -94,6 +95,7 @@ class VideoDetailData { this.noCache, this.pages, this.subtitle, + this.ugcSeason, this.isSeasonDisplay, this.userGarb, this.honorReply, @@ -137,6 +139,9 @@ class VideoDetailData { : List.from(json["pages"]!.map((e) => Page.fromJson(e))); subtitle = json["subtitle"] == null ? null : Subtitle.fromJson(json["subtitle"]); + ugcSeason = json["ugc_season"] != null + ? UgcSeason.fromJson(json["ugc_season"]) + : null; isSeasonDisplay = json["is_season_display"]; userGarb = json["user_garb"] == null ? null : UserGarb.fromJson(json["user_garb"]); @@ -522,3 +527,111 @@ class UserGarb { } class Label {} + +class UgcSeason { + UgcSeason({ + this.id, + this.title, + this.cover, + this.mid, + this.intro, + this.signState, + this.attribute, + this.sections, + this.stat, + this.epCount, + this.seasonType, + this.isPaySeason, + }); + + int? id; + String? title; + String? cover; + int? mid; + String? intro; + int? signState; + int? attribute; + List? sections; + Stat? stat; + int? epCount; + int? seasonType; + bool? isPaySeason; + + UgcSeason.fromJson(Map json) { + id = json['id']; + title = json['title']; + cover = json['cover']; + mid = json['mid']; + intro = json['intro']; + signState = json['sign_state']; + attribute = json['attribute']; + sections = json['sections'] + .map((e) => SectionItem.fromJson(e)) + .toList(); + stat = Stat.fromJson(json['stat']); + epCount = json['ep_count']; + seasonType = json['season_type']; + isPaySeason = json['is_pay_count']; + } +} + +class SectionItem { + SectionItem({ + this.seasonId, + this.id, + this.title, + this.type, + this.episodes, + }); + + int? seasonId; + int? id; + String? title; + int? type; + List? episodes; + + SectionItem.fromJson(Map json) { + seasonId = json['season_id']; + id = json['id']; + title = json['title']; + type = json['type']; + episodes = json['episodes'] + .map((e) => EpisodeItem.fromJson(e)) + .toList(); + } +} + +class EpisodeItem { + EpisodeItem({ + this.seasonId, + this.sectionId, + this.id, + this.aid, + this.cid, + this.title, + this.attribute, + this.page, + this.bvid, + }); + int? seasonId; + int? sectionId; + int? id; + int? aid; + int? cid; + String? title; + int? attribute; + Page? page; + String? bvid; + + EpisodeItem.fromJson(Map json) { + seasonId = json['season_id']; + sectionId = json['sectionId']; + id = json['id']; + aid = json['aid']; + cid = json['cid']; + title = json['title']; + attribute = json['attribute']; + page = Page.fromJson(json['page']); + bvid = json['bvid']; + } +} diff --git a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart index f7d73e73..863c55a4 100644 --- a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart +++ b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/utils/utils.dart'; @@ -11,7 +12,10 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) { itemBuilder: (context, index) { var i = list![index]; return InkWell( - onTap: () {}, + onTap: () { + Get.toNamed('/video?bvid=${i.bvid}&cid=${i.cid}', + arguments: {'videoItem': i, 'heroTag': Utils.makeHeroTag(i.id)}); + }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 85521a52..af097a70 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -113,7 +113,6 @@ class VideoDetailController extends GetxController { // 视频链接 queryVideoUrl() async { - print('🐶🐶🐶'); var result = await VideoHttp.videoUrl(cid: cid, bvid: bvid); // log('result: ${result.toString()}'); if (result['status']) { diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 00685a17..18629609 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -76,7 +76,7 @@ class VideoIntroController extends GetxController { userLogin = user.get(UserBoxKey.userLogin) != null; } - // 获取视频简介 + // 获取视频简介&分p Future queryVideoIntro() async { var result = await VideoHttp.videoIntro(bvid: bvid); if (result['status']) { diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index f1e4340d..1a9ca176 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -16,6 +16,8 @@ import 'package:pilipala/pages/video/detail/introduction/controller.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; +import 'widgets/season.dart'; + class VideoIntroPanel extends StatefulWidget { const VideoIntroPanel({Key? key}) : super(key: key); @@ -342,7 +344,14 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ), const SizedBox(height: 8), + // 点赞收藏转发 _actionGrid(context, videoIntroController), + // 合集 + if (!widget.loadingStatus && + widget.videoDetail!.ugcSeason != null) ...[ + seasonPanel(widget.videoDetail!.ugcSeason!, + widget.videoDetail!.pages!.first.cid) + ], Divider( height: 26, color: Theme.of(context).dividerColor.withOpacity(0.1), diff --git a/lib/pages/video/detail/introduction/widgets/season.dart b/lib/pages/video/detail/introduction/widgets/season.dart new file mode 100644 index 00000000..61598f8c --- /dev/null +++ b/lib/pages/video/detail/introduction/widgets/season.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/models/video_detail_res.dart'; + +Widget seasonPanel(UgcSeason ugcSeason, cid) { + return Builder(builder: (context) { + List episodes = ugcSeason.sections!.first.episodes!; + int currentIndex = episodes.indexWhere((e) => e.cid == cid); + return Container( + margin: const EdgeInsets.only( + top: 15, + left: 2, + right: 2, + ), + child: Material( + color: Theme.of(context).colorScheme.onInverseSurface, + borderRadius: BorderRadius.circular(6), + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () => showBottomSheet( + context: context, + builder: (_) => Container( + height: Get.size.height - Get.size.width * 9 / 16 - 45, + color: Theme.of(context).colorScheme.background, + child: Column( + children: [ + Container( + height: 45, + padding: const EdgeInsets.only(left: 14, right: 14), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '合集(${episodes.length})', + style: Theme.of(context).textTheme.titleMedium, + ), + IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ), + Divider( + height: 1, + color: Theme.of(context).dividerColor.withOpacity(0.1), + ), + Expanded( + child: Material( + child: ListView.builder( + itemCount: episodes.length, + itemBuilder: (context, index) { + return InkWell( + onTap: () {}, + child: Padding( + padding: const EdgeInsets.only( + top: 10, bottom: 10, left: 15, right: 15), + child: Text( + episodes[index].title!, + style: TextStyle( + color: index == currentIndex + ? Theme.of(context).colorScheme.primary + : Theme.of(context) + .colorScheme + .onSurface), + ), + ), + ); + }, + ), + ), + ), + ], + ), + ), + ), + child: Padding( + padding: const EdgeInsets.fromLTRB(10, 10, 10, 10), + child: Row( + children: [ + Text('合集:${ugcSeason.title!}'), + const Spacer(), + Text( + '${currentIndex + 1} / ${ugcSeason.epCount}', + style: Theme.of(context).textTheme.labelSmall, + ), + const SizedBox(width: 2), + const Icon( + Icons.arrow_forward_ios_outlined, + size: 13, + ) + ], + ), + ), + ), + ), + ); + }); +} diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 52069e3f..781148de 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -59,6 +59,10 @@ class _VideoDetailPageState extends State setState(() {}); Wakelock.disable(); } + // 播放完成停止 or 切换下一个 + if (status == PlayerStatus.completed) { + _meeduPlayerController!.pause(); + } }, ); @@ -67,8 +71,6 @@ class _VideoDetailPageState extends State _extendNestCtr.addListener( () { - print(_extendNestCtr.position.pixels); - double offset = _extendNestCtr.position.pixels; if (offset > doubleOffset) { animationController.forward();