From 171c16a4f923e1e5791504a88b52417070591a1f Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 21 Apr 2023 14:06:01 +0800 Subject: [PATCH] =?UTF-8?q?mod:=20=E7=9B=B8=E5=85=B3=E6=8E=A8=E8=8D=90?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E5=BC=80=E5=8F=91=E3=80=81=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E8=B7=B3=E8=BD=ACHero=E3=80=81=E4=B8=80=E4=BA=9B=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/widgets/video_card_h.dart | 23 +++++---- lib/http/api.dart | 3 ++ lib/http/video.dart | 8 +-- lib/models/model_hot_video_item.dart | 4 +- lib/pages/video/detail/controller.dart | 4 ++ .../video/detail/introduction/controller.dart | 5 ++ .../video/detail/introduction/index.dart | 2 +- lib/pages/video/detail/introduction/view.dart | 17 ++++--- lib/pages/video/detail/player/controller.dart | 0 lib/pages/video/detail/player/index.dart | 4 ++ lib/pages/video/detail/player/view.dart | 0 .../video/detail/related/controller.dart | 31 ++++++++++++ lib/pages/video/detail/related/index.dart | 4 ++ lib/pages/video/detail/related/view.dart | 49 +++++++++++++++++++ lib/pages/video/detail/view.dart | 29 +++++++---- 15 files changed, 152 insertions(+), 31 deletions(-) create mode 100644 lib/pages/video/detail/player/controller.dart create mode 100644 lib/pages/video/detail/player/index.dart create mode 100644 lib/pages/video/detail/player/view.dart create mode 100644 lib/pages/video/detail/related/controller.dart create mode 100644 lib/pages/video/detail/related/index.dart create mode 100644 lib/pages/video/detail/related/view.dart diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart index 5333ad72..5156a191 100644 --- a/lib/common/widgets/video_card_h.dart +++ b/lib/common/widgets/video_card_h.dart @@ -13,13 +13,15 @@ class VideoCardH extends StatelessWidget { @override Widget build(BuildContext context) { + int aid = videoItem.aid; + String heroTag = Utils.makeHeroTag(aid); return Material( child: Ink( child: InkWell( onTap: () async { await Future.delayed(const Duration(milliseconds: 200)); - int aid = videoItem['id'] ?? videoItem['aid']; - Get.toNamed('/video?aid=$aid', arguments: {'videoItem': videoItem}); + Get.toNamed('/video?aid=$aid', + arguments: {'videoItem': videoItem, 'heroTag': heroTag}); }, child: Container( padding: const EdgeInsets.fromLTRB( @@ -44,12 +46,15 @@ class VideoCardH extends StatelessWidget { double PR = MediaQuery.of(context).devicePixelRatio; return Stack( children: [ - NetworkImgLayer( - // src: videoItem['pic'] + - // '@${(maxWidth * 2).toInt()}w', - src: videoItem.pic + '@.webp', - width: maxWidth, - height: maxHeight, + Hero( + tag: heroTag, + child: NetworkImgLayer( + // src: videoItem['pic'] + + // '@${(maxWidth * 2).toInt()}w', + src: videoItem.pic + '@.webp', + width: maxWidth, + height: maxHeight, + ), ), // Image.network( videoItem['pic'], width: double.infinity, height: double.infinity,), Positioned( @@ -109,7 +114,7 @@ class VideoContent extends StatelessWidget { overflow: TextOverflow.ellipsis, ), const Spacer(), - if (videoItem.rcmdReason != '' && + if (videoItem.rcmdReason != null && videoItem.rcmdReason.content != '') Container( padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 5), diff --git a/lib/http/api.dart b/lib/http/api.dart index ccea17f7..4f088015 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -6,4 +6,7 @@ class Api { // 视频详情 // 竖屏 https://api.bilibili.com/x/web-interface/view?aid=527403921 static const String videoDetail = '/x/web-interface/view'; + + // 视频详情页 相关视频 + static const String relatedList = '/x/web-interface/archive/related'; } diff --git a/lib/http/video.dart b/lib/http/video.dart index 98d448bd..9e023051 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -25,8 +25,8 @@ class VideoHttp { } } - // static Future videoRecommend(data) async { - // var res = await Request().get(Api.videoRecommend, data: data); - // return res; - // } + static Future videoRecommend(data) async { + var res = await Request().get(Api.relatedList, data: data); + return res; + } } diff --git a/lib/models/model_hot_video_item.dart b/lib/models/model_hot_video_item.dart index 7c30dcd4..1a9f582e 100644 --- a/lib/models/model_hot_video_item.dart +++ b/lib/models/model_hot_video_item.dart @@ -80,7 +80,9 @@ class HotVideoItemModel { pubLocation = json["pub_location"]; seasontype = json["seasontype"]; isOgv = json["isOgv"]; - rcmdReason = RcmdReason.fromJson(json['rcmd_reason']); + rcmdReason = json['rcmd_reason'] != '' + ? RcmdReason.fromJson(json['rcmd_reason']) + : null; } } diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 5feddde6..89142e01 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -1,6 +1,9 @@ import 'package:get/get.dart'; class VideoDetailController extends GetxController { + // tabs + RxList tabs = ['简介', '评论'].obs; + // 视频aid String aid = Get.parameters['aid']!; @@ -14,6 +17,7 @@ class VideoDetailController extends GetxController { RxBool isLoading = false.obs; String heroTag = ''; + @override void onInit() { super.onInit(); diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 1480c004..e098880d 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -2,6 +2,7 @@ import 'package:get/get.dart'; import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/init.dart'; import 'package:pilipala/models/video_detail_res.dart'; +import 'package:pilipala/pages/video/detail/controller.dart'; class VideoIntroController extends GetxController { // 视频aid @@ -41,6 +42,10 @@ class VideoIntroController extends GetxController { }); VideoDetailResponse result = VideoDetailResponse.fromJson(res.data); videoDetail.value = result.data!; + Get.find().tabs.value = [ + '简介', + '评论 ${result.data!.stat!.reply}' + ]; // await Future.delayed(const Duration(seconds: 3)); return true; } diff --git a/lib/pages/video/detail/introduction/index.dart b/lib/pages/video/detail/introduction/index.dart index 60b98c3c..5eaae572 100644 --- a/lib/pages/video/detail/introduction/index.dart +++ b/lib/pages/video/detail/introduction/index.dart @@ -1,4 +1,4 @@ -library video_detail_introduction; +library video_intro_panel; export './controller.dart'; export './view.dart'; diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 4ddaa53c..41e624d4 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -1,4 +1,3 @@ -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:pilipala/common/constants.dart'; @@ -17,11 +16,16 @@ class VideoIntroPanel extends StatefulWidget { State createState() => _VideoIntroPanelState(); } -class _VideoIntroPanelState extends State { +class _VideoIntroPanelState extends State + with AutomaticKeepAliveClientMixin { final VideoIntroController videoIntroController = Get.put(VideoIntroController()); VideoDetailData? videoDetail; + // 添加页面缓存 + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); @@ -42,10 +46,10 @@ class _VideoIntroPanelState extends State { future: videoIntroController.queryVideoDetail(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { - print(snapshot.data); if (snapshot.data) { // 请求成功 - return _buildView(context, false, videoDetail); + // return _buildView(context, false, videoDetail); + return VideoInfo(loadingStatus: false, videoDetail: videoDetail); } else { // 请求错误 return Center( @@ -58,7 +62,8 @@ class _VideoIntroPanelState extends State { ); } } else { - return _buildView(context, true, videoDetail); + // return _buildView(context, true, videoDetail); + return VideoInfo(loadingStatus: true, videoDetail: videoDetail); } }, ); @@ -320,7 +325,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ), _actionGrid(context), - const SizedBox(height: 5), + // const SizedBox(height: 5), ], ) : const Center(child: CircularProgressIndicator()), diff --git a/lib/pages/video/detail/player/controller.dart b/lib/pages/video/detail/player/controller.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/pages/video/detail/player/index.dart b/lib/pages/video/detail/player/index.dart new file mode 100644 index 00000000..c5d4ff78 --- /dev/null +++ b/lib/pages/video/detail/player/index.dart @@ -0,0 +1,4 @@ +library video_player; + +export './controller.dart'; +export './view.dart'; diff --git a/lib/pages/video/detail/player/view.dart b/lib/pages/video/detail/player/view.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/pages/video/detail/related/controller.dart b/lib/pages/video/detail/related/controller.dart new file mode 100644 index 00000000..872f8871 --- /dev/null +++ b/lib/pages/video/detail/related/controller.dart @@ -0,0 +1,31 @@ +import 'dart:convert'; + +import 'package:get/get.dart'; +import 'package:pilipala/http/video.dart'; +import 'package:pilipala/models/model_hot_video_item.dart'; + +class ReleatedController extends GetxController { + // 视频aid + String aid = Get.parameters['aid']!; + // 推荐视频列表 + List relatedVideoList = []; + + Future queryVideoRecommend() async { + try { + var res = await VideoHttp.videoRecommend({'aid': aid}); + List list = []; + try { + for (var i in res.data['data']) { + list.add(HotVideoItemModel.fromJson(i)); + } + relatedVideoList = list; + } catch (err) { + return err.toString(); + } + + return res.data['data']; + } catch (err) { + return err.toString(); + } + } +} diff --git a/lib/pages/video/detail/related/index.dart b/lib/pages/video/detail/related/index.dart new file mode 100644 index 00000000..ce29b10a --- /dev/null +++ b/lib/pages/video/detail/related/index.dart @@ -0,0 +1,4 @@ +library releated_video_panel; + +export './controller.dart'; +export './view.dart'; diff --git a/lib/pages/video/detail/related/view.dart b/lib/pages/video/detail/related/view.dart new file mode 100644 index 00000000..319e75d4 --- /dev/null +++ b/lib/pages/video/detail/related/view.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/common/widgets/video_card_h.dart'; +import './controller.dart'; + +class RelatedVideoPanel extends StatefulWidget { + const RelatedVideoPanel({super.key}); + + @override + State createState() => _RelatedVideoPanelState(); +} + +class _RelatedVideoPanelState extends State { + final ReleatedController _releatedController = Get.put(ReleatedController()); + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _releatedController.queryVideoRecommend(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.data!.isNotEmpty) { + // 请求成功 + List videoList = _releatedController.relatedVideoList; + return SliverList( + delegate: SliverChildBuilderDelegate((context, index) { + if (index == videoList.length) { + return SizedBox(height: MediaQuery.of(context).padding.bottom); + } else { + return VideoCardH( + videoItem: videoList[index], + ); + } + }, childCount: videoList.length + 1)); + } else { + // 请求错误 + return const Center( + child: Text('出错了'), + ); + } + } else { + return const SliverToBoxAdapter( + child: Text('请求中'), + ); + } + }, + ); + } +} diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index d0ad3a85..eb088f19 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/introduction/index.dart'; +import 'package:pilipala/pages/video/detail/related/index.dart'; class VideoDetailPage extends StatefulWidget { const VideoDetailPage({Key? key}) : super(key: key); @@ -15,12 +16,10 @@ class _VideoDetailPageState extends State { final VideoDetailController videoDetailController = Get.put(VideoDetailController()); - final _tabs = ['简介', '评论']; - @override Widget build(BuildContext context) { return DefaultTabController( - length: _tabs.length, // tab的数量. + length: videoDetailController.tabs.length, // tab的数量. child: SafeArea( top: false, bottom: false, @@ -80,14 +79,16 @@ class _VideoDetailPageState extends State { mainAxisSize: MainAxisSize.max, children: [ Container( - width: 180, + width: 280, margin: const EdgeInsets.only(left: 20), - child: TabBar( - splashBorderRadius: BorderRadius.circular(6), - dividerColor: Colors.transparent, - tabs: _tabs - .map((String name) => Tab(text: name)) - .toList(), + child: Obx( + () => TabBar( + splashBorderRadius: BorderRadius.circular(6), + dividerColor: Colors.transparent, + tabs: videoDetailController.tabs + .map((String name) => Tab(text: name)) + .toList(), + ), ), ), // 弹幕开关 @@ -117,6 +118,14 @@ class _VideoDetailPageState extends State { context), ), const VideoIntroPanel(), + SliverToBoxAdapter( + child: Divider( + color: + Theme.of(context).dividerColor.withOpacity(0.1), + ), + ), + const SliverPadding(padding: EdgeInsets.only(bottom: 5)), + const RelatedVideoPanel(), ], ); }),