From 779d3c7eb2daa9e1d72ab39828898382dc0f6845 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 10 Aug 2023 22:14:13 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=80=89=E9=9B=86=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video/detail/introduction/controller.dart | 6 + lib/pages/video/detail/introduction/view.dart | 13 ++ .../introduction/widgets/intro_detail.dart | 30 +-- .../detail/introduction/widgets/page.dart | 203 ++++++++++++++++++ 4 files changed, 239 insertions(+), 13 deletions(-) create mode 100644 lib/pages/video/detail/introduction/widgets/page.dart diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 9a4039c7..55b63445 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -51,6 +51,8 @@ class VideoIntroController extends GetxController { RxMap followStatus = {}.obs; int _tempThemeValue = -1; + RxInt lastPlayCid = 0.obs; + @override void onInit() { super.onInit(); @@ -76,6 +78,7 @@ class VideoIntroController extends GetxController { } } userLogin = user.get(UserBoxKey.userLogin) != null; + lastPlayCid.value = int.parse(Get.parameters['cid']!); } // 获取视频简介&分p @@ -83,6 +86,9 @@ class VideoIntroController extends GetxController { var result = await VideoHttp.videoIntro(bvid: bvid); if (result['status']) { videoDetail.value = result['data']!; + if (videoDetail.value.pages!.isNotEmpty && lastPlayCid.value == 0) { + lastPlayCid.value = videoDetail.value.pages!.first.cid!; + } Get.find(tag: Get.arguments['heroTag']) .tabs .value = ['简介', '评论 ${result['data']!.stat!.reply}']; diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 4f4c29bc..2a6aa172 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -19,6 +19,7 @@ import 'widgets/action_item.dart'; import 'widgets/action_row_item.dart'; import 'widgets/fav_panel.dart'; import 'widgets/intro_detail.dart'; +import 'widgets/page.dart'; import 'widgets/season.dart'; class VideoIntroPanel extends StatefulWidget { @@ -274,6 +275,18 @@ class _VideoInfoState extends State with TickerProviderStateMixin { .changeSeasonOrbangu(bvid, cid, aid), ) ], + if (!loadingStatus && + widget.videoDetail!.pages != null && + widget.videoDetail!.pages!.length > 1) ...[ + Obx(() => PagesPanel( + pages: widget.videoDetail!.pages!, + cid: videoIntroController.lastPlayCid.value, + sheetHeight: sheetHeight, + changeFuc: (cid) => + videoIntroController.changeSeasonOrbangu( + videoIntroController.bvid, cid, null), + )) + ], GestureDetector( onTap: onPushMember, child: Container( diff --git a/lib/pages/video/detail/introduction/widgets/intro_detail.dart b/lib/pages/video/detail/introduction/widgets/intro_detail.dart index dd771d7c..35d60eda 100644 --- a/lib/pages/video/detail/introduction/widgets/intro_detail.dart +++ b/lib/pages/video/detail/introduction/widgets/intro_detail.dart @@ -27,19 +27,23 @@ class IntroDetail extends StatelessWidget { height: sheetHeight, child: Column( children: [ - Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .onSecondaryContainer - .withOpacity(0.5), - borderRadius: const BorderRadius.all(Radius.circular(3))), + InkWell( + onTap: () => Get.back(), + child: Container( + height: 35, + padding: const EdgeInsets.only(bottom: 2), + child: Center( + child: Container( + width: 32, + height: 3, + decoration: BoxDecoration( + color: Theme.of(context) + .colorScheme + .onSecondaryContainer + .withOpacity(0.5), + borderRadius: + const BorderRadius.all(Radius.circular(3))), + ), ), ), ), diff --git a/lib/pages/video/detail/introduction/widgets/page.dart b/lib/pages/video/detail/introduction/widgets/page.dart new file mode 100644 index 00000000..261b6227 --- /dev/null +++ b/lib/pages/video/detail/introduction/widgets/page.dart @@ -0,0 +1,203 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/models/video_detail_res.dart'; + +class PagesPanel extends StatefulWidget { + final List pages; + final int? cid; + final double? sheetHeight; + final Function? changeFuc; + + const PagesPanel({ + super.key, + required this.pages, + this.cid, + this.sheetHeight, + this.changeFuc, + }); + + @override + State createState() => _PagesPanelState(); +} + +class _PagesPanelState extends State { + late List episodes; + late int currentIndex; + + @override + void initState() { + super.initState(); + episodes = widget.pages; + currentIndex = episodes.indexWhere((e) => e.cid == widget.cid); + } + + void changeFucCall(item, i) async { + await widget.changeFuc!( + item.cid, + ); + currentIndex = i; + setState(() {}); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10, bottom: 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('视频选集 '), + Expanded( + child: Text( + ' 正在播放:${widget.pages[currentIndex].pagePart}', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), + ), + ), + const SizedBox(width: 10), + SizedBox( + height: 34, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () { + showBottomSheet( + context: context, + builder: (_) => Container( + height: widget.sheetHeight, + 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: () { + changeFucCall(episodes[index], index); + Get.back(); + }, + child: Padding( + padding: const EdgeInsets.only( + top: 10, + bottom: 10, + left: 15, + right: 15), + child: Text( + episodes[index].pagePart!, + style: TextStyle( + color: index == currentIndex + ? Theme.of(context) + .colorScheme + .primary + : Theme.of(context) + .colorScheme + .onSurface), + ), + ), + ); + }, + ), + ), + ), + ], + ), + ), + ); + }, + child: Text( + '共${widget.pages.length}集', + style: const TextStyle(fontSize: 13), + ), + ), + ), + ], + ), + ), + Container( + height: 35, + margin: const EdgeInsets.only(bottom: 8), + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: widget.pages.length, + itemExtent: 150, + itemBuilder: ((context, i) { + return Container( + width: 150, + margin: const EdgeInsets.only(right: 10), + child: Material( + color: Theme.of(context).colorScheme.onInverseSurface, + borderRadius: BorderRadius.circular(6), + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () => changeFucCall(widget.pages[i], i), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 8, horizontal: 8), + child: Row( + children: [ + if (i == currentIndex) ...[ + Image.asset( + 'assets/images/live.gif', + color: Theme.of(context).colorScheme.primary, + height: 12, + ), + const SizedBox(width: 6) + ], + Expanded( + child: Text( + widget.pages[i].pagePart!, + maxLines: 1, + style: TextStyle( + fontSize: 13, + color: i == currentIndex + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface), + overflow: TextOverflow.ellipsis, + )) + ], + ), + ), + ), + ), + ); + }), + ), + ) + ], + ); + } +}