From ab10223eca6e0936ad6835dab86cdc6ffbef47b2 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 11 Mar 2024 23:03:50 +0800 Subject: [PATCH 01/71] =?UTF-8?q?feat:=20=E6=8E=A5=E6=94=B6=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E7=BB=84=E4=BB=B6=E4=BC=A0=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pl_player/models/bottom_control_type.dart | 1 + lib/plugin/pl_player/view.dart | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/plugin/pl_player/models/bottom_control_type.dart b/lib/plugin/pl_player/models/bottom_control_type.dart index 599f6e4f..739e1d38 100644 --- a/lib/plugin/pl_player/models/bottom_control_type.dart +++ b/lib/plugin/pl_player/models/bottom_control_type.dart @@ -7,4 +7,5 @@ enum BottomControlType { fit, speed, fullscreen, + custom, } diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 0b2e652e..1f3c4156 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -34,6 +34,8 @@ class PLVideoPlayer extends StatefulWidget { this.bottomControl, this.danmuWidget, this.bottomList, + this.customWidget, + this.customWidgets, super.key, }); @@ -42,6 +44,10 @@ class PLVideoPlayer extends StatefulWidget { final PreferredSizeWidget? bottomControl; final Widget? danmuWidget; final List? bottomList; + // List or Widget + + final Widget? customWidget; + final List? customWidgets; @override State createState() => _PLVideoPlayerState(); @@ -310,7 +316,7 @@ class _PLVideoPlayerState extends State ), }; final List list = []; - var userSpecifyItem = widget.bottomList ?? + List userSpecifyItem = widget.bottomList ?? [ BottomControlType.playOrPause, BottomControlType.time, @@ -319,7 +325,16 @@ class _PLVideoPlayerState extends State BottomControlType.fullscreen, ]; for (var i = 0; i < userSpecifyItem.length; i++) { - list.add(videoProgressWidgets[userSpecifyItem[i]]!); + if (userSpecifyItem[i] == BottomControlType.custom) { + if (widget.customWidget != null && widget.customWidget is Widget) { + list.add(widget.customWidget!); + } + if (widget.customWidgets != null && widget.customWidgets!.isNotEmpty) { + list.addAll(widget.customWidgets!); + } + } else { + list.add(videoProgressWidgets[userSpecifyItem[i]]!); + } } return list; } From 11e907d74bc1bbcb68dea7579fe0242dea035791 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Mar 2024 10:48:45 +0800 Subject: [PATCH 02/71] =?UTF-8?q?mod:=20=E5=BC=B9=E5=B9=95=E5=BC=80?= =?UTF-8?q?=E5=85=B3=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index a403e298..69801beb 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -368,7 +368,7 @@ class _VideoDetailPageState extends State !(plPlayerController?.isOpenDanmu.value ?? false); }, - icon: (plPlayerController?.isOpenDanmu.value ?? + icon: !(plPlayerController?.isOpenDanmu.value ?? false) ? SvgPicture.asset( 'assets/images/video/danmu_close.svg', From 77b509fd1703b464fd557b1ca87983f19c62c324 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Mar 2024 13:42:40 +0800 Subject: [PATCH 03/71] =?UTF-8?q?opt:=20=E6=8E=92=E8=A1=8C=E6=A6=9C?= =?UTF-8?q?=E5=88=87=E6=8D=A2tab=E6=95=B0=E6=8D=AE=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/rank/controller.dart | 2 +- lib/pages/rank/zone/view.dart | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/pages/rank/controller.dart b/lib/pages/rank/controller.dart index 61475d97..da73ea02 100644 --- a/lib/pages/rank/controller.dart +++ b/lib/pages/rank/controller.dart @@ -9,7 +9,7 @@ import 'package:pilipala/utils/storage.dart'; class RankController extends GetxController with GetTickerProviderStateMixin { bool flag = false; late RxList tabs = [].obs; - RxInt initialIndex = 1.obs; + RxInt initialIndex = 0.obs; late TabController tabController; late List tabsCtrList; late List tabsPageList; diff --git a/lib/pages/rank/zone/view.dart b/lib/pages/rank/zone/view.dart index 58ca187f..fbf8a524 100644 --- a/lib/pages/rank/zone/view.dart +++ b/lib/pages/rank/zone/view.dart @@ -22,15 +22,20 @@ class ZonePage extends StatefulWidget { State createState() => _ZonePageState(); } -class _ZonePageState extends State { - final ZoneController _zoneController = Get.put(ZoneController()); +class _ZonePageState extends State + with AutomaticKeepAliveClientMixin { + late ZoneController _zoneController; List videoList = []; Future? _futureBuilderFuture; late ScrollController scrollController; + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); + _zoneController = Get.put(ZoneController(), tag: widget.rid.toString()); _futureBuilderFuture = _zoneController.queryRankFeed('init', widget.rid); scrollController = _zoneController.scrollController; StreamController mainStream = @@ -68,6 +73,7 @@ class _ZonePageState extends State { @override Widget build(BuildContext context) { + super.build(context); return RefreshIndicator( onRefresh: () async { return await _zoneController.onRefresh(); From 02d2598d0192e32a4de297d952053956f214f7f3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Mar 2024 16:03:18 +0800 Subject: [PATCH 04/71] =?UTF-8?q?mod:=20=E8=A7=86=E9=A2=91=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=A1=B5=E7=AE=80=E4=BB=8B=E6=9F=A5=E7=9C=8B&?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/introduction/view.dart | 33 ++--- .../introduction/widgets/intro_detail.dart | 130 ++++-------------- .../detail/widgets/expandable_section.dart | 20 +-- 3 files changed, 50 insertions(+), 133 deletions(-) diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 9c1b7db0..831491f6 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -15,6 +15,7 @@ import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; +import '../widgets/expandable_section.dart'; import 'widgets/action_item.dart'; import 'widgets/fav_panel.dart'; import 'widgets/intro_detail.dart'; @@ -137,6 +138,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { late String memberHeroTag; late bool enableAi; bool isProcessing = false; + RxBool isExpand = false.obs; void Function()? handleState(Future Function() action) { return isProcessing ? null @@ -212,13 +214,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { // 视频介绍 showIntroDetail() { feedBack(); - showBottomSheet( - context: context, - enableDrag: true, - builder: (BuildContext context) { - return IntroDetail(videoDetail: widget.videoDetail!); - }, - ); + isExpand.value = !(isExpand.value); } // 用户主页 @@ -330,6 +326,16 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ], ), + /// 视频简介 + Obx( + () => ExpandedSection( + expand: isExpand.value, + begin: 0, + end: 1, + child: IntroDetail(videoDetail: widget.videoDetail!), + ), + ), + /// 点赞收藏转发 actionGrid(context, videoIntroController), // 合集 @@ -438,6 +444,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { margin: const EdgeInsets.only(top: 6, bottom: 4), height: constraints.maxWidth / 5 * 0.8, child: GridView.count( + physics: const NeverScrollableScrollPhysics(), primary: false, padding: EdgeInsets.zero, crossAxisCount: 5, @@ -451,12 +458,6 @@ class _VideoInfoState extends State with TickerProviderStateMixin { selectStatus: videoIntroController.hasLike.value, text: widget.videoDetail!.stat!.like!.toString()), ), - // ActionItem( - // icon: const Icon(FontAwesomeIcons.clock), - // onTap: () => videoIntroController.actionShareVideo(), - // selectStatus: false, - // loadingStatus: loadingStatus, - // text: '稍后再看'), Obx( () => ActionItem( icon: const Icon(FontAwesomeIcons.b), @@ -477,10 +478,10 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ), ActionItem( - icon: const Icon(FontAwesomeIcons.comment), - onTap: () => videoDetailCtr.tabCtr.animateTo(1), + icon: const Icon(FontAwesomeIcons.clock), + onTap: () => videoIntroController.actionShareVideo(), selectStatus: false, - text: widget.videoDetail!.stat!.reply!.toString(), + text: '稍后看', ), ActionItem( icon: const Icon(FontAwesomeIcons.shareFromSquare), diff --git a/lib/pages/video/detail/introduction/widgets/intro_detail.dart b/lib/pages/video/detail/introduction/widgets/intro_detail.dart index c74e27ee..1e9bb842 100644 --- a/lib/pages/video/detail/introduction/widgets/intro_detail.dart +++ b/lib/pages/video/detail/introduction/widgets/intro_detail.dart @@ -1,16 +1,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:hive/hive.dart'; -import 'package:pilipala/common/widgets/stat/danmu.dart'; -import 'package:pilipala/common/widgets/stat/view.dart'; -import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; -Box localCache = GStrorage.localCache; -late double sheetHeight; - class IntroDetail extends StatelessWidget { const IntroDetail({ super.key, @@ -20,105 +14,39 @@ class IntroDetail extends StatelessWidget { @override Widget build(BuildContext context) { - sheetHeight = localCache.get('sheetHeight'); - return Container( - color: Theme.of(context).colorScheme.background, - padding: EdgeInsets.only( - left: 14, - right: 14, - bottom: MediaQuery.of(context).padding.bottom + 20), - height: sheetHeight, + return SizedBox( + width: double.infinity, + child: SelectableRegion( + focusNode: FocusNode(), + selectionControls: MaterialTextSelectionControls(), child: Column( - children: [ - 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.primary, - borderRadius: - const BorderRadius.all(Radius.circular(3))), - ), - ), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData(text: videoDetail!.bvid!)); + SmartDialog.showToast('已复制'); + }, + child: Text( + videoDetail!.bvid!, + style: TextStyle( + fontSize: 13, color: Theme.of(context).colorScheme.primary), ), ), - Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - videoDetail!.title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - Row( - children: [ - StatView( - theme: 'gray', - view: videoDetail!.stat!.view, - size: 'medium', - ), - const SizedBox(width: 10), - StatDanMu( - theme: 'gray', - danmu: videoDetail!.stat!.danmaku, - size: 'medium', - ), - const SizedBox(width: 10), - Text( - Utils.dateFormat(videoDetail!.pubdate, - formatType: 'detail'), - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, - ), - ), - ], - ), - const SizedBox(height: 20), - SizedBox( - width: double.infinity, - child: SelectableRegion( - focusNode: FocusNode(), - selectionControls: MaterialTextSelectionControls(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - videoDetail!.bvid!, - style: const TextStyle(fontSize: 13), - ), - const SizedBox(height: 4), - Text.rich( - style: const TextStyle( - height: 1.4, - // fontSize: 13, - ), - TextSpan( - children: [ - buildContent(context, videoDetail!), - ], - ), - ), - ], - ), - ), - ), - ], - ), + const SizedBox(height: 4), + Text.rich( + style: const TextStyle(height: 1.4), + TextSpan( + children: [ + buildContent(context, videoDetail!), + ], ), - ) + ), ], - )); + ), + ), + ); } InlineSpan buildContent(BuildContext context, content) { diff --git a/lib/pages/video/detail/widgets/expandable_section.dart b/lib/pages/video/detail/widgets/expandable_section.dart index afa68cc9..69e73e20 100644 --- a/lib/pages/video/detail/widgets/expandable_section.dart +++ b/lib/pages/video/detail/widgets/expandable_section.dart @@ -32,28 +32,14 @@ class _ExpandedSectionState extends State _runExpandCheck(); } - ///Setting up the animation - // void prepareAnimations() { - // expandController = AnimationController( - // vsync: this, duration: const Duration(milliseconds: 500)); - // animation = CurvedAnimation( - // parent: expandController, - // curve: Curves.fastOutSlowIn, - // ); - // } - void prepareAnimations() { expandController = AnimationController( vsync: this, duration: const Duration(milliseconds: 400)); Animation curve = CurvedAnimation( parent: expandController, - curve: Curves.fastOutSlowIn, + curve: Curves.linear, ); animation = Tween(begin: widget.begin, end: widget.end).animate(curve); - // animation = CurvedAnimation( - // parent: expandController, - // curve: Curves.fastOutSlowIn, - // ); } void _runExpandCheck() { @@ -67,7 +53,9 @@ class _ExpandedSectionState extends State @override void didUpdateWidget(ExpandedSection oldWidget) { super.didUpdateWidget(oldWidget); - _runExpandCheck(); + if (widget.expand != oldWidget.expand) { + _runExpandCheck(); + } } @override From f8326e7cb5aea074f772836acc42894df94a6d41 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Mar 2024 16:17:02 +0800 Subject: [PATCH 05/71] =?UTF-8?q?fix:=20appbar=E6=BB=91=E5=8A=A8=E8=B7=9D?= =?UTF-8?q?=E7=A6=BB=E7=A7=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/widgets/app_bar.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pages/video/detail/widgets/app_bar.dart b/lib/pages/video/detail/widgets/app_bar.dart index 17f4bec7..efc0b593 100644 --- a/lib/pages/video/detail/widgets/app_bar.dart +++ b/lib/pages/video/detail/widgets/app_bar.dart @@ -17,12 +17,16 @@ class ScrollAppBar extends StatelessWidget { Widget build(BuildContext context) { final double statusBarHeight = MediaQuery.of(context).padding.top; final videoHeight = MediaQuery.sizeOf(context).width * 9 / 16; + double scrollDistance = scrollVal; + if (scrollVal > videoHeight - kToolbarHeight) { + scrollDistance = videoHeight - kToolbarHeight; + } return Positioned( - top: -videoHeight + scrollVal + kToolbarHeight + 0.5, + top: -videoHeight + scrollDistance + kToolbarHeight + 0.5, left: 0, right: 0, child: Opacity( - opacity: scrollVal / (videoHeight - kToolbarHeight), + opacity: scrollDistance / (videoHeight - kToolbarHeight), child: Container( height: statusBarHeight + kToolbarHeight, color: Theme.of(context).colorScheme.background, From a925ef63eb09ebaae30f5558f37999b00d443df3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Mar 2024 16:03:18 +0800 Subject: [PATCH 06/71] =?UTF-8?q?mod:=20=E8=A7=86=E9=A2=91=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=A1=B5=E7=AE=80=E4=BB=8B=E6=9F=A5=E7=9C=8B&?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/introduction/view.dart | 33 ++--- .../introduction/widgets/intro_detail.dart | 130 ++++-------------- .../detail/widgets/expandable_section.dart | 20 +-- 3 files changed, 50 insertions(+), 133 deletions(-) diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 9c1b7db0..831491f6 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -15,6 +15,7 @@ import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; +import '../widgets/expandable_section.dart'; import 'widgets/action_item.dart'; import 'widgets/fav_panel.dart'; import 'widgets/intro_detail.dart'; @@ -137,6 +138,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { late String memberHeroTag; late bool enableAi; bool isProcessing = false; + RxBool isExpand = false.obs; void Function()? handleState(Future Function() action) { return isProcessing ? null @@ -212,13 +214,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { // 视频介绍 showIntroDetail() { feedBack(); - showBottomSheet( - context: context, - enableDrag: true, - builder: (BuildContext context) { - return IntroDetail(videoDetail: widget.videoDetail!); - }, - ); + isExpand.value = !(isExpand.value); } // 用户主页 @@ -330,6 +326,16 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ], ), + /// 视频简介 + Obx( + () => ExpandedSection( + expand: isExpand.value, + begin: 0, + end: 1, + child: IntroDetail(videoDetail: widget.videoDetail!), + ), + ), + /// 点赞收藏转发 actionGrid(context, videoIntroController), // 合集 @@ -438,6 +444,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { margin: const EdgeInsets.only(top: 6, bottom: 4), height: constraints.maxWidth / 5 * 0.8, child: GridView.count( + physics: const NeverScrollableScrollPhysics(), primary: false, padding: EdgeInsets.zero, crossAxisCount: 5, @@ -451,12 +458,6 @@ class _VideoInfoState extends State with TickerProviderStateMixin { selectStatus: videoIntroController.hasLike.value, text: widget.videoDetail!.stat!.like!.toString()), ), - // ActionItem( - // icon: const Icon(FontAwesomeIcons.clock), - // onTap: () => videoIntroController.actionShareVideo(), - // selectStatus: false, - // loadingStatus: loadingStatus, - // text: '稍后再看'), Obx( () => ActionItem( icon: const Icon(FontAwesomeIcons.b), @@ -477,10 +478,10 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ), ActionItem( - icon: const Icon(FontAwesomeIcons.comment), - onTap: () => videoDetailCtr.tabCtr.animateTo(1), + icon: const Icon(FontAwesomeIcons.clock), + onTap: () => videoIntroController.actionShareVideo(), selectStatus: false, - text: widget.videoDetail!.stat!.reply!.toString(), + text: '稍后看', ), ActionItem( icon: const Icon(FontAwesomeIcons.shareFromSquare), diff --git a/lib/pages/video/detail/introduction/widgets/intro_detail.dart b/lib/pages/video/detail/introduction/widgets/intro_detail.dart index c74e27ee..1e9bb842 100644 --- a/lib/pages/video/detail/introduction/widgets/intro_detail.dart +++ b/lib/pages/video/detail/introduction/widgets/intro_detail.dart @@ -1,16 +1,10 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:hive/hive.dart'; -import 'package:pilipala/common/widgets/stat/danmu.dart'; -import 'package:pilipala/common/widgets/stat/view.dart'; -import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; -Box localCache = GStrorage.localCache; -late double sheetHeight; - class IntroDetail extends StatelessWidget { const IntroDetail({ super.key, @@ -20,105 +14,39 @@ class IntroDetail extends StatelessWidget { @override Widget build(BuildContext context) { - sheetHeight = localCache.get('sheetHeight'); - return Container( - color: Theme.of(context).colorScheme.background, - padding: EdgeInsets.only( - left: 14, - right: 14, - bottom: MediaQuery.of(context).padding.bottom + 20), - height: sheetHeight, + return SizedBox( + width: double.infinity, + child: SelectableRegion( + focusNode: FocusNode(), + selectionControls: MaterialTextSelectionControls(), child: Column( - children: [ - 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.primary, - borderRadius: - const BorderRadius.all(Radius.circular(3))), - ), - ), + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 4), + GestureDetector( + onTap: () { + Clipboard.setData(ClipboardData(text: videoDetail!.bvid!)); + SmartDialog.showToast('已复制'); + }, + child: Text( + videoDetail!.bvid!, + style: TextStyle( + fontSize: 13, color: Theme.of(context).colorScheme.primary), ), ), - Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - videoDetail!.title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - ), - ), - const SizedBox(height: 6), - Row( - children: [ - StatView( - theme: 'gray', - view: videoDetail!.stat!.view, - size: 'medium', - ), - const SizedBox(width: 10), - StatDanMu( - theme: 'gray', - danmu: videoDetail!.stat!.danmaku, - size: 'medium', - ), - const SizedBox(width: 10), - Text( - Utils.dateFormat(videoDetail!.pubdate, - formatType: 'detail'), - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, - ), - ), - ], - ), - const SizedBox(height: 20), - SizedBox( - width: double.infinity, - child: SelectableRegion( - focusNode: FocusNode(), - selectionControls: MaterialTextSelectionControls(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - videoDetail!.bvid!, - style: const TextStyle(fontSize: 13), - ), - const SizedBox(height: 4), - Text.rich( - style: const TextStyle( - height: 1.4, - // fontSize: 13, - ), - TextSpan( - children: [ - buildContent(context, videoDetail!), - ], - ), - ), - ], - ), - ), - ), - ], - ), + const SizedBox(height: 4), + Text.rich( + style: const TextStyle(height: 1.4), + TextSpan( + children: [ + buildContent(context, videoDetail!), + ], ), - ) + ), ], - )); + ), + ), + ); } InlineSpan buildContent(BuildContext context, content) { diff --git a/lib/pages/video/detail/widgets/expandable_section.dart b/lib/pages/video/detail/widgets/expandable_section.dart index afa68cc9..69e73e20 100644 --- a/lib/pages/video/detail/widgets/expandable_section.dart +++ b/lib/pages/video/detail/widgets/expandable_section.dart @@ -32,28 +32,14 @@ class _ExpandedSectionState extends State _runExpandCheck(); } - ///Setting up the animation - // void prepareAnimations() { - // expandController = AnimationController( - // vsync: this, duration: const Duration(milliseconds: 500)); - // animation = CurvedAnimation( - // parent: expandController, - // curve: Curves.fastOutSlowIn, - // ); - // } - void prepareAnimations() { expandController = AnimationController( vsync: this, duration: const Duration(milliseconds: 400)); Animation curve = CurvedAnimation( parent: expandController, - curve: Curves.fastOutSlowIn, + curve: Curves.linear, ); animation = Tween(begin: widget.begin, end: widget.end).animate(curve); - // animation = CurvedAnimation( - // parent: expandController, - // curve: Curves.fastOutSlowIn, - // ); } void _runExpandCheck() { @@ -67,7 +53,9 @@ class _ExpandedSectionState extends State @override void didUpdateWidget(ExpandedSection oldWidget) { super.didUpdateWidget(oldWidget); - _runExpandCheck(); + if (widget.expand != oldWidget.expand) { + _runExpandCheck(); + } } @override From 7e7bb1f43a4c23f0b3473ca58506c93da51912ec Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Mar 2024 16:17:02 +0800 Subject: [PATCH 07/71] =?UTF-8?q?fix:=20appbar=E6=BB=91=E5=8A=A8=E8=B7=9D?= =?UTF-8?q?=E7=A6=BB=E7=A7=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/widgets/app_bar.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pages/video/detail/widgets/app_bar.dart b/lib/pages/video/detail/widgets/app_bar.dart index 17f4bec7..efc0b593 100644 --- a/lib/pages/video/detail/widgets/app_bar.dart +++ b/lib/pages/video/detail/widgets/app_bar.dart @@ -17,12 +17,16 @@ class ScrollAppBar extends StatelessWidget { Widget build(BuildContext context) { final double statusBarHeight = MediaQuery.of(context).padding.top; final videoHeight = MediaQuery.sizeOf(context).width * 9 / 16; + double scrollDistance = scrollVal; + if (scrollVal > videoHeight - kToolbarHeight) { + scrollDistance = videoHeight - kToolbarHeight; + } return Positioned( - top: -videoHeight + scrollVal + kToolbarHeight + 0.5, + top: -videoHeight + scrollDistance + kToolbarHeight + 0.5, left: 0, right: 0, child: Opacity( - opacity: scrollVal / (videoHeight - kToolbarHeight), + opacity: scrollDistance / (videoHeight - kToolbarHeight), child: Container( height: statusBarHeight + kToolbarHeight, color: Theme.of(context).colorScheme.background, From d6fd2993950779a57a75f4e4fe533f3b8c8f2bc9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 25 Mar 2024 22:25:05 +0800 Subject: [PATCH 08/71] =?UTF-8?q?fix:=20tabbar=E6=8C=87=E7=A4=BA=E5=99=A8?= =?UTF-8?q?=E6=8A=96=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/rank/controller.dart | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lib/pages/rank/controller.dart b/lib/pages/rank/controller.dart index da73ea02..6fe3d424 100644 --- a/lib/pages/rank/controller.dart +++ b/lib/pages/rank/controller.dart @@ -50,21 +50,5 @@ class RankController extends GetxController with GetTickerProviderStateMixin { length: tabs.length, vsync: this, ); - // 监听 tabController 切换 - if (enableGradientBg) { - tabController.animation!.addListener(() { - if (tabController.indexIsChanging) { - if (initialIndex.value != tabController.index) { - initialIndex.value = tabController.index; - } - } else { - final int temp = tabController.animation!.value.round(); - if (initialIndex.value != temp) { - initialIndex.value = temp; - tabController.index = initialIndex.value; - } - } - }); - } } } From d6b972a8ab7e6036f82b91fd866f77792996aa24 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 26 Mar 2024 22:13:01 +0800 Subject: [PATCH 09/71] =?UTF-8?q?mod:=20=E5=BC=B9=E5=B9=95=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E9=A2=9C=E8=89=B2&=E7=A8=8D=E5=90=8E=E5=86=8D?= =?UTF-8?q?=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/introduction/view.dart | 7 ++++++- lib/pages/video/detail/view.dart | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 831491f6..344b4b3a 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -15,6 +15,7 @@ import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; +import '../../../../http/user.dart'; import '../widgets/expandable_section.dart'; import 'widgets/action_item.dart'; import 'widgets/fav_panel.dart'; @@ -479,7 +480,11 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), ActionItem( icon: const Icon(FontAwesomeIcons.clock), - onTap: () => videoIntroController.actionShareVideo(), + onTap: () async { + final res = + await UserHttp.toViewLater(bvid: widget.videoDetail!.bvid); + SmartDialog.showToast(res['msg']); + }, selectStatus: false, text: '稍后看', ), diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 69801beb..ffa50476 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -372,6 +372,9 @@ class _VideoDetailPageState extends State false) ? SvgPicture.asset( 'assets/images/video/danmu_close.svg', + // ignore: deprecated_member_use + color: + Theme.of(context).colorScheme.outline, ) : SvgPicture.asset( 'assets/images/video/danmu_open.svg', From ed8443ba02a2660d5e33e77eee314dcfad98a0b6 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 27 Mar 2024 22:26:47 +0800 Subject: [PATCH 10/71] =?UTF-8?q?feat:=20navigation=20Bar=E7=BC=96?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/common/nav_bar_config.dart | 9 ++ lib/pages/main/controller.dart | 38 ++++--- .../setting/pages/navigation_bar_set.dart | 100 ++++++++++++++++++ lib/pages/setting/style_setting.dart | 7 +- lib/router/app_pages.dart | 4 + lib/utils/storage.dart | 3 +- 6 files changed, 144 insertions(+), 17 deletions(-) create mode 100644 lib/pages/setting/pages/navigation_bar_set.dart diff --git a/lib/models/common/nav_bar_config.dart b/lib/models/common/nav_bar_config.dart index 9ebe8e6f..64cebafb 100644 --- a/lib/models/common/nav_bar_config.dart +++ b/lib/models/common/nav_bar_config.dart @@ -1,5 +1,10 @@ import 'package:flutter/material.dart'; +import '../../pages/dynamics/index.dart'; +import '../../pages/home/index.dart'; +import '../../pages/media/index.dart'; +import '../../pages/rank/index.dart'; + List defaultNavigationBars = [ { 'id': 0, @@ -13,6 +18,7 @@ List defaultNavigationBars = [ ), 'label': "首页", 'count': 0, + 'page': const HomePage(), }, { 'id': 1, @@ -26,6 +32,7 @@ List defaultNavigationBars = [ ), 'label': "排行榜", 'count': 0, + 'page': const RankPage(), }, { 'id': 2, @@ -39,6 +46,7 @@ List defaultNavigationBars = [ ), 'label': "动态", 'count': 0, + 'page': const DynamicsPage(), }, { 'id': 3, @@ -52,5 +60,6 @@ List defaultNavigationBars = [ ), 'label': "媒体库", 'count': 0, + 'page': const MediaPage(), } ]; diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index ddbd364a..f929a1aa 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -6,23 +6,16 @@ import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/http/common.dart'; -import 'package:pilipala/pages/dynamics/index.dart'; -import 'package:pilipala/pages/home/view.dart'; -import 'package:pilipala/pages/media/index.dart'; -import 'package:pilipala/pages/rank/index.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; import '../../models/common/dynamic_badge_mode.dart'; import '../../models/common/nav_bar_config.dart'; class MainController extends GetxController { - List pages = [ - const HomePage(), - const RankPage(), - const DynamicsPage(), - const MediaPage(), - ]; - RxList navigationBars = defaultNavigationBars.obs; + List pages = []; + RxList navigationBars = [].obs; + late List defaultNavTabs; + late List navBarSort; final StreamController bottomBarStream = StreamController.broadcast(); Box setting = GStrorage.setting; @@ -41,10 +34,7 @@ class MainController extends GetxController { Utils.checkUpdata(); } hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true); - int defaultHomePage = - setting.get(SettingBoxKey.defaultHomePage, defaultValue: 0) as int; - selectedIndex = defaultNavigationBars - .indexWhere((item) => item['id'] == defaultHomePage); + var userInfo = userInfoCache.get('userInfoCache'); userLogin.value = userInfo != null; dynamicBadgeType.value = DynamicBadgeMode.values[setting.get( @@ -53,6 +43,7 @@ class MainController extends GetxController { if (dynamicBadgeType.value != DynamicBadgeMode.hidden) { getUnreadDynamic(); } + setNavBarConfig(); } void onBackPressed(BuildContext context) { @@ -93,4 +84,21 @@ class MainController extends GetxController { } navigationBars.refresh(); } + + void setNavBarConfig() async { + defaultNavTabs = [...defaultNavigationBars]; + navBarSort = + setting.get(SettingBoxKey.navBarSort, defaultValue: [0, 1, 2, 3]); + defaultNavTabs.retainWhere((item) => navBarSort.contains(item['id'])); + defaultNavTabs.sort((a, b) => + navBarSort.indexOf(a['id']).compareTo(navBarSort.indexOf(b['id']))); + navigationBars.value = defaultNavTabs; + int defaultHomePage = + setting.get(SettingBoxKey.defaultHomePage, defaultValue: 0) as int; + int defaultIndex = + navigationBars.indexWhere((item) => item['id'] == defaultHomePage); + // 如果找不到匹配项,默认索引设置为0或其他合适的值 + selectedIndex = defaultIndex != -1 ? defaultIndex : 0; + pages = navigationBars.map((e) => e['page']).toList(); + } } diff --git a/lib/pages/setting/pages/navigation_bar_set.dart b/lib/pages/setting/pages/navigation_bar_set.dart new file mode 100644 index 00000000..8e1771e3 --- /dev/null +++ b/lib/pages/setting/pages/navigation_bar_set.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/models/common/tab_type.dart'; +import 'package:pilipala/utils/storage.dart'; + +import '../../../models/common/nav_bar_config.dart'; + +class NavigationBarSetPage extends StatefulWidget { + const NavigationBarSetPage({super.key}); + + @override + State createState() => _NavigationbarSetPageState(); +} + +class _NavigationbarSetPageState extends State { + Box settingStorage = GStrorage.setting; + late List defaultNavTabs; + late List navBarSort; + + @override + void initState() { + super.initState(); + defaultNavTabs = defaultNavigationBars; + navBarSort = settingStorage + .get(SettingBoxKey.navBarSort, defaultValue: [0, 1, 2, 3]); + // 对 tabData 进行排序 + defaultNavTabs.sort((a, b) { + int indexA = navBarSort.indexOf(a['id']); + int indexB = navBarSort.indexOf(b['id']); + + // 如果类型在 sortOrder 中不存在,则放在末尾 + if (indexA == -1) indexA = navBarSort.length; + if (indexB == -1) indexB = navBarSort.length; + + return indexA.compareTo(indexB); + }); + } + + void saveEdit() { + List sortedTabbar = defaultNavTabs + .where((i) => navBarSort.contains(i['id'])) + .map((i) => i['id']) + .toList(); + settingStorage.put(SettingBoxKey.navBarSort, sortedTabbar); + SmartDialog.showToast('保存成功,下次启动时生效'); + } + + void onReorder(int oldIndex, int newIndex) { + setState(() { + if (newIndex > oldIndex) { + newIndex -= 1; + } + final tabsItem = defaultNavTabs.removeAt(oldIndex); + defaultNavTabs.insert(newIndex, tabsItem); + }); + } + + @override + Widget build(BuildContext context) { + final listTiles = [ + for (int i = 0; i < defaultNavTabs.length; i++) ...[ + CheckboxListTile( + key: Key(defaultNavTabs[i]['label']), + value: navBarSort.contains(defaultNavTabs[i]['id']), + onChanged: (bool? newValue) { + int tabTypeId = defaultNavTabs[i]['id']; + if (!newValue!) { + navBarSort.remove(tabTypeId); + } else { + navBarSort.add(tabTypeId); + } + setState(() {}); + }, + title: Text(defaultNavTabs[i]['label']), + secondary: const Icon(Icons.drag_indicator_rounded), + enabled: defaultNavTabs[i]['id'] != 3, + ) + ] + ]; + + return Scaffold( + appBar: AppBar( + title: const Text('Navbar编辑'), + actions: [ + TextButton(onPressed: () => saveEdit(), child: const Text('保存')), + const SizedBox(width: 12) + ], + ), + body: ReorderableListView( + onReorder: onReorder, + physics: const NeverScrollableScrollPhysics(), + footer: SizedBox( + height: MediaQuery.of(context).padding.bottom + 30, + ), + children: listTiles, + ), + ); + } +} diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index 30b9a30f..d2403cff 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -284,12 +284,17 @@ class _StyleSettingState extends State { onTap: () => Get.toNamed('/tabbarSetting'), title: Text('首页tabbar', style: titleStyle), ), + ListTile( + dense: false, + onTap: () => Get.toNamed('/navbarSetting'), + title: Text('navbar设置', style: titleStyle), + ), if (Platform.isAndroid) ListTile( dense: false, onTap: () => Get.toNamed('/displayModeSetting'), title: Text('屏幕帧率', style: titleStyle), - ) + ), ], ), ); diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 1f1ea31e..7fda1bd8 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -39,6 +39,7 @@ import '../pages/setting/pages/color_select.dart'; import '../pages/setting/pages/display_mode.dart'; import '../pages/setting/pages/font_size_select.dart'; import '../pages/setting/pages/home_tabbar_set.dart'; +import '../pages/setting/pages/navigation_bar_set.dart'; import '../pages/setting/pages/play_gesture_set.dart'; import '../pages/setting/pages/play_speed_set.dart'; import '../pages/setting/recommend_setting.dart'; @@ -170,6 +171,9 @@ class Routes { // 播放器手势 CustomGetPage( name: '/playerGestureSet', page: () => const PlayGesturePage()), + // navigation bar + CustomGetPage( + name: '/navbarSetting', page: () => const NavigationBarSetPage()), ]; } diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index a82972e0..29cf1846 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -148,7 +148,8 @@ class SettingBoxKey { hideTabBar = 'hideTabBar', // 收起底栏 tabbarSort = 'tabbarSort', // 首页tabbar dynamicBadgeMode = 'dynamicBadgeMode', - enableGradientBg = 'enableGradientBg'; + enableGradientBg = 'enableGradientBg', + navBarSort = 'navBarSort'; } class LocalCacheKey { From 463ee1d5b5b7630eb7c974a5374c50d4852d9694 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 27 Mar 2024 23:27:53 +0800 Subject: [PATCH 11/71] =?UTF-8?q?mod:=20=E6=A0=87=E9=A2=98=E8=BD=AC?= =?UTF-8?q?=E4=B9=89=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utils/em.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/utils/em.dart b/lib/utils/em.dart index 733f5c35..4e2ed9f2 100644 --- a/lib/utils/em.dart +++ b/lib/utils/em.dart @@ -27,7 +27,8 @@ class Em { .replaceAll('"', '"') .replaceAll(''', "'") .replaceAll(' ', " ") - .replaceAll('&', "&"); + .replaceAll('&', "&") + .replaceAll(''', "'"); Map map = {'type': 'text', 'text': str}; res.add(map); } From 6b028c36af68d308eeab024a8394db61cac090ba Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 27 Mar 2024 23:34:59 +0800 Subject: [PATCH 12/71] =?UTF-8?q?mod:=20=E6=90=9C=E7=B4=A2=E4=B8=93?= =?UTF-8?q?=E6=A0=8F=E5=89=AF=E6=A0=87=E9=A2=98=E8=BD=AC=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/search/result.dart | 3 ++- lib/utils/em.dart | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/models/search/result.dart b/lib/models/search/result.dart index 0067791c..418fb99d 100644 --- a/lib/models/search/result.dart +++ b/lib/models/search/result.dart @@ -437,7 +437,8 @@ class SearchArticleItemModel { pubTime = json['pub_time']; like = json['like']; title = Em.regTitle(json['title']); - subTitle = json['title'].replaceAll(RegExp(r'<[^>]*>'), ''); + subTitle = + Em.decodeHtmlEntities(json['title'].replaceAll(RegExp(r'<[^>]*>'), '')); rankOffset = json['rank_offset']; mid = json['mid']; imageUrls = json['image_urls']; diff --git a/lib/utils/em.dart b/lib/utils/em.dart index 4e2ed9f2..2c5af8ba 100644 --- a/lib/utils/em.dart +++ b/lib/utils/em.dart @@ -19,16 +19,7 @@ class Em { return regCate(matchStr); }, onNonMatch: (String str) { if (str != '') { - str = str - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('"', '"') - .replaceAll(''', "'") - .replaceAll('"', '"') - .replaceAll(''', "'") - .replaceAll(' ', " ") - .replaceAll('&', "&") - .replaceAll(''', "'"); + str = decodeHtmlEntities(str); Map map = {'type': 'text', 'text': str}; res.add(map); } @@ -36,4 +27,17 @@ class Em { }); return res; } + + static String decodeHtmlEntities(String title) { + return title + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll(''', "'") + .replaceAll('"', '"') + .replaceAll(''', "'") + .replaceAll(' ', " ") + .replaceAll('&', "&") + .replaceAll(''', "'"); + } } From aae08d068852bad5d0844f81423deb1f90b8530f Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 27 Mar 2024 23:44:07 +0800 Subject: [PATCH 13/71] =?UTF-8?q?fix:=20=E6=9C=80=E7=83=AD/=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E8=AF=84=E8=AE=BA=E6=A0=87=E8=AF=86=E6=9C=AA=E5=88=B7?= =?UTF-8?q?=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/reply/view.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 38203f7e..2a167fe9 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -149,13 +149,16 @@ class _VideoReplyPanelState extends State delegate: _MySliverPersistentHeaderDelegate( child: Container( height: 40, - padding: const EdgeInsets.fromLTRB(12, 6, 6, 0), + padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), + color: Theme.of(context).colorScheme.surface, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - '${_videoReplyController.sortTypeLabel.value}评论', - style: const TextStyle(fontSize: 13), + Obx( + () => Text( + '${_videoReplyController.sortTypeLabel.value}评论', + style: const TextStyle(fontSize: 13), + ), ), SizedBox( height: 35, From fb3be848b4d0769af856983a8788b41af3c55884 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Mar 2024 00:00:27 +0800 Subject: [PATCH 14/71] =?UTF-8?q?feat:=20=E6=92=AD=E6=94=BE=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E8=BF=9B=E5=BA=A6=E6=9D=A1=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/history/widgets/item.dart | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index a83e118b..f4bd9221 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -185,7 +185,7 @@ class HistoryItem extends StatelessWidget { ? '已看完' : '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}', right: 6.0, - bottom: 6.0, + bottom: 8.0, type: 'gray', ), // 右上角 @@ -258,6 +258,24 @@ class HistoryItem extends StatelessWidget { ), ), ), + Positioned( + left: 3, + right: 3, + bottom: 0, + child: ClipRRect( + borderRadius: BorderRadius.only( + bottomLeft: + Radius.circular(StyleString.imgRadius.x), + bottomRight: + Radius.circular(StyleString.imgRadius.x), + ), + child: LinearProgressIndicator( + value: videoItem.progress == -1 + ? 100 + : videoItem.progress / videoItem.duration, + ), + ), + ) ], ), VideoContent(videoItem: videoItem, ctr: ctr) From 53941469cec5405c36ed23acb112e7410cbe0b6c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Mar 2024 00:29:22 +0800 Subject: [PATCH 15/71] =?UTF-8?q?opt:=20=E5=90=91=E4=B8=8B=E6=9F=A5?= =?UTF-8?q?=E6=89=BE=E5=8F=AF=E7=94=A8=E8=A7=86=E9=A2=91=E6=B8=85=E6=99=B0?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utils/utils.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index adcc7b5a..bc3252b8 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -208,14 +208,16 @@ class Utils { static int findClosestNumber(int target, List numbers) { int minDiff = 127; - late int closestNumber; + int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数 try { for (int number in numbers) { - int diff = (number - target).abs(); + if (number < target) { + int diff = target - number; // 计算目标值与当前整数的差值 - if (diff < minDiff) { - minDiff = diff; - closestNumber = number; + if (diff < minDiff) { + minDiff = diff; + closestNumber = number; + } } } } catch (_) {} From 8f9fbf5d41c7daa1ed17e774e1710236218a9c23 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 29 Mar 2024 00:01:17 +0800 Subject: [PATCH 16/71] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=B1=95=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Podfile.lock | 13 ++-- lib/pages/video/detail/introduction/view.dart | 62 ++++++++++++++----- pubspec.lock | 8 +++ pubspec.yaml | 2 + 4 files changed, 65 insertions(+), 20 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 8db59815..2c1a635b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -9,6 +9,7 @@ PODS: - Flutter - connectivity_plus (0.0.1): - Flutter + - FlutterMacOS - ReachabilitySwift - device_info_plus (0.0.1): - Flutter @@ -38,7 +39,7 @@ PODS: - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - permission_handler_apple (9.1.1): + - permission_handler_apple (9.3.0): - Flutter - ReachabilitySwift (5.0.0) - saver_gallery (0.0.1): @@ -71,7 +72,7 @@ DEPENDENCIES: - audio_service (from `.symlinks/plugins/audio_service/ios`) - audio_session (from `.symlinks/plugins/audio_session/ios`) - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) + - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) - flutter_mailer (from `.symlinks/plugins/flutter_mailer/ios`) @@ -113,7 +114,7 @@ EXTERNAL SOURCES: auto_orientation: :path: ".symlinks/plugins/auto_orientation/ios" connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" + :path: ".symlinks/plugins/connectivity_plus/darwin" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" Flutter: @@ -166,7 +167,7 @@ SPEC CHECKSUMS: audio_service: f509d65da41b9521a61f1c404dd58651f265a567 audio_session: 4f3e461722055d21515cf3261b64c973c062f345 auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d - connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a + connectivity_plus: e2dad488011aeb593e219360e804c43cc1af5770 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 @@ -180,7 +181,7 @@ SPEC CHECKSUMS: media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 - permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78 screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 @@ -193,7 +194,7 @@ SPEC CHECKSUMS: volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7 - webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a + webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 PODFILE CHECKSUM: 637cd290bed23275b5f5ffcc7eb1e73d0a5fb2be diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 344b4b3a..a990aab8 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -1,3 +1,4 @@ +import 'package:expandable/expandable.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; @@ -16,7 +17,6 @@ import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; import '../../../../http/user.dart'; -import '../widgets/expandable_section.dart'; import 'widgets/action_item.dart'; import 'widgets/fav_panel.dart'; import 'widgets/intro_detail.dart'; @@ -140,6 +140,8 @@ class _VideoInfoState extends State with TickerProviderStateMixin { late bool enableAi; bool isProcessing = false; RxBool isExpand = false.obs; + late ExpandableController _expandableCtr; + void Function()? handleState(Future Function() action) { return isProcessing ? null @@ -163,6 +165,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { follower = Utils.numFormat(videoIntroController.userStat['follower']); followStatus = videoIntroController.followStatus; enableAi = setting.get(SettingBoxKey.enableAi, defaultValue: true); + _expandableCtr = ExpandableController(initialExpanded: false); } // 收藏 @@ -216,6 +219,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { showIntroDetail() { feedBack(); isExpand.value = !(isExpand.value); + _expandableCtr.toggle(); } // 用户主页 @@ -239,6 +243,12 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ); } + @override + void dispose() { + _expandableCtr.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final ThemeData t = Theme.of(context); @@ -256,14 +266,34 @@ class _VideoInfoState extends State with TickerProviderStateMixin { GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => showIntroDetail(), - child: Text( - widget.videoDetail!.title!, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, + child: ExpandablePanel( + controller: _expandableCtr, + collapsed: Text( + widget.videoDetail!.title!, + softWrap: true, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + expanded: Text( + widget.videoDetail!.title!, + softWrap: true, + maxLines: 4, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + theme: const ExpandableThemeData( + animationDuration: Duration(milliseconds: 300), + scrollAnimationDuration: Duration(milliseconds: 300), + crossFadePoint: 0, + fadeCurve: Curves.ease, + sizeCurve: Curves.linear, ), - maxLines: 2, - overflow: TextOverflow.ellipsis, ), ), Stack( @@ -328,12 +358,16 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), /// 视频简介 - Obx( - () => ExpandedSection( - expand: isExpand.value, - begin: 0, - end: 1, - child: IntroDetail(videoDetail: widget.videoDetail!), + ExpandablePanel( + controller: _expandableCtr, + collapsed: const SizedBox(height: 0), + expanded: IntroDetail(videoDetail: widget.videoDetail!), + theme: const ExpandableThemeData( + animationDuration: Duration(milliseconds: 300), + scrollAnimationDuration: Duration(milliseconds: 300), + crossFadePoint: 0, + fadeCurve: Curves.ease, + sizeCurve: Curves.linear, ), ), diff --git a/pubspec.lock b/pubspec.lock index 695505d7..84556c06 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -433,6 +433,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "5.0.3" + expandable: + dependency: "direct main" + description: + name: expandable + sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.1" extended_image: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 5e19b56b..ba5976eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -142,6 +142,8 @@ dependencies: path: 1.8.3 # 电池优化 disable_battery_optimization: ^1.1.1 + # 展开/收起 + expandable: ^5.0.1 dev_dependencies: flutter_test: From d806de7d8f982fe0ea6a650692a63408d853bd8d Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Mar 2024 00:00:27 +0800 Subject: [PATCH 17/71] =?UTF-8?q?feat:=20=E6=92=AD=E6=94=BE=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E8=BF=9B=E5=BA=A6=E6=9D=A1=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/history/widgets/item.dart | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index a83e118b..f4bd9221 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -185,7 +185,7 @@ class HistoryItem extends StatelessWidget { ? '已看完' : '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}', right: 6.0, - bottom: 6.0, + bottom: 8.0, type: 'gray', ), // 右上角 @@ -258,6 +258,24 @@ class HistoryItem extends StatelessWidget { ), ), ), + Positioned( + left: 3, + right: 3, + bottom: 0, + child: ClipRRect( + borderRadius: BorderRadius.only( + bottomLeft: + Radius.circular(StyleString.imgRadius.x), + bottomRight: + Radius.circular(StyleString.imgRadius.x), + ), + child: LinearProgressIndicator( + value: videoItem.progress == -1 + ? 100 + : videoItem.progress / videoItem.duration, + ), + ), + ) ], ), VideoContent(videoItem: videoItem, ctr: ctr) From 6c2eab86e949c8c518fba3acde0456f60eb3b535 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 29 Mar 2024 00:01:17 +0800 Subject: [PATCH 18/71] =?UTF-8?q?fix:=20=E8=A7=86=E9=A2=91=E6=A0=87?= =?UTF-8?q?=E9=A2=98=E5=B1=95=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/introduction/view.dart | 62 ++++++++++++++----- pubspec.lock | 8 +++ pubspec.yaml | 2 + 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 344b4b3a..a990aab8 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -1,3 +1,4 @@ +import 'package:expandable/expandable.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; @@ -16,7 +17,6 @@ import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/utils.dart'; import '../../../../http/user.dart'; -import '../widgets/expandable_section.dart'; import 'widgets/action_item.dart'; import 'widgets/fav_panel.dart'; import 'widgets/intro_detail.dart'; @@ -140,6 +140,8 @@ class _VideoInfoState extends State with TickerProviderStateMixin { late bool enableAi; bool isProcessing = false; RxBool isExpand = false.obs; + late ExpandableController _expandableCtr; + void Function()? handleState(Future Function() action) { return isProcessing ? null @@ -163,6 +165,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { follower = Utils.numFormat(videoIntroController.userStat['follower']); followStatus = videoIntroController.followStatus; enableAi = setting.get(SettingBoxKey.enableAi, defaultValue: true); + _expandableCtr = ExpandableController(initialExpanded: false); } // 收藏 @@ -216,6 +219,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { showIntroDetail() { feedBack(); isExpand.value = !(isExpand.value); + _expandableCtr.toggle(); } // 用户主页 @@ -239,6 +243,12 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ); } + @override + void dispose() { + _expandableCtr.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { final ThemeData t = Theme.of(context); @@ -256,14 +266,34 @@ class _VideoInfoState extends State with TickerProviderStateMixin { GestureDetector( behavior: HitTestBehavior.translucent, onTap: () => showIntroDetail(), - child: Text( - widget.videoDetail!.title!, - style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, + child: ExpandablePanel( + controller: _expandableCtr, + collapsed: Text( + widget.videoDetail!.title!, + softWrap: true, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + expanded: Text( + widget.videoDetail!.title!, + softWrap: true, + maxLines: 4, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + theme: const ExpandableThemeData( + animationDuration: Duration(milliseconds: 300), + scrollAnimationDuration: Duration(milliseconds: 300), + crossFadePoint: 0, + fadeCurve: Curves.ease, + sizeCurve: Curves.linear, ), - maxLines: 2, - overflow: TextOverflow.ellipsis, ), ), Stack( @@ -328,12 +358,16 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), /// 视频简介 - Obx( - () => ExpandedSection( - expand: isExpand.value, - begin: 0, - end: 1, - child: IntroDetail(videoDetail: widget.videoDetail!), + ExpandablePanel( + controller: _expandableCtr, + collapsed: const SizedBox(height: 0), + expanded: IntroDetail(videoDetail: widget.videoDetail!), + theme: const ExpandableThemeData( + animationDuration: Duration(milliseconds: 300), + scrollAnimationDuration: Duration(milliseconds: 300), + crossFadePoint: 0, + fadeCurve: Curves.ease, + sizeCurve: Curves.linear, ), ), diff --git a/pubspec.lock b/pubspec.lock index 695505d7..84556c06 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -433,6 +433,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "5.0.3" + expandable: + dependency: "direct main" + description: + name: expandable + sha256: "9604d612d4d1146dafa96c6d8eec9c2ff0994658d6d09fed720ab788c7f5afc2" + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.1" extended_image: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 5e19b56b..ba5976eb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -142,6 +142,8 @@ dependencies: path: 1.8.3 # 电池优化 disable_battery_optimization: ^1.1.1 + # 展开/收起 + expandable: ^5.0.1 dev_dependencies: flutter_test: From d003f864cec8076bb97fc63b99df8eee139ad06c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 30 Mar 2024 17:01:32 +0800 Subject: [PATCH 19/71] =?UTF-8?q?feat:=20=E8=AE=A2=E9=98=85=E5=8F=96?= =?UTF-8?q?=E6=B6=88=20issues=20#658?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 2 ++ lib/http/user.dart | 17 +++++++++++ lib/pages/subscription/controller.dart | 36 ++++++++++++++++++++++++ lib/pages/subscription/view.dart | 3 +- lib/pages/subscription/widgets/item.dart | 33 ++++++++++++++++++++-- 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index 445f6102..fa4cc1e8 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -506,4 +506,6 @@ class Api { /// 排行榜 static const String getRankApi = "/x/web-interface/ranking/v2"; + /// 取消订阅 + static const String cancelSub = '/x/v3/fav/season/unfav'; } diff --git a/lib/http/user.dart b/lib/http/user.dart index 7d3def4e..bae61720 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -349,4 +349,21 @@ class UserHttp { return {'status': false, 'msg': res.data['message']}; } } + + // 取消订阅 + static Future cancelSub({required int seasonId}) async { + var res = await Request().post( + Api.cancelSub, + queryParameters: { + 'platform': 'web', + 'season_id': seasonId, + 'csrf': await Request.getCsrf(), + }, + ); + if (res.data['code'] == 0) { + return {'status': true}; + } else { + return {'status': false, 'msg': res.data['message']}; + } + } } diff --git a/lib/pages/subscription/controller.dart b/lib/pages/subscription/controller.dart index bf0c593c..7be8d22c 100644 --- a/lib/pages/subscription/controller.dart +++ b/lib/pages/subscription/controller.dart @@ -46,4 +46,40 @@ class SubController extends GetxController { Future onLoad() async { querySubFolder(type: 'onload'); } + + // 取消订阅 + Future cancelSub(SubFolderItemData subFolderItem) async { + showDialog( + context: Get.context!, + builder: (context) => AlertDialog( + title: const Text('提示'), + content: const Text('确定取消订阅吗?'), + actions: [ + TextButton( + onPressed: () { + Get.back(); + }, + child: Text( + '取消', + style: TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + TextButton( + onPressed: () async { + var res = await UserHttp.cancelSub(seasonId: subFolderItem.id!); + if (res['status']) { + subFolderData.value.list!.remove(subFolderItem); + subFolderData.update((val) {}); + SmartDialog.showToast('取消订阅成功'); + } else { + SmartDialog.showToast(res['msg']); + } + Get.back(); + }, + child: const Text('确定'), + ), + ], + ), + ); + } } diff --git a/lib/pages/subscription/view.dart b/lib/pages/subscription/view.dart index 1eee4a4f..2d7d0cb5 100644 --- a/lib/pages/subscription/view.dart +++ b/lib/pages/subscription/view.dart @@ -58,7 +58,8 @@ class _SubPageState extends State { itemBuilder: (context, index) { return SubItem( subFolderItem: - _subController.subFolderData.value.list![index]); + _subController.subFolderData.value.list![index], + cancelSub: _subController.cancelSub); }, ), ); diff --git a/lib/pages/subscription/widgets/item.dart b/lib/pages/subscription/widgets/item.dart index fd08ffa5..5b2a0134 100644 --- a/lib/pages/subscription/widgets/item.dart +++ b/lib/pages/subscription/widgets/item.dart @@ -8,7 +8,12 @@ import '../../../models/user/sub_folder.dart'; class SubItem extends StatelessWidget { final SubFolderItemData subFolderItem; - const SubItem({super.key, required this.subFolderItem}); + final Function(SubFolderItemData) cancelSub; + const SubItem({ + super.key, + required this.subFolderItem, + required this.cancelSub, + }); @override Widget build(BuildContext context) { @@ -51,7 +56,10 @@ class SubItem extends StatelessWidget { }, ), ), - VideoContent(subFolderItem: subFolderItem) + VideoContent( + subFolderItem: subFolderItem, + cancelSub: cancelSub, + ) ], ), ); @@ -64,7 +72,8 @@ class SubItem extends StatelessWidget { class VideoContent extends StatelessWidget { final SubFolderItemData subFolderItem; - const VideoContent({super.key, required this.subFolderItem}); + final Function(SubFolderItemData)? cancelSub; + const VideoContent({super.key, required this.subFolderItem, this.cancelSub}); @override Widget build(BuildContext context) { @@ -100,6 +109,24 @@ class VideoContent extends StatelessWidget { color: Theme.of(context).colorScheme.outline, ), ), + const Spacer(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( + height: 35, + width: 35, + child: IconButton( + onPressed: () => cancelSub?.call(subFolderItem), + style: TextButton.styleFrom( + foregroundColor: Theme.of(context).colorScheme.outline, + padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), + ), + icon: const Icon(Icons.delete_outline, size: 18), + ), + ) + ], + ) ], ), ), From af1163f6e05193e6023b217e8b85fcbacc942721 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 30 Mar 2024 22:17:37 +0800 Subject: [PATCH 20/71] =?UTF-8?q?fix:=20=E5=8E=86=E5=8F=B2=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E8=BF=9B=E5=BA=A6=E6=9D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/history/widgets/item.dart | 39 ++++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index f4bd9221..39c6931d 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -258,24 +258,27 @@ class HistoryItem extends StatelessWidget { ), ), ), - Positioned( - left: 3, - right: 3, - bottom: 0, - child: ClipRRect( - borderRadius: BorderRadius.only( - bottomLeft: - Radius.circular(StyleString.imgRadius.x), - bottomRight: - Radius.circular(StyleString.imgRadius.x), - ), - child: LinearProgressIndicator( - value: videoItem.progress == -1 - ? 100 - : videoItem.progress / videoItem.duration, - ), - ), - ) + videoItem.progress != 0 + ? Positioned( + left: 3, + right: 3, + bottom: 0, + child: ClipRRect( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular( + StyleString.imgRadius.x), + bottomRight: Radius.circular( + StyleString.imgRadius.x), + ), + child: LinearProgressIndicator( + value: videoItem.progress == -1 + ? 100 + : videoItem.progress / + videoItem.duration, + ), + ), + ) + : const SizedBox() ], ), VideoContent(videoItem: videoItem, ctr: ctr) From 53b103b8535b1938569a55c8f460815404cccdbb Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 31 Mar 2024 00:27:39 +0800 Subject: [PATCH 21/71] fix: utils timeFormat error --- lib/utils/utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index adcc7b5a..ecba771f 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -51,7 +51,7 @@ class Utils { } if (time < 3600) { if (time == 0) { - return time; + return '00:00'; } final int minute = time ~/ 60; final double res = time / 60; From 336feb4fda028b7ae7ea022af4628ce3b5d4adbe Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 31 Mar 2024 00:27:39 +0800 Subject: [PATCH 22/71] fix: utils timeFormat error --- lib/utils/utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index adcc7b5a..ecba771f 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -51,7 +51,7 @@ class Utils { } if (time < 3600) { if (time == 0) { - return time; + return '00:00'; } final int minute = time ~/ 60; final double res = time / 60; From 8897c4dd5b523599a3a3af75a03aac9c28ef51de Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 31 Mar 2024 11:11:50 +0800 Subject: [PATCH 23/71] =?UTF-8?q?feat:=20=E5=90=AF=E5=8A=A8=E6=97=B6?= =?UTF-8?q?=E6=B8=85=E9=99=A4=E6=97=A5=E5=BF=97=20issues=20#656?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/main.dart b/lib/main.dart index 44bb1dcd..7fdaeeb0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -34,6 +34,7 @@ void main() async { .then((_) async { await GStrorage.init(); await setupServiceLocator(); + clearLogs(); Request(); await Request.setCookie(); RecommendFilter(); From 469a5ec691f9f96e0a7250ee1d258dde502099a0 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 1 Apr 2024 23:03:31 +0800 Subject: [PATCH 24/71] =?UTF-8?q?mod:=20=E4=B8=AA=E4=BA=BA=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E6=A0=B7=E5=BC=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/member/info.dart | 5 +++ lib/pages/member/view.dart | 13 +++++-- lib/pages/member/widgets/seasons.dart | 53 ++++++++++----------------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/lib/models/member/info.dart b/lib/models/member/info.dart index 789131ee..83f94c54 100644 --- a/lib/models/member/info.dart +++ b/lib/models/member/info.dart @@ -47,18 +47,23 @@ class Vip { this.status, this.dueDate, this.label, + this.nicknameColor, }); int? type; int? status; int? dueDate; Map? label; + int? nicknameColor; Vip.fromJson(Map json) { type = json['type']; status = json['status']; dueDate = json['due_date']; label = json['label']; + nicknameColor = json['nickname_color'] == '' + ? null + : int.parse("0xFF${json['nickname_color'].replaceAll('#', '')}"); } } diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index 0663e94e..c8a9f406 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -281,8 +281,8 @@ class _MemberPageState extends State future: _futureBuilderFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data!; - if (data['status']) { + Map? data = snapshot.data; + if (data != null && data['status']) { return Obx( () => Stack( alignment: AlignmentDirectional.center, @@ -302,7 +302,14 @@ class _MemberPageState extends State style: Theme.of(context) .textTheme .titleMedium! - .copyWith(fontWeight: FontWeight.bold), + .copyWith( + fontWeight: FontWeight.bold, + color: _memberController.memberInfo.value + .vip!.nicknameColor != + null + ? Color(_memberController.memberInfo + .value.vip!.nicknameColor!) + : null), )), const SizedBox(width: 2), if (_memberController.memberInfo.value.sex == '女') diff --git a/lib/pages/member/widgets/seasons.dart b/lib/pages/member/widgets/seasons.dart index 68c4077f..125c978f 100644 --- a/lib/pages/member/widgets/seasons.dart +++ b/lib/pages/member/widgets/seasons.dart @@ -18,45 +18,32 @@ class MemberSeasonsPanel extends StatelessWidget { itemBuilder: (context, index) { MemberSeasonsList item = data!.seasonsList![index]; return Padding( - padding: const EdgeInsets.only(bottom: 12, right: 4), + padding: const EdgeInsets.only(bottom: 12), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.only(bottom: 12, left: 4), - child: Row( - children: [ - Text( - item.meta!.name!, - maxLines: 1, - style: Theme.of(context).textTheme.titleSmall!, - ), - const SizedBox(width: 10), - PBadge( - stack: 'relative', - size: 'small', - text: item.meta!.total.toString(), - ), - const Spacer(), - SizedBox( - width: 35, - height: 35, - child: IconButton( - onPressed: () => Get.toNamed( - '/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'), - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - icon: const Icon( - Icons.arrow_forward, - size: 20, - ), - ), - ) - ], + ListTile( + onTap: () => Get.toNamed( + '/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'), + title: Text( + item.meta!.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall!, + ), + dense: true, + leading: PBadge( + stack: 'relative', + size: 'small', + text: item.meta!.total.toString(), + ), + trailing: const Icon( + Icons.arrow_forward, + size: 20, ), ), + const SizedBox(height: 10), LayoutBuilder( builder: (context, boxConstraints) { return GridView.builder( From a20217bf3962d309b4d2a19018a01769f5734f57 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Mar 2024 00:29:22 +0800 Subject: [PATCH 25/71] =?UTF-8?q?opt:=20=E5=90=91=E4=B8=8B=E6=9F=A5?= =?UTF-8?q?=E6=89=BE=E5=8F=AF=E7=94=A8=E8=A7=86=E9=A2=91=E6=B8=85=E6=99=B0?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utils/utils.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index ecba771f..cb7cbf25 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -208,14 +208,16 @@ class Utils { static int findClosestNumber(int target, List numbers) { int minDiff = 127; - late int closestNumber; + int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数 try { for (int number in numbers) { - int diff = (number - target).abs(); + if (number < target) { + int diff = target - number; // 计算目标值与当前整数的差值 - if (diff < minDiff) { - minDiff = diff; - closestNumber = number; + if (diff < minDiff) { + minDiff = diff; + closestNumber = number; + } } } } catch (_) {} From e212a327635ba608a148bdfacbbe9df9e33e11de Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 31 Mar 2024 11:11:50 +0800 Subject: [PATCH 26/71] =?UTF-8?q?feat:=20=E5=90=AF=E5=8A=A8=E6=97=B6?= =?UTF-8?q?=E6=B8=85=E9=99=A4=E6=97=A5=E5=BF=97=20issues=20#656?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/main.dart b/lib/main.dart index 44bb1dcd..7fdaeeb0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -34,6 +34,7 @@ void main() async { .then((_) async { await GStrorage.init(); await setupServiceLocator(); + clearLogs(); Request(); await Request.setCookie(); RecommendFilter(); From da9828a295b51f267be2464f03f070ed7968b4da Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 1 Apr 2024 23:03:31 +0800 Subject: [PATCH 27/71] =?UTF-8?q?mod:=20=E4=B8=AA=E4=BA=BA=E4=B8=BB?= =?UTF-8?q?=E9=A1=B5=E6=A0=B7=E5=BC=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/member/info.dart | 5 +++ lib/pages/member/view.dart | 13 +++++-- lib/pages/member/widgets/seasons.dart | 53 ++++++++++----------------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/lib/models/member/info.dart b/lib/models/member/info.dart index 789131ee..83f94c54 100644 --- a/lib/models/member/info.dart +++ b/lib/models/member/info.dart @@ -47,18 +47,23 @@ class Vip { this.status, this.dueDate, this.label, + this.nicknameColor, }); int? type; int? status; int? dueDate; Map? label; + int? nicknameColor; Vip.fromJson(Map json) { type = json['type']; status = json['status']; dueDate = json['due_date']; label = json['label']; + nicknameColor = json['nickname_color'] == '' + ? null + : int.parse("0xFF${json['nickname_color'].replaceAll('#', '')}"); } } diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index 0663e94e..c8a9f406 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -281,8 +281,8 @@ class _MemberPageState extends State future: _futureBuilderFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data!; - if (data['status']) { + Map? data = snapshot.data; + if (data != null && data['status']) { return Obx( () => Stack( alignment: AlignmentDirectional.center, @@ -302,7 +302,14 @@ class _MemberPageState extends State style: Theme.of(context) .textTheme .titleMedium! - .copyWith(fontWeight: FontWeight.bold), + .copyWith( + fontWeight: FontWeight.bold, + color: _memberController.memberInfo.value + .vip!.nicknameColor != + null + ? Color(_memberController.memberInfo + .value.vip!.nicknameColor!) + : null), )), const SizedBox(width: 2), if (_memberController.memberInfo.value.sex == '女') diff --git a/lib/pages/member/widgets/seasons.dart b/lib/pages/member/widgets/seasons.dart index 68c4077f..125c978f 100644 --- a/lib/pages/member/widgets/seasons.dart +++ b/lib/pages/member/widgets/seasons.dart @@ -18,45 +18,32 @@ class MemberSeasonsPanel extends StatelessWidget { itemBuilder: (context, index) { MemberSeasonsList item = data!.seasonsList![index]; return Padding( - padding: const EdgeInsets.only(bottom: 12, right: 4), + padding: const EdgeInsets.only(bottom: 12), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.only(bottom: 12, left: 4), - child: Row( - children: [ - Text( - item.meta!.name!, - maxLines: 1, - style: Theme.of(context).textTheme.titleSmall!, - ), - const SizedBox(width: 10), - PBadge( - stack: 'relative', - size: 'small', - text: item.meta!.total.toString(), - ), - const Spacer(), - SizedBox( - width: 35, - height: 35, - child: IconButton( - onPressed: () => Get.toNamed( - '/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'), - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - icon: const Icon( - Icons.arrow_forward, - size: 20, - ), - ), - ) - ], + ListTile( + onTap: () => Get.toNamed( + '/memberSeasons?mid=${item.meta!.mid}&seasonId=${item.meta!.seasonId}'), + title: Text( + item.meta!.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall!, + ), + dense: true, + leading: PBadge( + stack: 'relative', + size: 'small', + text: item.meta!.total.toString(), + ), + trailing: const Icon( + Icons.arrow_forward, + size: 20, ), ), + const SizedBox(height: 10), LayoutBuilder( builder: (context, boxConstraints) { return GridView.builder( From c6de1fa95a80a63734f0a1b39b46555557796208 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 1 Apr 2024 23:55:35 +0800 Subject: [PATCH 28/71] =?UTF-8?q?mod:=20=E8=AF=84=E8=AE=BAb23.tv=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E5=8C=B9=E9=85=8D=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../detail/reply/widgets/reply_item.dart | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index e79b6159..50fe20d4 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -525,14 +525,18 @@ InlineSpan buildContent( if (jumpUrlKeysList.isNotEmpty) { patternStr += '|${jumpUrlKeysList.join('|')}'; } + RegExp bv23Regex = RegExp(r'https://b23\.tv/[a-zA-Z0-9]{7}'); final RegExp pattern = RegExp(patternStr); List matchedStrs = []; void addPlainTextSpan(str) { - spanChilds.add(TextSpan( + spanChilds.add( + TextSpan( text: str, recognizer: TapGestureRecognizer() ..onTap = () => - replyReply?.call(replyItem.root == 0 ? replyItem : fReplyItem))); + replyReply?.call(replyItem.root == 0 ? replyItem : fReplyItem), + ), + ); } // 分割文本并处理每个部分 @@ -734,8 +738,36 @@ InlineSpan buildContent( return ''; }, onNonMatch: (String nonMatchStr) { - addPlainTextSpan(nonMatchStr); - return nonMatchStr; + return nonMatchStr.splitMapJoin( + bv23Regex, + onMatch: (Match match) { + String matchStr = match[0]!; + spanChilds.add( + TextSpan( + text: ' $matchStr ', + style: isVideoPage + ? TextStyle( + color: Theme.of(context).colorScheme.primary, + ) + : null, + recognizer: TapGestureRecognizer() + ..onTap = () => Get.toNamed( + '/webview', + parameters: { + 'url': matchStr, + 'type': 'url', + 'pageTitle': matchStr + }, + ), + ), + ); + return ''; + }, + onNonMatch: (String nonMatchOtherStr) { + addPlainTextSpan(nonMatchOtherStr); + return nonMatchOtherStr; + }, + ); }, ); From c0f3b4f3a2052eb6b4aa4f73022f6f884d432d3e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 2 Apr 2024 23:13:15 +0800 Subject: [PATCH 29/71] =?UTF-8?q?fix:=20=E5=85=A8=E5=B1=8F=E6=97=B6?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E5=BC=B9=E5=B9=95=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video/detail/widgets/header_control.dart | 132 ++++++++++++++++-- 1 file changed, 123 insertions(+), 9 deletions(-) diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 858ca2df..9448a62a 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -17,6 +17,7 @@ import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/services/shutdown_timer_service.dart'; +import '../../../../http/danmaku.dart'; import '../../../../models/common/search_type.dart'; import '../../../../models/video_detail_res.dart'; import '../introduction/index.dart'; @@ -52,7 +53,7 @@ class _HeaderControlState extends State { final Box videoStorage = GStrorage.video; late List speedsList; double buttonSpace = 8; - bool showTitle = false; + RxBool isFullScreen = false.obs; late String heroTag; late VideoIntroController videoIntroController; late VideoDetailData videoDetail; @@ -69,13 +70,8 @@ class _HeaderControlState extends State { } void fullScreenStatusListener() { - widget.videoDetailCtr!.plPlayerController.isFullScreen - .listen((bool isFullScreen) { - if (isFullScreen) { - showTitle = true; - } else { - showTitle = false; - } + widget.videoDetailCtr!.plPlayerController.isFullScreen.listen((bool val) { + isFullScreen.value = val; /// TODO setState() called after dispose() if (mounted) { @@ -218,6 +214,87 @@ class _HeaderControlState extends State { ); } + /// 发送弹幕 + void showShootDanmakuSheet() { + final TextEditingController textController = TextEditingController(); + bool isSending = false; // 追踪是否正在发送 + showDialog( + context: Get.context!, + builder: (BuildContext context) { + // TODO: 支持更多类型和颜色的弹幕 + return AlertDialog( + title: const Text('发送弹幕(测试)'), + content: StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return TextField( + controller: textController, + ); + }), + actions: [ + TextButton( + onPressed: () => Get.back(), + child: Text( + '取消', + style: TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return TextButton( + onPressed: isSending + ? null + : () async { + final String msg = textController.text; + if (msg.isEmpty) { + SmartDialog.showToast('弹幕内容不能为空'); + return; + } else if (msg.length > 100) { + SmartDialog.showToast('弹幕内容不能超过100个字符'); + return; + } + setState(() { + isSending = true; // 开始发送,更新状态 + }); + //修改按钮文字 + final dynamic res = await DanmakaHttp.shootDanmaku( + oid: widget.videoDetailCtr!.cid.value, + msg: textController.text, + bvid: widget.videoDetailCtr!.bvid, + progress: + widget.controller!.position.value.inMilliseconds, + type: 1, + ); + setState(() { + isSending = false; // 发送结束,更新状态 + }); + if (res['status']) { + SmartDialog.showToast('发送成功'); + // 发送成功,自动预览该弹幕,避免重新请求 + // TODO: 暂停状态下预览弹幕仍会移动与计时,可考虑添加到dmSegList或其他方式实现 + widget.controller!.danmakuController!.addItems([ + DanmakuItem( + msg, + color: Colors.white, + time: widget + .controller!.position.value.inMilliseconds, + type: DanmakuItemType.scroll, + isSend: true, + ) + ]); + Get.back(); + } else { + SmartDialog.showToast('发送失败,错误信息为${res['msg']}'); + } + }, + child: Text(isSending ? '发送中...' : '发送'), + ); + }) + ], + ); + }, + ); + } + /// 定时关闭 void scheduleExit() async { const List scheduleTimeChoices = [ @@ -1029,7 +1106,7 @@ class _HeaderControlState extends State { }, ), SizedBox(width: buttonSpace), - if (showTitle && + if (isFullScreen.value && isLandscape && widget.videoType == SearchType.video) ...[ Column( @@ -1081,6 +1158,43 @@ class _HeaderControlState extends State { // ), // fuc: () => _.screenshot(), // ), + if (isFullScreen.value) ...[ + SizedBox( + width: 56, + height: 34, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () => showShootDanmakuSheet(), + child: const Text( + '发弹幕', + style: textStyle, + ), + ), + ), + SizedBox( + width: 34, + height: 34, + child: Obx( + () => IconButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () { + _.isOpenDanmu.value = !_.isOpenDanmu.value; + }, + icon: Icon( + _.isOpenDanmu.value + ? Icons.subtitles_outlined + : Icons.subtitles_off_outlined, + size: 19, + color: Colors.white, + ), + ), + ), + ), + ], SizedBox(width: buttonSpace), if (Platform.isAndroid) ...[ SizedBox( From 74f6b0ad1e3aaf0d80b917c68fddb0f853755dc0 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 2 Apr 2024 23:58:27 +0800 Subject: [PATCH 30/71] =?UTF-8?q?fix:=20=E8=AF=84=E8=AE=BA=E6=A1=86?= =?UTF-8?q?=E5=88=87=E6=8D=A2action=E6=97=B6=E9=AB=98=E5=BA=A6=E8=B7=B3?= =?UTF-8?q?=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/reply_new/view.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pages/video/detail/reply_new/view.dart b/lib/pages/video/detail/reply_new/view.dart index 05351411..a94b6071 100644 --- a/lib/pages/video/detail/reply_new/view.dart +++ b/lib/pages/video/detail/reply_new/view.dart @@ -142,9 +142,10 @@ class _VideoReplyNewDialogState extends State @override Widget build(BuildContext context) { - double keyboardHeight = EdgeInsets.fromViewPadding( + double _keyboardHeight = EdgeInsets.fromViewPadding( View.of(context).viewInsets, View.of(context).devicePixelRatio) .bottom; + print('_keyboardHeight: $_keyboardHeight'); return Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( @@ -235,7 +236,11 @@ class _VideoReplyNewDialogState extends State duration: const Duration(milliseconds: 300), child: SizedBox( width: double.infinity, - height: toolbarType == 'input' ? keyboardHeight : emoteHeight, + height: toolbarType == 'input' + ? (_keyboardHeight > keyboardHeight + ? _keyboardHeight + : keyboardHeight) + : emoteHeight, child: EmotePanel( onChoose: (package, emote) => onChooseEmote(package, emote), ), From 2ba72e3792ef32f45ea9d1ac6568e584e7e22243 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 3 Apr 2024 23:59:24 +0800 Subject: [PATCH 31/71] Update README.md --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 237bd07f..470e9a35 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,13 @@ Xcode 13.4 不支持**auto_orientation**,请注释相关代码 ```bash -[✓] Flutter (Channel stable, 3.16.4, on macOS 14.1.2 23B92 darwin-arm64, locale +[✓] Flutter (Channel stable, 3.16.5, on macOS 14.1.2 23B92 darwin-arm64, locale zh-Hans-CN) [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 15.1) [✓] Chrome - develop for the web [✓] Android Studio (version 2022.3) -[✓] VS Code (version 1.85.1) +[✓] VS Code (version 1.87.2) [✓] Connected device (3 available) [✓] Network resources @@ -44,6 +44,9 @@ Xcode 13.4 不支持**auto_orientation**,请注释相关代码 ## 技术交流 Telegram: https://t.me/+lm_oOVmF0RJiODk1 + +Tg Beta版本:@PiliPala_Beta + QQ频道: https://pd.qq.com/s/365esodk3 From b58df720fd7d8d45836662f2f39ecc42f3300c97 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 4 Apr 2024 23:41:16 +0800 Subject: [PATCH 32/71] =?UTF-8?q?mod:=20=E4=BC=98=E5=8C=96selectDialog?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/setting/widgets/select_dialog.dart | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/pages/setting/widgets/select_dialog.dart b/lib/pages/setting/widgets/select_dialog.dart index 72119755..50229f9e 100644 --- a/lib/pages/setting/widgets/select_dialog.dart +++ b/lib/pages/setting/widgets/select_dialog.dart @@ -44,6 +44,7 @@ class _SelectDialogState extends State> { setState(() { _tempValue = value as T; }); + Navigator.pop(context, _tempValue); }, ), ] @@ -51,19 +52,6 @@ class _SelectDialogState extends State> { ), ); }), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text( - '取消', - style: TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - TextButton( - onPressed: () => Navigator.pop(context, _tempValue), - child: const Text('确定'), - ) - ], ); } } From 247f6ee0a7c077342e09c07cf7ac6eb22ab097fe Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 4 Apr 2024 23:59:53 +0800 Subject: [PATCH 33/71] mod: findClosestNumber --- lib/pages/video/detail/controller.dart | 10 +++++----- lib/utils/utils.dart | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 5c4ac14b..c1a96132 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -91,7 +91,7 @@ class VideoDetailController extends GetxController late bool enableCDN; late int? cacheVideoQa; late String cacheDecode; - late int cacheAudioQa; + late int defaultAudioQa; PersistentBottomSheetController? replyReplyBottomSheetCtr; RxList subtitleContents = @@ -146,7 +146,7 @@ class VideoDetailController extends GetxController // 预设的解码格式 cacheDecode = setting.get(SettingBoxKey.defaultDecode, defaultValue: VideoDecodeFormats.values.last.code); - cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa, + defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa, defaultValue: AudioQuality.hiRes.code); oid.value = IdUtils.bv2av(Get.parameters['bvid']!); getSubtitle(); @@ -353,9 +353,9 @@ class VideoDetailController extends GetxController if (audiosList.isNotEmpty) { final List numbers = audiosList.map((map) => map.id!).toList(); - int closestNumber = Utils.findClosestNumber(cacheAudioQa, numbers); - if (!numbers.contains(cacheAudioQa) && - numbers.any((e) => e > cacheAudioQa)) { + int closestNumber = Utils.findClosestNumber(defaultAudioQa, numbers); + if (!numbers.contains(defaultAudioQa) && + numbers.any((e) => e > defaultAudioQa)) { closestNumber = 30280; } firstAudio = audiosList.firstWhere((e) => e.id == closestNumber); diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index cb7cbf25..a7273f05 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -209,6 +209,8 @@ class Utils { static int findClosestNumber(int target, List numbers) { int minDiff = 127; int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数 + + // 向下查找 try { for (int number in numbers) { if (number < target) { @@ -221,6 +223,20 @@ class Utils { } } } catch (_) {} + + // 向上查找 + if (closestNumber == 0) { + try { + for (int number in numbers) { + int diff = (number - target).abs(); + + if (diff < minDiff) { + minDiff = diff; + closestNumber = number; + } + } + } catch (_) {} + } return closestNumber; } From 5500a58c32a23dfe5f684e6ecf5fd6a2b13d5b05 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 4 Apr 2024 23:41:16 +0800 Subject: [PATCH 34/71] =?UTF-8?q?mod:=20=E4=BC=98=E5=8C=96selectDialog?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/setting/widgets/select_dialog.dart | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/pages/setting/widgets/select_dialog.dart b/lib/pages/setting/widgets/select_dialog.dart index 72119755..50229f9e 100644 --- a/lib/pages/setting/widgets/select_dialog.dart +++ b/lib/pages/setting/widgets/select_dialog.dart @@ -44,6 +44,7 @@ class _SelectDialogState extends State> { setState(() { _tempValue = value as T; }); + Navigator.pop(context, _tempValue); }, ), ] @@ -51,19 +52,6 @@ class _SelectDialogState extends State> { ), ); }), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context), - child: Text( - '取消', - style: TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - TextButton( - onPressed: () => Navigator.pop(context, _tempValue), - child: const Text('确定'), - ) - ], ); } } From ec7762644b25fc6fdd4e6c3666391f390daacdac Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 5 Apr 2024 00:02:25 +0800 Subject: [PATCH 35/71] mod: findClosestNumber --- lib/pages/video/detail/controller.dart | 10 +++++----- lib/utils/utils.dart | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 5c4ac14b..c1a96132 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -91,7 +91,7 @@ class VideoDetailController extends GetxController late bool enableCDN; late int? cacheVideoQa; late String cacheDecode; - late int cacheAudioQa; + late int defaultAudioQa; PersistentBottomSheetController? replyReplyBottomSheetCtr; RxList subtitleContents = @@ -146,7 +146,7 @@ class VideoDetailController extends GetxController // 预设的解码格式 cacheDecode = setting.get(SettingBoxKey.defaultDecode, defaultValue: VideoDecodeFormats.values.last.code); - cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa, + defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa, defaultValue: AudioQuality.hiRes.code); oid.value = IdUtils.bv2av(Get.parameters['bvid']!); getSubtitle(); @@ -353,9 +353,9 @@ class VideoDetailController extends GetxController if (audiosList.isNotEmpty) { final List numbers = audiosList.map((map) => map.id!).toList(); - int closestNumber = Utils.findClosestNumber(cacheAudioQa, numbers); - if (!numbers.contains(cacheAudioQa) && - numbers.any((e) => e > cacheAudioQa)) { + int closestNumber = Utils.findClosestNumber(defaultAudioQa, numbers); + if (!numbers.contains(defaultAudioQa) && + numbers.any((e) => e > defaultAudioQa)) { closestNumber = 30280; } firstAudio = audiosList.firstWhere((e) => e.id == closestNumber); diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index cb7cbf25..a7273f05 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -209,6 +209,8 @@ class Utils { static int findClosestNumber(int target, List numbers) { int minDiff = 127; int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数 + + // 向下查找 try { for (int number in numbers) { if (number < target) { @@ -221,6 +223,20 @@ class Utils { } } } catch (_) {} + + // 向上查找 + if (closestNumber == 0) { + try { + for (int number in numbers) { + int diff = (number - target).abs(); + + if (diff < minDiff) { + minDiff = diff; + closestNumber = number; + } + } + } catch (_) {} + } return closestNumber; } From 0d0e0b9adb184ae61a4c2e73b60b85e31f3efe94 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 5 Apr 2024 22:19:45 +0800 Subject: [PATCH 36/71] =?UTF-8?q?fix:=20=E5=85=B3=E6=B3=A8=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E7=8A=B6=E6=80=81=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/member/widgets/profile.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pages/member/widgets/profile.dart b/lib/pages/member/widgets/profile.dart index 4bf7b7db..a708a35e 100644 --- a/lib/pages/member/widgets/profile.dart +++ b/lib/pages/member/widgets/profile.dart @@ -180,7 +180,9 @@ class ProfilePanel extends StatelessWidget { Obx( () => Expanded( child: TextButton( - onPressed: () => ctr.actionRelationMod(), + onPressed: () => loadingStatus + ? null + : ctr.actionRelationMod(), style: TextButton.styleFrom( foregroundColor: ctr.attribute.value == -1 ? Colors.transparent From 99645c7b4aee81a7165a8708ed5e296658a660c1 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 5 Apr 2024 23:20:44 +0800 Subject: [PATCH 37/71] fix: seekTo multiple trigger --- lib/plugin/pl_player/controller.dart | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index b385fca8..f936526b 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -101,7 +101,7 @@ class PlPlayerController { bool _isFirstTime = true; Timer? _timer; - Timer? _timerForSeek; + late Timer? _timerForSeek; Timer? _timerForVolume; Timer? _timerForShowingVolume; Timer? _timerForGettingVolume; @@ -646,9 +646,6 @@ class PlPlayerController { /// 跳转至指定位置 Future seekTo(Duration position, {type = 'seek'}) async { - // if (position >= duration.value) { - // position = duration.value - const Duration(milliseconds: 100); - // } if (position < Duration.zero) { position = Duration.zero; } @@ -661,21 +658,13 @@ class PlPlayerController { await _videoPlayerController?.stream.buffer.first; } await _videoPlayerController?.seek(position); - // if (playerStatus.stopped) { - // play(); - // } } else { - print('seek duration else'); _timerForSeek?.cancel(); - _timerForSeek = + _timerForSeek ??= Timer.periodic(const Duration(milliseconds: 200), (Timer t) async { - //_timerForSeek = null; if (duration.value.inSeconds != 0) { await _videoPlayerController!.stream.buffer.first; await _videoPlayerController?.seek(position); - // if (playerStatus.status.value == PlayerStatus.paused) { - // play(); - // } t.cancel(); _timerForSeek = null; } From a5494484aefe83fc4cb122ec1dcec9c72b9c67c8 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 6 Apr 2024 11:30:53 +0800 Subject: [PATCH 38/71] =?UTF-8?q?mod:=20=E6=9B=B4=E6=96=B0=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E5=99=A8=E5=BA=95=E6=A0=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/controller.dart | 9 ++ lib/pages/video/detail/view.dart | 2 + lib/plugin/pl_player/view.dart | 9 +- .../pl_player/widgets/bottom_control.dart | 87 +------------------ 4 files changed, 18 insertions(+), 89 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index fe870873..227d6b84 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -21,6 +21,7 @@ import 'package:pilipala/utils/video_utils.dart'; import 'package:screen_brightness/screen_brightness.dart'; import '../../../http/danmaku.dart'; +import '../../../plugin/pl_player/models/bottom_control_type.dart'; import '../../../utils/id_utils.dart'; import 'widgets/header_control.dart'; @@ -94,6 +95,14 @@ class VideoDetailController extends GetxController PersistentBottomSheetController? replyReplyBottomSheetCtr; late bool enableRelatedVideo; + List subtitles = []; + RxList bottomList = [ + BottomControlType.playOrPause, + BottomControlType.time, + BottomControlType.space, + BottomControlType.fit, + BottomControlType.fullscreen, + ].obs; @override void onInit() { diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index a403e298..5ebbf62e 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -24,6 +24,7 @@ import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/utils/storage.dart'; +import '../../../plugin/pl_player/models/bottom_control_type.dart'; import '../../../services/shutdown_timer_service.dart'; import 'widgets/app_bar.dart'; @@ -298,6 +299,7 @@ class _VideoDetailPageState extends State playerController: plPlayerController!, ), ), + bottomList: vdCtr.bottomList, ); }, ); diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 90861204..d32fc8e4 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -214,8 +214,8 @@ class _PLVideoPlayerState extends State /// 上一集 BottomControlType.pre: ComBtn( icon: const Icon( - Icons.skip_previous_outlined, - size: 15, + Icons.skip_previous_rounded, + size: 21, color: Colors.white, ), fuc: () {}, @@ -229,8 +229,8 @@ class _PLVideoPlayerState extends State /// 下一集 BottomControlType.next: ComBtn( icon: const Icon( - Icons.last_page_outlined, - size: 15, + Icons.skip_next_rounded, + size: 21, color: Colors.white, ), fuc: () {}, @@ -239,6 +239,7 @@ class _PLVideoPlayerState extends State /// 时间进度 BottomControlType.time: Row( children: [ + const SizedBox(width: 8), Obx(() { return Text( _.durationSeconds.value >= 3600 diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index ebb71b54..35e7792a 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -68,91 +68,8 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { ); }, ), - Row( - children: [...buildBottomControl!], - ), - // Row( - // children: [ - // PlayOrPauseButton( - // controller: _, - // ), - // const SizedBox(width: 4), - // // 播放时间 - // Obx(() { - // return Text( - // _.durationSeconds.value >= 3600 - // ? printDurationWithHours( - // Duration(seconds: _.positionSeconds.value)) - // : printDuration( - // Duration(seconds: _.positionSeconds.value)), - // style: textStyle, - // ); - // }), - // const SizedBox(width: 2), - // const Text('/', style: textStyle), - // const SizedBox(width: 2), - // Obx( - // () => Text( - // _.durationSeconds.value >= 3600 - // ? printDurationWithHours( - // Duration(seconds: _.durationSeconds.value)) - // : printDuration( - // Duration(seconds: _.durationSeconds.value)), - // style: textStyle, - // ), - // ), - // const Spacer(), - // // 倍速 - // // Obx( - // // () => SizedBox( - // // width: 45, - // // height: 34, - // // child: TextButton( - // // style: ButtonStyle( - // // padding: MaterialStateProperty.all(EdgeInsets.zero), - // // ), - // // onPressed: () { - // // _.togglePlaybackSpeed(); - // // }, - // // child: Text( - // // '${_.playbackSpeed.toString()}X', - // // style: textStyle, - // // ), - // // ), - // // ), - // // ), - // SizedBox( - // height: 30, - // child: TextButton( - // onPressed: () => _.toggleVideoFit(), - // style: ButtonStyle( - // padding: MaterialStateProperty.all(EdgeInsets.zero), - // ), - // child: Obx( - // () => Text( - // _.videoFitDEsc.value, - // style: const TextStyle(color: Colors.white, fontSize: 13), - // ), - // ), - // ), - // ), - // const SizedBox(width: 10), - // // 全屏 - // Obx( - // () => ComBtn( - // icon: Icon( - // _.isFullScreen.value - // ? FontAwesomeIcons.compress - // : FontAwesomeIcons.expand, - // size: 15, - // color: Colors.white, - // ), - // fuc: () => triggerFullScreen!(), - // ), - // ), - // ], - // ), - const SizedBox(height: 12), + Row(children: [...buildBottomControl!]), + const SizedBox(height: 10), ], ), ); From d4212f88c52704960b384e8565aae81ace88e47f Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 6 Apr 2024 15:26:53 +0800 Subject: [PATCH 39/71] =?UTF-8?q?feat:=20=E6=8A=95=E7=A8=BF=E3=80=81?= =?UTF-8?q?=E7=95=AA=E5=89=A7=E5=90=88=E9=9B=86=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/pages_bottom_sheet.dart | 135 +++++++++ lib/models/common/video_episode_type.dart | 5 + lib/pages/bangumi/introduction/view.dart | 5 +- lib/pages/bangumi/widgets/bangumi_panel.dart | 227 +++++---------- .../video/detail/introduction/controller.dart | 10 +- lib/pages/video/detail/introduction/view.dart | 25 +- .../detail/introduction/widgets/page.dart | 258 ------------------ .../introduction/widgets/page_panel.dart | 184 +++++++++++++ .../{season.dart => season_panel.dart} | 96 ++----- lib/pages/video/detail/view.dart | 1 + .../video/detail/widgets/header_control.dart | 3 +- .../video/detail/widgets/right_drawer.dart | 19 ++ 12 files changed, 458 insertions(+), 510 deletions(-) create mode 100644 lib/common/pages_bottom_sheet.dart create mode 100644 lib/models/common/video_episode_type.dart delete mode 100644 lib/pages/video/detail/introduction/widgets/page.dart create mode 100644 lib/pages/video/detail/introduction/widgets/page_panel.dart rename lib/pages/video/detail/introduction/widgets/{season.dart => season_panel.dart} (56%) create mode 100644 lib/pages/video/detail/widgets/right_drawer.dart diff --git a/lib/common/pages_bottom_sheet.dart b/lib/common/pages_bottom_sheet.dart new file mode 100644 index 00000000..b31ec4b1 --- /dev/null +++ b/lib/common/pages_bottom_sheet.dart @@ -0,0 +1,135 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; +import '../models/common/video_episode_type.dart'; + +class EpisodeBottomSheet { + final List episodes; + final int currentCid; + final dynamic dataType; + final BuildContext context; + final Function changeFucCall; + final int? cid; + final double? sheetHeight; + + EpisodeBottomSheet({ + required this.episodes, + required this.currentCid, + required this.dataType, + required this.context, + required this.changeFucCall, + this.cid, + this.sheetHeight, + }); + + Widget buildEpisodeListItem( + dynamic episode, + int index, + bool isCurrentIndex, + ) { + Color primary = Theme.of(context).colorScheme.primary; + Color onSurface = Theme.of(context).colorScheme.onSurface; + + String title = ''; + switch (dataType) { + case VideoEpidoesType.videoEpisode: + title = episode.title; + break; + case VideoEpidoesType.videoPart: + title = episode.pagePart; + break; + case VideoEpidoesType.bangumiEpisode: + title = '第${episode.title}话 ${episode.longTitle!}'; + break; + } + return ListTile( + 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, + ), + ), + ); + } + + Widget buildTitle() { + return AppBar( + toolbarHeight: 45, + automaticallyImplyLeading: false, + centerTitle: false, + title: Text( + '合集(${episodes.length})', + style: Theme.of(context).textTheme.titleMedium, + ), + actions: [ + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () => Navigator.pop(context), + ), + const SizedBox(width: 14), + ], + ); + } + + /// The [BuildContext] of the widget that calls the bottom sheet. + PersistentBottomSheetController show(BuildContext context) { + final ItemScrollController itemScrollController = ItemScrollController(); + int currentIndex = episodes.indexWhere((dynamic e) => e.cid == currentCid); + final PersistentBottomSheetController btmSheetCtr = showBottomSheet( + context: context, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + itemScrollController.jumpTo(index: currentIndex); + }); + return Container( + height: sheetHeight, + color: Theme.of(context).colorScheme.background, + child: Column( + children: [ + buildTitle(), + Expanded( + child: Material( + child: ScrollablePositionedList.builder( + itemScrollController: itemScrollController, + itemCount: episodes.length + 1, + itemBuilder: (BuildContext context, int index) { + bool isLastItem = index == episodes.length; + bool isCurrentIndex = currentIndex == index; + return isLastItem + ? SizedBox( + height: + MediaQuery.of(context).padding.bottom + 20, + ) + : buildEpisodeListItem( + episodes[index], + index, + isCurrentIndex, + ); + }, + ), + ), + ), + ], + ), + ); + }); + }, + ); + return btmSheetCtr; + } +} diff --git a/lib/models/common/video_episode_type.dart b/lib/models/common/video_episode_type.dart new file mode 100644 index 00000000..4875438f --- /dev/null +++ b/lib/models/common/video_episode_type.dart @@ -0,0 +1,5 @@ +enum VideoEpidoesType { + videoEpisode, + videoPart, + bangumiEpisode, +} diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index 6255ffda..13db7432 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -138,6 +138,9 @@ class _BangumiInfoState extends State { cid = widget.cid!; videoDetailCtr.cid.listen((p0) { cid = p0; + if (!mounted) { + return; + } setState(() {}); }); } @@ -317,7 +320,7 @@ class _BangumiInfoState extends State { if (widget.bangumiDetail!.episodes!.isNotEmpty) ...[ BangumiPanel( pages: widget.bangumiDetail!.episodes!, - cid: cid ?? widget.bangumiDetail!.episodes!.first.cid, + cid: cid! ?? widget.bangumiDetail!.episodes!.first.cid!, sheetHeight: sheetHeight, changeFuc: (bvid, cid, aid) => bangumiIntroController.changeSeasonOrbangu(bvid, cid, aid), diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index 05fd814c..988f8d4f 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -6,19 +8,21 @@ import 'package:pilipala/models/bangumi/info.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; +import '../../../common/pages_bottom_sheet.dart'; +import '../../../models/common/video_episode_type.dart'; class BangumiPanel extends StatefulWidget { const BangumiPanel({ super.key, required this.pages, - this.cid, + required this.cid, this.sheetHeight, this.changeFuc, this.bangumiDetail, }); final List pages; - final int? cid; + final int cid; final double? sheetHeight; final Function? changeFuc; final BangumiInfoModel? bangumiDetail; @@ -28,9 +32,8 @@ class BangumiPanel extends StatefulWidget { } class _BangumiPanelState extends State { - late int currentIndex; + late RxInt currentIndex = (-1).obs; final ScrollController listViewScrollCtr = ScrollController(); - final ScrollController listViewScrollCtr_2 = ScrollController(); Box userInfoCache = GStrorage.userInfo; dynamic userInfo; // 默认未开通 @@ -39,169 +42,68 @@ class _BangumiPanelState extends State { String heroTag = Get.arguments['heroTag']; late final VideoDetailController videoDetailCtr; final ItemScrollController itemScrollController = ItemScrollController(); + late PersistentBottomSheetController? _bottomSheetController; @override void initState() { super.initState(); - cid = widget.cid!; - currentIndex = widget.pages.indexWhere((e) => e.cid == cid); + cid = widget.cid; + videoDetailCtr = Get.find(tag: heroTag); + currentIndex.value = + widget.pages.indexWhere((EpisodeItem e) => e.cid == cid); scrollToIndex(); + videoDetailCtr.cid.listen((int p0) { + cid = p0; + currentIndex.value = + widget.pages.indexWhere((EpisodeItem e) => e.cid == cid); + scrollToIndex(); + }); + + /// 获取大会员状态 userInfo = userInfoCache.get('userInfoCache'); if (userInfo != null) { vipStatus = userInfo.vipStatus; } - videoDetailCtr = Get.find(tag: heroTag); - - videoDetailCtr.cid.listen((int p0) { - cid = p0; - setState(() {}); - currentIndex = widget.pages.indexWhere((EpisodeItem e) => e.cid == cid); - scrollToIndex(); - }); } @override void dispose() { listViewScrollCtr.dispose(); - listViewScrollCtr_2.dispose(); super.dispose(); } - Widget buildPageListItem( - EpisodeItem page, - int index, - bool isCurrentIndex, - ) { - Color primary = Theme.of(context).colorScheme.primary; - return ListTile( - onTap: () { - Get.back(); - setState(() { - changeFucCall(page, index); - }); - }, - dense: false, - leading: isCurrentIndex - ? Image.asset( - 'assets/images/live.gif', - color: primary, - height: 12, - ) - : null, - title: Text( - '第${page.title}话 ${page.longTitle!}', - style: TextStyle( - fontSize: 14, - color: isCurrentIndex - ? primary - : Theme.of(context).colorScheme.onSurface, - ), - ), - trailing: page.badge != null - ? Text( - page.badge!, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - ), - ) - : const SizedBox(), - ); - } - - void showBangumiPanel() { - showBottomSheet( - context: context, - builder: (BuildContext context) { - return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - WidgetsBinding.instance.addPostFrameCallback((_) async { - // await Future.delayed(const Duration(milliseconds: 200)); - // listViewScrollCtr_2.animateTo(currentIndex * 56, - // duration: const Duration(milliseconds: 500), - // curve: Curves.easeInOut); - itemScrollController.jumpTo(index: currentIndex); - }); - // 在这里使用 setState 更新状态 - return Container( - height: widget.sheetHeight, - color: Theme.of(context).colorScheme.background, - child: Column( - children: [ - AppBar( - toolbarHeight: 45, - automaticallyImplyLeading: false, - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '合集(${widget.pages.length})', - style: Theme.of(context).textTheme.titleMedium, - ), - IconButton( - icon: const Icon(Icons.close), - onPressed: () => Navigator.pop(context), - ), - ], - ), - titleSpacing: 10, - ), - Expanded( - child: Material( - child: ScrollablePositionedList.builder( - itemCount: widget.pages.length + 1, - itemBuilder: (BuildContext context, int index) { - bool isLastItem = index == widget.pages.length; - bool isCurrentIndex = currentIndex == index; - return isLastItem - ? SizedBox( - height: - MediaQuery.of(context).padding.bottom + - 20, - ) - : buildPageListItem( - widget.pages[index], - index, - isCurrentIndex, - ); - }, - itemScrollController: itemScrollController, - ), - ), - ), - ], - ), - ); - }, - ); - }, - ); - } - void changeFucCall(item, i) async { if (item.badge != null && item.badge == '会员' && vipStatus != 1) { SmartDialog.showToast('需要大会员'); return; } - await widget.changeFuc!( + widget.changeFuc?.call( item.bvid, item.cid, item.aid, ); + _bottomSheetController?.close(); currentIndex = i; - setState(() {}); scrollToIndex(); } void scrollToIndex() { WidgetsBinding.instance.addPostFrameCallback((_) { // 在回调函数中获取更新后的状态 - listViewScrollCtr.animateTo(currentIndex * 150, - duration: const Duration(milliseconds: 500), curve: Curves.easeInOut); + final double offset = min((currentIndex * 150) - 75, + listViewScrollCtr.position.maxScrollExtent); + listViewScrollCtr.animateTo( + offset, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); }); } @override Widget build(BuildContext context) { + Color primary = Theme.of(context).colorScheme.primary; + Color onSurface = Theme.of(context).colorScheme.onSurface; return Column( children: [ Padding( @@ -211,12 +113,14 @@ class _BangumiPanelState extends State { children: [ const Text('选集 '), Expanded( - child: Text( - ' 正在播放:${widget.pages[currentIndex].longTitle}', - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, + child: Obx( + () => Text( + ' 正在播放:${widget.pages[currentIndex.value].longTitle}', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), ), ), ), @@ -227,7 +131,16 @@ class _BangumiPanelState extends State { style: ButtonStyle( padding: MaterialStateProperty.all(EdgeInsets.zero), ), - onPressed: () => showBangumiPanel(), + onPressed: () { + _bottomSheetController = EpisodeBottomSheet( + currentCid: cid, + episodes: widget.pages, + changeFucCall: changeFucCall, + sheetHeight: widget.sheetHeight, + dataType: VideoEpidoesType.bangumiEpisode, + context: context, + ).show(context); + }, child: Text( '${widget.bangumiDetail!.newEp!['desc']}', style: const TextStyle(fontSize: 13), @@ -245,6 +158,8 @@ class _BangumiPanelState extends State { itemCount: widget.pages.length, itemExtent: 150, itemBuilder: (BuildContext context, int i) { + var page = widget.pages[i]; + bool isSelected = i == currentIndex.value; return Container( width: 150, margin: const EdgeInsets.only(right: 10), @@ -253,42 +168,37 @@ class _BangumiPanelState extends State { borderRadius: BorderRadius.circular(6), clipBehavior: Clip.hardEdge, child: InkWell( - onTap: () => changeFucCall(widget.pages[i], i), + onTap: () => changeFucCall(page, i), child: Padding( padding: const EdgeInsets.symmetric( - vertical: 8, horizontal: 10), + vertical: 8, + horizontal: 10, + ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ - if (i == currentIndex) ...[ - Image.asset( - 'assets/images/live.png', - color: Theme.of(context).colorScheme.primary, - height: 12, - ), + if (isSelected) ...[ + Image.asset('assets/images/live.png', + color: primary, height: 12), const SizedBox(width: 6) ], Text( '第${i + 1}话', style: TextStyle( - fontSize: 13, - color: i == currentIndex - ? Theme.of(context).colorScheme.primary - : Theme.of(context) - .colorScheme - .onSurface), + fontSize: 13, + color: isSelected ? primary : onSurface, + ), ), const SizedBox(width: 2), - if (widget.pages[i].badge != null) ...[ + if (page.badge != null) ...[ const Spacer(), Text( - widget.pages[i].badge!, + page.badge!, style: TextStyle( fontSize: 12, - color: - Theme.of(context).colorScheme.primary, + color: primary, ), ), ] @@ -296,13 +206,12 @@ class _BangumiPanelState extends State { ), const SizedBox(height: 3), Text( - widget.pages[i].longTitle!, + page.longTitle!, maxLines: 1, style: TextStyle( - fontSize: 13, - color: i == currentIndex - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.onSurface), + fontSize: 13, + color: isSelected ? primary : onSurface, + ), overflow: TextOverflow.ellipsis, ) ], diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 8114bdaf..241605ab 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -25,15 +25,10 @@ class VideoIntroController extends GetxController { VideoIntroController({required this.bvid}); // 视频bvid String bvid; - // 请求状态 - RxBool isLoading = false.obs; - // 视频详情 请求返回 Rx videoDetail = VideoDetailData().obs; - // up主粉丝数 Map userStat = {'follower': '-'}; - // 是否点赞 RxBool hasLike = false.obs; // 是否投币 @@ -59,6 +54,7 @@ class VideoIntroController extends GetxController { bool isPaused = false; String heroTag = ''; late ModelResult modelResult; + late PersistentBottomSheetController? bottomSheetController; @override void onInit() { @@ -562,4 +558,8 @@ class VideoIntroController extends GetxController { } return res; } + + hiddenEpisodeBottomSheet() { + bottomSheetController?.close(); + } } diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index a990aab8..608beec8 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -20,8 +20,8 @@ import '../../../../http/user.dart'; import 'widgets/action_item.dart'; import 'widgets/fav_panel.dart'; import 'widgets/intro_detail.dart'; -import 'widgets/page.dart'; -import 'widgets/season.dart'; +import 'widgets/page_panel.dart'; +import 'widgets/season_panel.dart'; class VideoIntroPanel extends StatefulWidget { final String bvid; @@ -384,18 +384,25 @@ class _VideoInfoState extends State with TickerProviderStateMixin { sheetHeight: sheetHeight, changeFuc: (bvid, cid, aid) => videoIntroController.changeSeasonOrbangu(bvid, cid, aid), + videoIntroCtr: videoIntroController, ), ) ], if (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), - )) + Obx( + () => PagesPanel( + pages: widget.videoDetail!.pages!, + cid: videoIntroController.lastPlayCid.value, + sheetHeight: sheetHeight, + changeFuc: (cid) => videoIntroController.changeSeasonOrbangu( + videoIntroController.bvid, + cid, + null, + ), + videoIntroCtr: videoIntroController, + ), + ) ], GestureDetector( onTap: onPushMember, diff --git a/lib/pages/video/detail/introduction/widgets/page.dart b/lib/pages/video/detail/introduction/widgets/page.dart deleted file mode 100644 index 8d296050..00000000 --- a/lib/pages/video/detail/introduction/widgets/page.dart +++ /dev/null @@ -1,258 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:pilipala/models/video_detail_res.dart'; -import 'package:pilipala/pages/video/detail/index.dart'; - -class PagesPanel extends StatefulWidget { - const PagesPanel({ - super.key, - required this.pages, - this.cid, - this.sheetHeight, - this.changeFuc, - }); - final List pages; - final int? cid; - final double? sheetHeight; - final Function? changeFuc; - - @override - State createState() => _PagesPanelState(); -} - -class _PagesPanelState extends State { - late List episodes; - late int cid; - late int currentIndex; - final String heroTag = Get.arguments['heroTag']; - late VideoDetailController _videoDetailController; - final ScrollController _scrollController = ScrollController(); - - @override - void initState() { - super.initState(); - cid = widget.cid!; - episodes = widget.pages; - _videoDetailController = Get.find(tag: heroTag); - currentIndex = episodes.indexWhere((Part e) => e.cid == cid); - _videoDetailController.cid.listen((int p0) { - cid = p0; - setState(() {}); - currentIndex = episodes.indexWhere((Part e) => e.cid == cid); - }); - } - - void changeFucCall(item, i) async { - await widget.changeFuc!( - item.cid, - ); - currentIndex = i; - setState(() {}); - } - - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } - - Widget buildEpisodeListItem( - Part episode, - int index, - bool isCurrentIndex, - ) { - Color primary = Theme.of(context).colorScheme.primary; - return ListTile( - onTap: () { - changeFucCall(episode, index); - Get.back(); - }, - dense: false, - leading: isCurrentIndex - ? Image.asset( - 'assets/images/live.gif', - color: primary, - height: 12, - ) - : null, - title: Text( - episode.pagePart!, - style: TextStyle( - fontSize: 14, - color: isCurrentIndex - ? primary - : Theme.of(context).colorScheme.onSurface, - ), - ), - ); - } - - @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: (BuildContext context) { - return StatefulBuilder(builder: - (BuildContext context, StateSetter setState) { - WidgetsBinding.instance - .addPostFrameCallback((_) async { - await Future.delayed( - const Duration(milliseconds: 200)); - _scrollController.jumpTo(currentIndex * 56); - }); - return 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( - controller: _scrollController, - itemCount: episodes.length + 1, - itemBuilder: - (BuildContext context, int index) { - bool isLastItem = - index == episodes.length; - bool isCurrentIndex = - currentIndex == index; - return isLastItem - ? SizedBox( - height: MediaQuery.of(context) - .padding - .bottom + - 20, - ) - : buildEpisodeListItem( - episodes[index], - index, - isCurrentIndex, - ); - }, - ), - ), - ), - ], - ), - ); - }); - }, - ); - }, - 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: (BuildContext context, int i) { - bool isCurrentIndex = currentIndex == 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 (isCurrentIndex) ...[ - 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: isCurrentIndex - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.onSurface), - overflow: TextOverflow.ellipsis, - )) - ], - ), - ), - ), - ), - ); - }, - ), - ) - ], - ); - } -} diff --git a/lib/pages/video/detail/introduction/widgets/page_panel.dart b/lib/pages/video/detail/introduction/widgets/page_panel.dart new file mode 100644 index 00000000..730a6105 --- /dev/null +++ b/lib/pages/video/detail/introduction/widgets/page_panel.dart @@ -0,0 +1,184 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/models/video_detail_res.dart'; +import 'package:pilipala/pages/video/detail/index.dart'; +import 'package:pilipala/pages/video/detail/introduction/index.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; +import '../../../../../common/pages_bottom_sheet.dart'; +import '../../../../../models/common/video_episode_type.dart'; + +class PagesPanel extends StatefulWidget { + const PagesPanel({ + super.key, + required this.pages, + required this.cid, + this.sheetHeight, + this.changeFuc, + required this.videoIntroCtr, + }); + final List pages; + final int cid; + final double? sheetHeight; + final Function? changeFuc; + final VideoIntroController videoIntroCtr; + + @override + State createState() => _PagesPanelState(); +} + +class _PagesPanelState extends State { + late List episodes; + late int cid; + late RxInt currentIndex = (-1).obs; + final String heroTag = Get.arguments['heroTag']; + late VideoDetailController _videoDetailController; + final ScrollController listViewScrollCtr = ScrollController(); + final ItemScrollController itemScrollController = ItemScrollController(); + late PersistentBottomSheetController? _bottomSheetController; + + @override + void initState() { + super.initState(); + cid = widget.cid; + episodes = widget.pages; + _videoDetailController = Get.find(tag: heroTag); + currentIndex.value = episodes.indexWhere((Part e) => e.cid == cid); + scrollToIndex(); + _videoDetailController.cid.listen((int p0) { + cid = p0; + currentIndex.value = episodes.indexWhere((Part e) => e.cid == cid); + scrollToIndex(); + }); + } + + @override + void dispose() { + listViewScrollCtr.dispose(); + super.dispose(); + } + + void changeFucCall(item, i) async { + widget.changeFuc?.call(item.cid); + currentIndex.value = i; + _bottomSheetController?.close(); + scrollToIndex(); + } + + void scrollToIndex() { + WidgetsBinding.instance.addPostFrameCallback((_) { + // 在回调函数中获取更新后的状态 + final double offset = min((currentIndex * 150) - 75, + listViewScrollCtr.position.maxScrollExtent); + listViewScrollCtr.animateTo( + offset, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }); + } + + @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: Obx(() => Text( + ' 正在播放:${widget.pages[currentIndex.value].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: () { + widget.videoIntroCtr.bottomSheetController = + _bottomSheetController = EpisodeBottomSheet( + currentCid: cid, + episodes: episodes, + changeFucCall: changeFucCall, + sheetHeight: widget.sheetHeight, + dataType: VideoEpidoesType.videoPart, + context: context, + ).show(context); + }, + 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, + controller: listViewScrollCtr, + itemCount: widget.pages.length, + itemExtent: 150, + itemBuilder: (BuildContext context, int i) { + bool isCurrentIndex = currentIndex.value == 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 (isCurrentIndex) ...[ + 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: isCurrentIndex + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface), + overflow: TextOverflow.ellipsis, + )) + ], + ), + ), + ), + ), + ); + }, + ), + ) + ], + ); + } +} diff --git a/lib/pages/video/detail/introduction/widgets/season.dart b/lib/pages/video/detail/introduction/widgets/season_panel.dart similarity index 56% rename from lib/pages/video/detail/introduction/widgets/season.dart rename to lib/pages/video/detail/introduction/widgets/season_panel.dart index 0f3884ed..cd8bc954 100644 --- a/lib/pages/video/detail/introduction/widgets/season.dart +++ b/lib/pages/video/detail/introduction/widgets/season_panel.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:pilipala/common/pages_bottom_sheet.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; +import '../../../../../models/common/video_episode_type.dart'; +import '../controller.dart'; class SeasonPanel extends StatefulWidget { const SeasonPanel({ @@ -12,11 +15,13 @@ class SeasonPanel extends StatefulWidget { this.cid, this.sheetHeight, this.changeFuc, + required this.videoIntroCtr, }); final UgcSeason ugcSeason; final int? cid; final double? sheetHeight; final Function? changeFuc; + final VideoIntroController videoIntroCtr; @override State createState() => _SeasonPanelState(); @@ -28,8 +33,8 @@ class _SeasonPanelState extends State { late int currentIndex; final String heroTag = Get.arguments['heroTag']; late VideoDetailController _videoDetailController; - final ScrollController _scrollController = ScrollController(); final ItemScrollController itemScrollController = ItemScrollController(); + late PersistentBottomSheetController? _bottomSheetController; @override void initState() { @@ -52,9 +57,6 @@ class _SeasonPanelState extends State { } /// 取对应 season_id 的 episodes - // episodes = widget.ugcSeason.sections! - // .firstWhere((e) => e.seasonId == widget.ugcSeason.id) - // .episodes!; currentIndex = episodes.indexWhere((EpisodeItem e) => e.cid == cid); _videoDetailController.cid.listen((int p0) { cid = p0; @@ -64,22 +66,16 @@ class _SeasonPanelState extends State { } void changeFucCall(item, int i) async { - await widget.changeFuc!( + widget.changeFuc?.call( IdUtils.av2bv(item.aid), item.cid, item.aid, ); currentIndex = i; - Get.back(); + _bottomSheetController?.close(); setState(() {}); } - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } - Widget buildEpisodeListItem( EpisodeItem episode, int index, @@ -123,71 +119,17 @@ class _SeasonPanelState extends State { borderRadius: BorderRadius.circular(6), clipBehavior: Clip.hardEdge, child: InkWell( - onTap: () => showBottomSheet( - context: context, - builder: (BuildContext context) { - return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - WidgetsBinding.instance.addPostFrameCallback((_) async { - itemScrollController.jumpTo(index: currentIndex); - }); - return 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: ScrollablePositionedList.builder( - itemCount: episodes.length + 1, - itemBuilder: (BuildContext context, int index) { - bool isLastItem = index == episodes.length; - bool isCurrentIndex = currentIndex == index; - return isLastItem - ? SizedBox( - height: MediaQuery.of(context) - .padding - .bottom + - 20, - ) - : buildEpisodeListItem( - episodes[index], - index, - isCurrentIndex, - ); - }, - itemScrollController: itemScrollController, - ), - ), - ), - ], - ), - ); - }); - }, - ), + onTap: () { + widget.videoIntroCtr.bottomSheetController = + _bottomSheetController = EpisodeBottomSheet( + currentCid: cid, + episodes: episodes, + changeFucCall: changeFucCall, + sheetHeight: widget.sheetHeight, + dataType: VideoEpidoesType.videoEpisode, + context: context, + ).show(context); + }, child: Padding( padding: const EdgeInsets.fromLTRB(8, 12, 8, 12), child: Row( diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index c2379f20..725639ff 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -176,6 +176,7 @@ class _VideoDetailPageState extends State plPlayerController?.isFullScreen.listen((bool isFullScreen) { if (isFullScreen) { vdCtr.hiddenReplyReplyPanel(); + videoIntroController.hiddenEpisodeBottomSheet(); } }); } diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 1ee65d83..4a8f4759 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -82,6 +82,7 @@ class _HeaderControlState extends State { /// 设置面板 void showSettingSheet() { + // Scaffold.of(context).openDrawer(); showModalBottomSheet( elevation: 0, context: context, @@ -158,7 +159,7 @@ class _HeaderControlState extends State { dense: true, leading: const Icon(Icons.hourglass_top_outlined, size: 20), - title: const Text('定时关闭(测试)', style: titleStyle), + title: const Text('定时关闭', style: titleStyle), ), ListTile( onTap: () => {Get.back(), showSetVideoQa()}, diff --git a/lib/pages/video/detail/widgets/right_drawer.dart b/lib/pages/video/detail/widgets/right_drawer.dart new file mode 100644 index 00000000..ca0d34ef --- /dev/null +++ b/lib/pages/video/detail/widgets/right_drawer.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class RightDrawer extends StatefulWidget { + const RightDrawer({super.key}); + + @override + State createState() => _RightDrawerState(); +} + +class _RightDrawerState extends State { + @override + Widget build(BuildContext context) { + return Drawer( + shadowColor: Colors.transparent, + elevation: 0, + backgroundColor: + Theme.of(context).colorScheme.surface.withOpacity(0.8)); + } +} From c2a4d80c79c9a2824c13505cc559035bb9d8d046 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 6 Apr 2024 21:32:29 +0800 Subject: [PATCH 40/71] =?UTF-8?q?feat:=20=E5=85=A8=E5=B1=8F=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E5=90=88=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/pages_bottom_sheet.dart | 103 ++++++++++-------- .../bangumi/introduction/controller.dart | 29 +++++ .../video/detail/introduction/controller.dart | 49 ++++++++- lib/pages/video/detail/introduction/view.dart | 9 +- .../introduction/widgets/page_panel.dart | 1 + .../introduction/widgets/season_panel.dart | 18 ++- lib/pages/video/detail/view.dart | 18 ++- .../pl_player/models/bottom_control_type.dart | 1 + lib/plugin/pl_player/view.dart | 20 ++++ lib/utils/drawer.dart | 39 +++++++ 10 files changed, 222 insertions(+), 65 deletions(-) create mode 100644 lib/utils/drawer.dart diff --git a/lib/common/pages_bottom_sheet.dart b/lib/common/pages_bottom_sheet.dart index b31ec4b1..c64b58b6 100644 --- a/lib/common/pages_bottom_sheet.dart +++ b/lib/common/pages_bottom_sheet.dart @@ -11,6 +11,7 @@ class EpisodeBottomSheet { final Function changeFucCall; final int? cid; final double? sheetHeight; + bool isFullScreen = false; EpisodeBottomSheet({ required this.episodes, @@ -20,6 +21,7 @@ class EpisodeBottomSheet { required this.changeFucCall, this.cid, this.sheetHeight, + this.isFullScreen = false, }); Widget buildEpisodeListItem( @@ -74,60 +76,69 @@ class EpisodeBottomSheet { '合集(${episodes.length})', style: Theme.of(context).textTheme.titleMedium, ), - actions: [ - IconButton( - icon: const Icon(Icons.close, size: 20), - onPressed: () => Navigator.pop(context), - ), - const SizedBox(width: 14), - ], + actions: !isFullScreen + ? [ + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () => Navigator.pop(context), + ), + const SizedBox(width: 14), + ] + : null, ); } + Widget buildShowContent(BuildContext context) { + final ItemScrollController itemScrollController = ItemScrollController(); + int currentIndex = episodes.indexWhere((dynamic e) => e.cid == currentCid); + return StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + itemScrollController.jumpTo(index: currentIndex); + }); + return Container( + height: sheetHeight, + color: Theme.of(context).colorScheme.background, + child: Column( + children: [ + buildTitle(), + Expanded( + child: Material( + child: PageStorage( + bucket: PageStorageBucket(), + child: ScrollablePositionedList.builder( + itemScrollController: itemScrollController, + itemCount: episodes.length + 1, + itemBuilder: (BuildContext context, int index) { + bool isLastItem = index == episodes.length; + bool isCurrentIndex = currentIndex == index; + return isLastItem + ? SizedBox( + height: + MediaQuery.of(context).padding.bottom + 20, + ) + : buildEpisodeListItem( + episodes[index], + index, + isCurrentIndex, + ); + }, + ), + ), + ), + ), + ], + ), + ); + }); + } + /// The [BuildContext] of the widget that calls the bottom sheet. PersistentBottomSheetController show(BuildContext context) { - final ItemScrollController itemScrollController = ItemScrollController(); - int currentIndex = episodes.indexWhere((dynamic e) => e.cid == currentCid); final PersistentBottomSheetController btmSheetCtr = showBottomSheet( context: context, builder: (BuildContext context) { - return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - WidgetsBinding.instance.addPostFrameCallback((_) { - itemScrollController.jumpTo(index: currentIndex); - }); - return Container( - height: sheetHeight, - color: Theme.of(context).colorScheme.background, - child: Column( - children: [ - buildTitle(), - Expanded( - child: Material( - child: ScrollablePositionedList.builder( - itemScrollController: itemScrollController, - itemCount: episodes.length + 1, - itemBuilder: (BuildContext context, int index) { - bool isLastItem = index == episodes.length; - bool isCurrentIndex = currentIndex == index; - return isLastItem - ? SizedBox( - height: - MediaQuery.of(context).padding.bottom + 20, - ) - : buildEpisodeListItem( - episodes[index], - index, - isCurrentIndex, - ); - }, - ), - ), - ), - ], - ), - ); - }); + return buildShowContent(context); }, ); return btmSheetCtr; diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index 12f0c053..63eadacf 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -15,6 +15,10 @@ import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:share_plus/share_plus.dart'; +import '../../../common/pages_bottom_sheet.dart'; +import '../../../models/common/video_episode_type.dart'; +import '../../../utils/drawer.dart'; + class BangumiIntroController extends GetxController { // 视频bvid String bvid = Get.parameters['bvid']!; @@ -291,4 +295,29 @@ class BangumiIntroController extends GetxController { int aid = episodes[nextIndex].aid!; changeSeasonOrbangu(bvid, cid, aid); } + + // 播放器底栏 选集 回调 + void showEposideHandler() { + late List episodes = bangumiDetail.value.episodes!; + VideoEpidoesType dataType = VideoEpidoesType.bangumiEpisode; + if (episodes.isEmpty) { + return; + } + VideoDetailController videoDetailCtr = + Get.find(tag: Get.arguments['heroTag']); + DrawerUtils.showRightDialog( + child: EpisodeBottomSheet( + episodes: episodes, + currentCid: videoDetailCtr.cid.value, + dataType: dataType, + context: Get.context!, + sheetHeight: Get.size.height, + isFullScreen: true, + changeFucCall: (item, index) { + changeSeasonOrbangu(item.bvid, item.cid, item.aid); + SmartDialog.dismiss(); + }, + ).buildShowContent(Get.context!), + ); + } } diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 241605ab..d81bda00 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -18,6 +18,9 @@ import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:share_plus/share_plus.dart'; +import '../../../../common/pages_bottom_sheet.dart'; +import '../../../../models/common/video_episode_type.dart'; +import '../../../../utils/drawer.dart'; import '../related/index.dart'; import 'widgets/group_panel.dart'; @@ -54,7 +57,7 @@ class VideoIntroController extends GetxController { bool isPaused = false; String heroTag = ''; late ModelResult modelResult; - late PersistentBottomSheetController? bottomSheetController; + PersistentBottomSheetController? bottomSheetController; @override void onInit() { @@ -562,4 +565,48 @@ class VideoIntroController extends GetxController { hiddenEpisodeBottomSheet() { bottomSheetController?.close(); } + + // 播放器底栏 选集 回调 + void showEposideHandler() { + late List episodes; + VideoEpidoesType dataType = VideoEpidoesType.videoEpisode; + if (videoDetail.value.ugcSeason != null) { + dataType = VideoEpidoesType.videoEpisode; + final List sections = videoDetail.value.ugcSeason!.sections!; + for (int i = 0; i < sections.length; i++) { + final List episodesList = sections[i].episodes!; + for (int j = 0; j < episodesList.length; j++) { + if (episodesList[j].cid == lastPlayCid.value) { + episodes = episodesList; + continue; + } + } + } + } + if (videoDetail.value.pages != null && + videoDetail.value.pages!.length > 1) { + dataType = VideoEpidoesType.videoPart; + episodes = videoDetail.value.pages!; + } + + DrawerUtils.showRightDialog( + child: EpisodeBottomSheet( + episodes: episodes, + currentCid: lastPlayCid.value, + dataType: dataType, + context: Get.context!, + sheetHeight: Get.size.height, + isFullScreen: true, + changeFucCall: (item, index) { + if (dataType == VideoEpidoesType.videoEpisode) { + changeSeasonOrbangu(IdUtils.av2bv(item.aid), item.cid, item.aid); + } + if (dataType == VideoEpidoesType.videoPart) { + changeSeasonOrbangu(bvid, item.cid, null); + } + SmartDialog.dismiss(); + }, + ).buildShowContent(Get.context!), + ); + } } diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 608beec8..70fa578d 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -373,7 +373,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { /// 点赞收藏转发 actionGrid(context, videoIntroController), - // 合集 + // 合集 videoPart 简洁 if (widget.videoDetail!.ugcSeason != null) ...[ Obx( () => SeasonPanel( @@ -383,11 +383,16 @@ class _VideoInfoState extends State with TickerProviderStateMixin { : widget.videoDetail!.pages!.first.cid, sheetHeight: sheetHeight, changeFuc: (bvid, cid, aid) => - videoIntroController.changeSeasonOrbangu(bvid, cid, aid), + videoIntroController.changeSeasonOrbangu( + bvid, + cid, + aid, + ), videoIntroCtr: videoIntroController, ), ) ], + // 合集 videoEpisode if (widget.videoDetail!.pages != null && widget.videoDetail!.pages!.length > 1) ...[ Obx( diff --git a/lib/pages/video/detail/introduction/widgets/page_panel.dart b/lib/pages/video/detail/introduction/widgets/page_panel.dart index 730a6105..fc999ba8 100644 --- a/lib/pages/video/detail/introduction/widgets/page_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/page_panel.dart @@ -60,6 +60,7 @@ class _PagesPanelState extends State { } void changeFucCall(item, i) async { + print('pages changeFucCall'); widget.changeFuc?.call(item.cid); currentIndex.value = i; _bottomSheetController?.close(); diff --git a/lib/pages/video/detail/introduction/widgets/season_panel.dart b/lib/pages/video/detail/introduction/widgets/season_panel.dart index cd8bc954..745c081d 100644 --- a/lib/pages/video/detail/introduction/widgets/season_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/season_panel.dart @@ -30,7 +30,7 @@ class SeasonPanel extends StatefulWidget { class _SeasonPanelState extends State { late List episodes; late int cid; - late int currentIndex; + late RxInt currentIndex = (-1).obs; final String heroTag = Get.arguments['heroTag']; late VideoDetailController _videoDetailController; final ItemScrollController itemScrollController = ItemScrollController(); @@ -57,11 +57,10 @@ class _SeasonPanelState extends State { } /// 取对应 season_id 的 episodes - currentIndex = episodes.indexWhere((EpisodeItem e) => e.cid == cid); + currentIndex.value = episodes.indexWhere((EpisodeItem e) => e.cid == cid); _videoDetailController.cid.listen((int p0) { cid = p0; - setState(() {}); - currentIndex = episodes.indexWhere((EpisodeItem e) => e.cid == cid); + currentIndex.value = episodes.indexWhere((EpisodeItem e) => e.cid == cid); }); } @@ -71,9 +70,8 @@ class _SeasonPanelState extends State { item.cid, item.aid, ); - currentIndex = i; + currentIndex.value = i; _bottomSheetController?.close(); - setState(() {}); } Widget buildEpisodeListItem( @@ -148,10 +146,10 @@ class _SeasonPanelState extends State { height: 12, ), const SizedBox(width: 10), - Text( - '${currentIndex + 1}/${episodes.length}', - style: Theme.of(context).textTheme.labelMedium, - ), + Obx(() => Text( + '${currentIndex.value + 1}/${episodes.length}', + style: Theme.of(context).textTheme.labelMedium, + )), const SizedBox(width: 6), const Icon( Icons.arrow_forward_ios_outlined, diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index ebbaeec9..7cbc7fed 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -178,6 +178,9 @@ class _VideoDetailPageState extends State if (isFullScreen) { vdCtr.hiddenReplyReplyPanel(); videoIntroController.hiddenEpisodeBottomSheet(); + vdCtr.bottomList.insert(3, BottomControlType.episode); + } else { + vdCtr.bottomList.removeAt(3); } }); } @@ -294,17 +297,20 @@ class _VideoDetailPageState extends State () { return !vdCtr.autoPlay.value ? const SizedBox() - : PLVideoPlayer( - controller: plPlayerController!, - headerControl: vdCtr.headerControl, - danmuWidget: Obx( - () => PlDanmaku( + : Obx( + () => PLVideoPlayer( + controller: plPlayerController!, + headerControl: vdCtr.headerControl, + danmuWidget: PlDanmaku( key: Key(vdCtr.danmakuCid.value.toString()), cid: vdCtr.danmakuCid.value, playerController: plPlayerController!, ), + bottomList: vdCtr.bottomList, + showEposideCb: () => vdCtr.videoType == SearchType.video + ? videoIntroController.showEposideHandler() + : bangumiIntroController.showEposideHandler(), ), - bottomList: vdCtr.bottomList, ); }, ); diff --git a/lib/plugin/pl_player/models/bottom_control_type.dart b/lib/plugin/pl_player/models/bottom_control_type.dart index 739e1d38..d724c5de 100644 --- a/lib/plugin/pl_player/models/bottom_control_type.dart +++ b/lib/plugin/pl_player/models/bottom_control_type.dart @@ -4,6 +4,7 @@ enum BottomControlType { next, time, space, + episode, fit, speed, fullscreen, diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 0e411f2e..6a5f22ec 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -37,6 +37,7 @@ class PLVideoPlayer extends StatefulWidget { this.bottomList, this.customWidget, this.customWidgets, + this.showEposideCb, super.key, }); @@ -49,6 +50,7 @@ class PLVideoPlayer extends StatefulWidget { final Widget? customWidget; final List? customWidgets; + final Function? showEposideCb; @override State createState() => _PLVideoPlayerState(); @@ -267,6 +269,24 @@ class _PLVideoPlayerState extends State /// 空白占位 BottomControlType.space: const Spacer(), + /// 选集 + BottomControlType.episode: SizedBox( + height: 30, + width: 30, + child: TextButton( + onPressed: () { + widget.showEposideCb?.call(); + }, + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + child: const Text( + '选集', + style: TextStyle(color: Colors.white, fontSize: 13), + ), + ), + ), + /// 画面比例 BottomControlType.fit: SizedBox( height: 30, diff --git a/lib/utils/drawer.dart b/lib/utils/drawer.dart new file mode 100644 index 00000000..f4aa17f8 --- /dev/null +++ b/lib/utils/drawer.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; + +class DrawerUtils { + static void showRightDialog({ + required Widget child, + double width = 400, + bool useSystem = false, + }) { + SmartDialog.show( + alignment: Alignment.topRight, + animationBuilder: (controller, child, animationParam) { + return SlideTransition( + position: Tween( + begin: const Offset(1, 0), + end: Offset.zero, + ).animate(controller.view), + child: child, + ); + }, + useSystem: useSystem, + maskColor: Colors.black.withOpacity(0.5), + animationTime: const Duration(milliseconds: 200), + builder: (context) => Container( + width: width, + color: Theme.of(context).scaffoldBackgroundColor, + child: SafeArea( + left: false, + right: false, + bottom: false, + child: MediaQuery( + data: const MediaQueryData(padding: EdgeInsets.zero), + child: child, + ), + ), + ), + ); + } +} From 46c975bbbb5b5b53dd5554617c79de0f823f2b75 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 6 Apr 2024 21:57:57 +0800 Subject: [PATCH 41/71] =?UTF-8?q?mod:=20=E5=90=88=E9=9B=86=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E5=B1=95=E7=A4=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/view.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 7cbc7fed..822d0a45 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -178,9 +178,15 @@ class _VideoDetailPageState extends State if (isFullScreen) { vdCtr.hiddenReplyReplyPanel(); videoIntroController.hiddenEpisodeBottomSheet(); - vdCtr.bottomList.insert(3, BottomControlType.episode); + if (videoIntroController.videoDetail.value.ugcSeason != null || + (videoIntroController.videoDetail.value.pages != null && + videoIntroController.videoDetail.value.pages!.length > 1)) { + vdCtr.bottomList.insert(3, BottomControlType.episode); + } } else { - vdCtr.bottomList.removeAt(3); + if (vdCtr.bottomList.contains(BottomControlType.episode)) { + vdCtr.bottomList.removeAt(3); + } } }); } From 9c12c2179623091028d14bc2823b6e47eb577d1e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 7 Apr 2024 23:13:51 +0800 Subject: [PATCH 42/71] =?UTF-8?q?mod:=20navigation=20Bar=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/setting/pages/navigation_bar_set.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/setting/pages/navigation_bar_set.dart b/lib/pages/setting/pages/navigation_bar_set.dart index 8e1771e3..09e92bc3 100644 --- a/lib/pages/setting/pages/navigation_bar_set.dart +++ b/lib/pages/setting/pages/navigation_bar_set.dart @@ -74,7 +74,7 @@ class _NavigationbarSetPageState extends State { }, title: Text(defaultNavTabs[i]['label']), secondary: const Icon(Icons.drag_indicator_rounded), - enabled: defaultNavTabs[i]['id'] != 3, + enabled: defaultNavTabs[i]['id'] != 0, ) ] ]; From 9ee0f6526c8b7aecb39c9b6df4e7c4d77e25c03b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 7 Apr 2024 23:48:27 +0800 Subject: [PATCH 43/71] =?UTF-8?q?mod:=20=E8=AE=A2=E9=98=85=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E7=B1=BB=E5=9E=8B=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 7 +++- lib/http/user.dart | 33 +++++++++++++++- lib/pages/subscription_detail/controller.dart | 21 ++++++---- lib/pages/subscription_detail/view.dart | 39 +++++++++---------- 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index fa4cc1e8..b6975c4b 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -490,8 +490,11 @@ class Api { /// 我的订阅 static const userSubFolder = '/x/v3/fav/folder/collected/list'; - /// 我的订阅详情 - static const userSubFolderDetail = '/x/space/fav/season/list'; + /// 我的订阅详情 type 21 + static const userSeasonList = '/x/space/fav/season/list'; + + /// 我的订阅详情 type 11 + static const userResourceList = '/x/v3/fav/resource/list'; /// 表情 static const emojiList = '/x/emote/user/panel/web'; diff --git a/lib/http/user.dart b/lib/http/user.dart index bae61720..fea0a22e 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -330,12 +330,12 @@ class UserHttp { } } - static Future userSubFolderDetail({ + static Future userSeasonList({ required int seasonId, required int pn, required int ps, }) async { - var res = await Request().get(Api.userSubFolderDetail, data: { + var res = await Request().get(Api.userSeasonList, data: { 'season_id': seasonId, 'ps': ps, 'pn': pn, @@ -350,6 +350,35 @@ class UserHttp { } } + static Future userResourceList({ + required int seasonId, + required int pn, + required int ps, + }) async { + var res = await Request().get(Api.userResourceList, data: { + 'media_id': seasonId, + 'ps': ps, + 'pn': pn, + 'keyword': '', + 'order': 'mtime', + 'type': 0, + 'tid': 0, + 'platform': 'web', + }); + if (res.data['code'] == 0) { + try { + return { + 'status': true, + 'data': SubDetailModelData.fromJson(res.data['data']) + }; + } catch (err) { + return {'status': false, 'msg': err}; + } + } else { + return {'status': false, 'msg': res.data['message']}; + } + } + // 取消订阅 static Future cancelSub({required int seasonId}) async { var res = await Request().post( diff --git a/lib/pages/subscription_detail/controller.dart b/lib/pages/subscription_detail/controller.dart index 6ecb894e..4245df2c 100644 --- a/lib/pages/subscription_detail/controller.dart +++ b/lib/pages/subscription_detail/controller.dart @@ -6,7 +6,6 @@ import '../../models/user/sub_folder.dart'; class SubDetailController extends GetxController { late SubFolderItemData item; - late int seasonId; late String heroTag; int currentPage = 1; @@ -26,17 +25,23 @@ class SubDetailController extends GetxController { super.onInit(); } - Future queryUserSubFolderDetail({type = 'init'}) async { + Future queryUserSeasonList({type = 'init'}) async { if (type == 'onLoad' && subList.length >= mediaCount) { loadingText.value = '没有更多了'; return; } isLoadingMore = true; - var res = await UserHttp.userSubFolderDetail( - seasonId: seasonId, - ps: 20, - pn: currentPage, - ); + var res = type == 21 + ? await UserHttp.userSeasonList( + seasonId: seasonId, + ps: 20, + pn: currentPage, + ) + : await UserHttp.userResourceList( + seasonId: seasonId, + ps: 20, + pn: currentPage, + ); if (res['status']) { subInfo.value = res['data'].info; if (currentPage == 1 && type == 'init') { @@ -55,6 +60,6 @@ class SubDetailController extends GetxController { } onLoad() { - queryUserSubFolderDetail(type: 'onLoad'); + queryUserSeasonList(type: 'onLoad'); } } diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index d56125cd..93e0abbb 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -26,13 +26,11 @@ class _SubDetailPageState extends State { Get.put(SubDetailController()); late StreamController titleStreamC; // a late Future _futureBuilderFuture; - late String seasonId; @override void initState() { super.initState(); - seasonId = Get.parameters['seasonId']!; - _futureBuilderFuture = _subDetailController.queryUserSubFolderDetail(); + _futureBuilderFuture = _subDetailController.queryUserSeasonList(); titleStreamC = StreamController(); _controller.addListener( () { @@ -161,15 +159,18 @@ class _SubDetailPageState extends State { ), ), const SizedBox(height: 4), - Text( - '${Utils.numFormat(_subDetailController.item.viewCount)}次播放', - style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - color: Theme.of(context).colorScheme.outline), - ), + Obx( + () => Text( + '${Utils.numFormat(_subDetailController.subInfo.value.cntInfo?['play'])}次播放', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .labelSmall! + .fontSize, + color: + Theme.of(context).colorScheme.outline), + ), + ) ], ), ), @@ -182,14 +183,12 @@ class _SubDetailPageState extends State { SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.only(top: 15, bottom: 8, left: 14), - child: Obx( - () => Text( - '共${_subDetailController.subList.length}条视频', - style: TextStyle( - fontSize: - Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline, - letterSpacing: 1), + child: Text( + '共${_subDetailController.item.mediaCount}条视频', + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.outline, + letterSpacing: 1, ), ), ), From 48f0b59701011e478b2d3f8efea17459ae865c0c Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 8 Apr 2024 23:33:43 +0800 Subject: [PATCH 44/71] =?UTF-8?q?mod:=20=E7=9B=B8=E5=86=8C=E3=80=81?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E6=9D=83=E9=99=90=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utils/download.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/utils/download.dart b/lib/utils/download.dart index a9c56ec0..e27335d0 100644 --- a/lib/utils/download.dart +++ b/lib/utils/download.dart @@ -11,8 +11,7 @@ class DownloadUtils { static Future requestStoragePer() async { await Permission.storage.request(); PermissionStatus status = await Permission.storage.status; - if (status == PermissionStatus.denied || - status == PermissionStatus.permanentlyDenied) { + if (status == PermissionStatus.denied) { SmartDialog.show( useSystem: true, animationType: SmartAnimationType.centerFade_otherSlide, @@ -41,8 +40,7 @@ class DownloadUtils { static Future requestPhotoPer() async { await Permission.photos.request(); PermissionStatus status = await Permission.photos.status; - if (status == PermissionStatus.denied || - status == PermissionStatus.permanentlyDenied) { + if (status == PermissionStatus.denied) { SmartDialog.show( useSystem: true, animationType: SmartAnimationType.centerFade_otherSlide, From 2bd97f800efb4e88dda04e307739cefb2dcc9b58 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 8 Apr 2024 23:43:25 +0800 Subject: [PATCH 45/71] Update beta_ci.yml --- .github/workflows/beta_ci.yml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.github/workflows/beta_ci.yml b/.github/workflows/beta_ci.yml index e839aca1..80fe8afb 100644 --- a/.github/workflows/beta_ci.yml +++ b/.github/workflows/beta_ci.yml @@ -1,17 +1,5 @@ name: Pilipala Beta -on: - workflow_dispatch: - push: - branches: - - "main" - paths-ignore: - - "**.md" - - "**.txt" - - ".github/**" - - ".idea/**" - - "!.github/workflows/**" - jobs: update_version: name: Read and update version From b9e93dabe62884251fd617719e3b647406b97097 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 8 Apr 2024 23:45:54 +0800 Subject: [PATCH 46/71] Update beta_ci.yml --- .github/workflows/beta_ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/beta_ci.yml b/.github/workflows/beta_ci.yml index 80fe8afb..40f3f042 100644 --- a/.github/workflows/beta_ci.yml +++ b/.github/workflows/beta_ci.yml @@ -1,5 +1,18 @@ name: Pilipala Beta +on: + workflow_dispatch: + push: + branches: + - "never" + paths-ignore: + - "**.md" + - "**.txt" + - ".github/**" + - ".idea/**" + - "!.github/workflows/**" + + jobs: update_version: name: Read and update version From 84f83c260ab092e9040093bf894b9d9d035192c9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 8 Apr 2024 23:55:29 +0800 Subject: [PATCH 47/71] =?UTF-8?q?feat:=20=E7=AE=80=E5=8D=95=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E6=8A=95=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/dlna/index.dart | 111 ++++++++++++++++++ .../video/detail/widgets/header_control.dart | 17 +++ pubspec.lock | 8 ++ pubspec.yaml | 2 + 4 files changed, 138 insertions(+) create mode 100644 lib/pages/dlna/index.dart diff --git a/lib/pages/dlna/index.dart b/lib/pages/dlna/index.dart new file mode 100644 index 00000000..3ec5965b --- /dev/null +++ b/lib/pages/dlna/index.dart @@ -0,0 +1,111 @@ +import 'dart:async'; + +import 'package:dlna_dart/dlna.dart'; +import 'package:flutter/material.dart'; + +class LiveDlnaPage extends StatefulWidget { + final String datasource; + + const LiveDlnaPage({Key? key, required this.datasource}) : super(key: key); + + @override + State createState() => _LiveDlnaPageState(); +} + +class _LiveDlnaPageState extends State { + final Map _deviceList = {}; + final DLNAManager searcher = DLNAManager(); + late final Timer stopSearchTimer; + String selectDeviceKey = ''; + bool isSearching = true; + + DLNADevice? get device => _deviceList[selectDeviceKey]; + + @override + void initState() { + stopSearchTimer = Timer(const Duration(seconds: 20), () { + setState(() => isSearching = false); + searcher.stop(); + }); + searcher.stop(); + startSearch(); + super.initState(); + } + + @override + void dispose() { + super.dispose(); + searcher.stop(); + stopSearchTimer.cancel(); + } + + void startSearch() async { + // clear old devices + isSearching = true; + selectDeviceKey = ''; + _deviceList.clear(); + setState(() {}); + // start search server + final m = await searcher.start(); + m.devices.stream.listen((deviceList) { + deviceList.forEach((key, value) { + _deviceList[key] = value; + }); + setState(() {}); + }); + // close the server, the closed server can be start by call searcher.start() + } + + void selectDevice(String key) { + if (selectDeviceKey.isNotEmpty) device?.pause(); + + selectDeviceKey = key; + device?.setUrl(widget.datasource); + device?.play(); + setState(() {}); + } + + @override + Widget build(BuildContext context) { + Widget cur; + if (isSearching && _deviceList.isEmpty) { + cur = const Center(child: CircularProgressIndicator()); + } else if (_deviceList.isEmpty) { + cur = Center( + child: Text( + '没有找到设备', + style: Theme.of(context).textTheme.bodyLarge, + ), + ); + } else { + cur = ListView( + children: _deviceList.keys + .map((key) => ListTile( + contentPadding: const EdgeInsets.all(2), + title: Text(_deviceList[key]!.info.friendlyName), + subtitle: Text(key), + onTap: () => selectDevice(key), + )) + .toList(), + ); + } + + return AlertDialog( + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('查找设备'), + IconButton( + onPressed: startSearch, + icon: const Icon(Icons.refresh_rounded), + ), + ], + ), + content: SizedBox( + height: 200, + width: 200, + child: cur, + ), + ); + } +} diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 4a8f4759..7a12b0cf 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -11,6 +11,7 @@ import 'package:ns_danmaku/ns_danmaku.dart'; import 'package:pilipala/http/user.dart'; import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/models/video/play/url.dart'; +import 'package:pilipala/pages/dlna/index.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; @@ -1209,6 +1210,22 @@ class _HeaderControlState extends State { // ), // fuc: () => _.screenshot(), // ), + ComBtn( + icon: const Icon( + Icons.cast, + size: 19, + color: Colors.white, + ), + fuc: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return LiveDlnaPage( + datasource: widget.videoDetailCtr!.videoUrl); + }, + ); + }, + ), if (isFullScreen.value) ...[ SizedBox( width: 56, diff --git a/pubspec.lock b/pubspec.lock index 84556c06..a64c85c0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -409,6 +409,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.2" + dlna_dart: + dependency: "direct main" + description: + name: dlna_dart + sha256: ae07c1c53077bbf58756fa589f936968719b0085441981d33e74f82f89d1d281 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.8" dynamic_color: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index ba5976eb..27b8b720 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -144,6 +144,8 @@ dependencies: disable_battery_optimization: ^1.1.1 # 展开/收起 expandable: ^5.0.1 + # 投屏 + dlna_dart: ^0.0.8 dev_dependencies: flutter_test: From ca37d45eb94007be0fa666ab993fcf3a0049fe7b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 9 Apr 2024 23:22:57 +0800 Subject: [PATCH 48/71] =?UTF-8?q?fix:=20=E5=85=A8=E5=B1=8F=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=90=88=E9=9B=86=E8=A7=86=E9=A2=91=E6=A0=87=E9=A2=98?= =?UTF-8?q?=E6=9C=AA=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video/detail/widgets/header_control.dart | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 7a12b0cf..e6a324cb 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -83,7 +83,6 @@ class _HeaderControlState extends State { /// 设置面板 void showSettingSheet() { - // Scaffold.of(context).openDrawer(); showModalBottomSheet( elevation: 0, context: context, @@ -732,9 +731,12 @@ class _HeaderControlState extends State { margin: const EdgeInsets.all(12), child: Column( children: [ - SizedBox( - height: 45, - child: Center(child: Text('选择解码格式', style: titleStyle))), + const SizedBox( + height: 45, + child: Center( + child: Text('选择解码格式', style: titleStyle), + ), + ), Expanded( child: Material( child: ListView( @@ -1079,9 +1081,12 @@ class _HeaderControlState extends State { margin: const EdgeInsets.all(12), child: Column( children: [ - SizedBox( - height: 45, - child: Center(child: Text('选择播放顺序', style: titleStyle))), + const SizedBox( + height: 45, + child: Center( + child: Text('选择播放顺序', style: titleStyle), + ), + ), Expanded( child: Material( child: ListView( @@ -1166,11 +1171,13 @@ class _HeaderControlState extends State { children: [ ConstrainedBox( constraints: const BoxConstraints(maxWidth: 200), - child: Text( - videoIntroController.videoDetail.value.title ?? '', - style: const TextStyle( - color: Colors.white, - fontSize: 16, + child: Obx( + () => Text( + videoIntroController.videoDetail.value.title ?? '', + style: const TextStyle( + color: Colors.white, + fontSize: 16, + ), ), ), ), From 04bfc294525d47511ea9c005fbcfa2c9addae142 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 9 Apr 2024 23:33:13 +0800 Subject: [PATCH 49/71] =?UTF-8?q?feat:=20=E7=9B=B4=E6=92=AD=E9=97=B4?= =?UTF-8?q?=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/live_room/view.dart | 5 ++++ .../live_room/widgets/bottom_control.dart | 28 +++++++------------ 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 1e5c29c5..37981b1d 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -62,6 +62,11 @@ class _LiveRoomPageState extends State { controller: plPlayerController, liveRoomCtr: _liveRoomController, floating: floating, + onRefresh: () { + setState(() { + _futureBuilderFuture = _liveRoomController.queryLiveInfo(); + }); + }, ), ); } else { diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index 3c908d71..e5a9d6c9 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -14,10 +14,12 @@ class BottomControl extends StatefulWidget implements PreferredSizeWidget { final PlPlayerController? controller; final LiveRoomController? liveRoomCtr; final Floating? floating; + final Function? onRefresh; const BottomControl({ this.controller, this.liveRoomCtr, this.floating, + this.onRefresh, Key? key, }) : super(key: key); @@ -61,6 +63,14 @@ class _BottomControlState extends State { // ), // fuc: () => Get.back(), // ), + ComBtn( + icon: const Icon( + Icons.refresh_outlined, + size: 18, + color: Colors.white, + ), + fuc: widget.onRefresh, + ), const Spacer(), // ComBtn( // icon: const Icon( @@ -150,21 +160,3 @@ class _BottomControlState extends State { ); } } - -class MSliderTrackShape extends RoundedRectSliderTrackShape { - @override - Rect getPreferredRect({ - required RenderBox parentBox, - Offset offset = Offset.zero, - SliderThemeData? sliderTheme, - bool isEnabled = false, - bool isDiscrete = false, - }) { - const double trackHeight = 3; - final double trackLeft = offset.dx; - final double trackTop = - offset.dy + (parentBox.size.height - trackHeight) / 2 + 4; - final double trackWidth = parentBox.size.width; - return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight); - } -} From 9f9471d7f9961332077b98380c5f8afa096e94cc Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 9 Apr 2024 23:42:09 +0800 Subject: [PATCH 50/71] =?UTF-8?q?fix:=20up=E4=B8=BB=E9=A1=B5=E4=B8=93?= =?UTF-8?q?=E6=A0=8F=E8=A7=86=E9=A2=91=E6=97=B6=E9=95=BF=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/member_seasons/widgets/item.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pages/member_seasons/widgets/item.dart b/lib/pages/member_seasons/widgets/item.dart index 6398c5eb..4df74b70 100644 --- a/lib/pages/member_seasons/widgets/item.dart +++ b/lib/pages/member_seasons/widgets/item.dart @@ -25,7 +25,7 @@ class MemberSeasonsItem extends StatelessWidget { child: InkWell( onTap: () async { int cid = - await SearchHttp.ab2c(aid: seasonItem.aid, bvid: seasonItem.bvid); + await SearchHttp.ab2c(aid: seasonItem.aid, bvid: seasonItem.bvid); Get.toNamed('/video?bvid=${seasonItem.bvid}&cid=$cid', arguments: {'videoItem': seasonItem, 'heroTag': heroTag}); }, @@ -51,8 +51,7 @@ class MemberSeasonsItem extends StatelessWidget { bottom: 6, right: 6, type: 'gray', - text: Utils.CustomStamp_str( - timestamp: seasonItem.pubdate, date: 'YY-MM-DD'), + text: Utils.timeFormat(seasonItem.duration), ) ], ); From 3f16a36bacc6d140ed6355ba95e9ad1e3f1c4de4 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 10 Apr 2024 23:34:59 +0800 Subject: [PATCH 51/71] =?UTF-8?q?fix:=20=E6=A5=BC=E4=B8=AD=E6=A5=BC?= =?UTF-8?q?=E8=AF=84=E8=AE=BA=E8=AF=B7=E6=B1=82=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/reply_reply/view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index e8754a31..344ca1b1 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -140,8 +140,8 @@ class _VideoReplyReplyPanelState extends State { future: _futureBuilderFuture, builder: (BuildContext context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { - final Map data = snapshot.data as Map; - if (data['status']) { + Map? data = snapshot.data; + if (data != null && data['status']) { // 请求成功 return Obx( () => SliverList( @@ -199,7 +199,7 @@ class _VideoReplyReplyPanelState extends State { } else { // 请求错误 return HttpError( - errMsg: data['msg'], + errMsg: data?['msg'] ?? '请求错误', fn: () => setState(() {}), ); } From 7fd23044313690d15b7b07586d251605c024191a Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 10 Apr 2024 23:52:21 +0800 Subject: [PATCH 52/71] =?UTF-8?q?fix:=20pip=E8=BF=9B=E5=85=A5=E6=97=B6appb?= =?UTF-8?q?arStream=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index ffa50476..a061a0e2 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -107,7 +107,7 @@ class _VideoDetailPageState extends State // 流 appbarStreamListen() { - appbarStream = StreamController(); + appbarStream = StreamController.broadcast(); _extendNestCtr.addListener( () { final double offset = _extendNestCtr.position.pixels; From 4b3dd3ca599793d74e76abd0e71f943b2fd0631a Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 11 Apr 2024 23:26:06 +0800 Subject: [PATCH 53/71] =?UTF-8?q?opt:=20navigationBar=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/main/view.dart | 130 +++++++++++++-------------- lib/pages/setting/style_setting.dart | 2 +- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index c551e690..e4e980af 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -127,81 +127,81 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { }, children: _mainController.pages, ), - bottomNavigationBar: StreamBuilder( - stream: _mainController.hideTabBar - ? _mainController.bottomBarStream.stream - : StreamController.broadcast().stream, - initialData: true, - builder: (context, AsyncSnapshot snapshot) { - return AnimatedSlide( - curve: Curves.easeInOutCubicEmphasized, - duration: const Duration(milliseconds: 500), - offset: Offset(0, snapshot.data ? 0 : 1), - child: Obx( - () => enableMYBar - ? NavigationBar( - onDestinationSelected: (value) => setIndex(value), - selectedIndex: _mainController.selectedIndex, - destinations: [ - ..._mainController.navigationBars.map((e) { - return NavigationDestination( - icon: Obx( - () => Badge( - label: - _mainController.dynamicBadgeType.value == + bottomNavigationBar: _mainController.navigationBars.length > 1 + ? StreamBuilder( + stream: _mainController.hideTabBar + ? _mainController.bottomBarStream.stream + : StreamController.broadcast().stream, + initialData: true, + builder: (context, AsyncSnapshot snapshot) { + return AnimatedSlide( + curve: Curves.easeInOutCubicEmphasized, + duration: const Duration(milliseconds: 500), + offset: Offset(0, snapshot.data ? 0 : 1), + child: enableMYBar + ? NavigationBar( + onDestinationSelected: (value) => setIndex(value), + selectedIndex: _mainController.selectedIndex, + destinations: [ + ..._mainController.navigationBars.map((e) { + return NavigationDestination( + icon: Obx( + () => Badge( + label: _mainController + .dynamicBadgeType.value == DynamicBadgeMode.number ? Text(e['count'].toString()) : null, - padding: - const EdgeInsets.fromLTRB(6, 0, 6, 0), - isLabelVisible: - _mainController.dynamicBadgeType.value != + padding: + const EdgeInsets.fromLTRB(6, 0, 6, 0), + isLabelVisible: _mainController + .dynamicBadgeType.value != DynamicBadgeMode.hidden && e['count'] > 0, - child: e['icon'], - ), - ), - selectedIcon: e['selectIcon'], - label: e['label'], - ); - }).toList(), - ], - ) - : BottomNavigationBar( - currentIndex: _mainController.selectedIndex, - onTap: (value) => setIndex(value), - iconSize: 16, - selectedFontSize: 12, - unselectedFontSize: 12, - items: [ - ..._mainController.navigationBars.map((e) { - return BottomNavigationBarItem( - icon: Obx( - () => Badge( - label: - _mainController.dynamicBadgeType.value == + child: e['icon'], + ), + ), + selectedIcon: e['selectIcon'], + label: e['label'], + ); + }).toList(), + ], + ) + : BottomNavigationBar( + currentIndex: _mainController.selectedIndex, + onTap: (value) => setIndex(value), + iconSize: 16, + selectedFontSize: 12, + unselectedFontSize: 12, + items: [ + ..._mainController.navigationBars.map((e) { + return BottomNavigationBarItem( + icon: Obx( + () => Badge( + label: _mainController + .dynamicBadgeType.value == DynamicBadgeMode.number ? Text(e['count'].toString()) : null, - padding: - const EdgeInsets.fromLTRB(6, 0, 6, 0), - isLabelVisible: - _mainController.dynamicBadgeType.value != + padding: + const EdgeInsets.fromLTRB(6, 0, 6, 0), + isLabelVisible: _mainController + .dynamicBadgeType.value != DynamicBadgeMode.hidden && e['count'] > 0, - child: e['icon'], - ), - ), - activeIcon: e['selectIcon'], - label: e['label'], - ); - }).toList(), - ], - ), - ), - ); - }, - ), + child: e['icon'], + ), + ), + activeIcon: e['selectIcon'], + label: e['label'], + ); + }).toList(), + ], + ), + ); + }, + ) + : null, ), ); } diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index d2403cff..364eabf0 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -287,7 +287,7 @@ class _StyleSettingState extends State { ListTile( dense: false, onTap: () => Get.toNamed('/navbarSetting'), - title: Text('navbar设置', style: titleStyle), + title: Text('底部导航栏设置', style: titleStyle), ), if (Platform.isAndroid) ListTile( From a74647eb61a36e1f0795f92593185c57c4e73bf6 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 11 Apr 2024 23:29:51 +0800 Subject: [PATCH 54/71] =?UTF-8?q?opt:=20=E9=BB=98=E8=AE=A4=E4=B8=8D?= =?UTF-8?q?=E6=94=B6=E8=B5=B7=E9=A1=B6=E6=A0=8F&=E5=BA=95=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/home/controller.dart | 2 +- lib/pages/main/controller.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/home/controller.dart b/lib/pages/home/controller.dart index fb85be0b..ca70e1c4 100644 --- a/lib/pages/home/controller.dart +++ b/lib/pages/home/controller.dart @@ -35,7 +35,7 @@ class HomeController extends GetxController with GetTickerProviderStateMixin { userLogin.value = userInfo != null; userFace.value = userInfo != null ? userInfo.face : ''; hideSearchBar = - setting.get(SettingBoxKey.hideSearchBar, defaultValue: true); + setting.get(SettingBoxKey.hideSearchBar, defaultValue: false); if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) { searchDefault(); } diff --git a/lib/pages/main/controller.dart b/lib/pages/main/controller.dart index f929a1aa..c2e5c322 100644 --- a/lib/pages/main/controller.dart +++ b/lib/pages/main/controller.dart @@ -33,7 +33,7 @@ class MainController extends GetxController { if (setting.get(SettingBoxKey.autoUpdate, defaultValue: false)) { Utils.checkUpdata(); } - hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: true); + hideTabBar = setting.get(SettingBoxKey.hideTabBar, defaultValue: false); var userInfo = userInfoCache.get('userInfoCache'); userLogin.value = userInfo != null; From 10435bb7b1fecff8552d5b5f523db10a2637da06 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 12 Apr 2024 00:01:32 +0800 Subject: [PATCH 55/71] =?UTF-8?q?mod:=20=E6=9C=80=E8=BF=91=E6=8A=95?= =?UTF-8?q?=E5=B8=81=E8=A7=86=E9=A2=91=E6=A0=87=E9=A2=98=E5=B7=A6=E5=AF=B9?= =?UTF-8?q?=E9=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/member_coin/widgets/item.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pages/member_coin/widgets/item.dart b/lib/pages/member_coin/widgets/item.dart index ea6e7ee1..de28585c 100644 --- a/lib/pages/member_coin/widgets/item.dart +++ b/lib/pages/member_coin/widgets/item.dart @@ -59,6 +59,7 @@ class MemberCoinsItem extends StatelessWidget { padding: const EdgeInsets.fromLTRB(5, 6, 0, 0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( coinItem.title!, From 1076c02a58173d4cdc25fbc85f7b03a9a2171557 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 12 Apr 2024 23:12:12 +0800 Subject: [PATCH 56/71] =?UTF-8?q?fix:=20android=2012=E6=9D=83=E9=99=90?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utils/download.dart | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/utils/download.dart b/lib/utils/download.dart index e27335d0..2aff8999 100644 --- a/lib/utils/download.dart +++ b/lib/utils/download.dart @@ -1,5 +1,7 @@ +import 'dart:io'; import 'dart:typed_data'; +import 'package:device_info_plus/device_info_plus.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -11,7 +13,8 @@ class DownloadUtils { static Future requestStoragePer() async { await Permission.storage.request(); PermissionStatus status = await Permission.storage.status; - if (status == PermissionStatus.denied) { + if (status == PermissionStatus.denied || + status == PermissionStatus.permanentlyDenied) { SmartDialog.show( useSystem: true, animationType: SmartAnimationType.centerFade_otherSlide, @@ -40,7 +43,8 @@ class DownloadUtils { static Future requestPhotoPer() async { await Permission.photos.request(); PermissionStatus status = await Permission.photos.status; - if (status == PermissionStatus.denied) { + if (status == PermissionStatus.denied || + status == PermissionStatus.permanentlyDenied) { SmartDialog.show( useSystem: true, animationType: SmartAnimationType.centerFade_otherSlide, @@ -68,9 +72,20 @@ class DownloadUtils { static Future downloadImg(String imgUrl, {String imgType = 'cover'}) async { try { - if (!await requestPhotoPer()) { + if (!Platform.isAndroid || !await requestPhotoPer()) { return false; } + final androidInfo = await DeviceInfoPlugin().androidInfo; + if (androidInfo.version.sdkInt <= 32) { + if (!await requestStoragePer()) { + return false; + } + } else { + if (!await requestPhotoPer()) { + return false; + } + } + SmartDialog.showLoading(msg: '保存中'); var response = await Dio() .get(imgUrl, options: Options(responseType: ResponseType.bytes)); From 297ad6a46d600bdfc664f54d44a3ccb9ab6ba2bd Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 01:41:24 +0800 Subject: [PATCH 57/71] =?UTF-8?q?opt:=20navBar=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 85 +++++++++++++++++++------------------- lib/pages/main/view.dart | 6 +-- lib/utils/global_data.dart | 6 +++ 3 files changed, 52 insertions(+), 45 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 44bb1dcd..c3f5814a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -20,6 +20,7 @@ import 'package:pilipala/services/disable_battery_opt.dart'; import 'package:pilipala/services/service_locator.dart'; import 'package:pilipala/utils/app_scheme.dart'; import 'package:pilipala/utils/data.dart'; +import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc. import 'package:pilipala/utils/recommend_filter.dart'; @@ -63,14 +64,8 @@ void main() async { }, ); - // 小白条、导航栏沉浸 - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - systemNavigationBarColor: Colors.transparent, - systemNavigationBarDividerColor: Colors.transparent, - statusBarColor: Colors.transparent, - )); Data.init(); + GlobalData(); PiliSchame.init(); DisableBatteryOpt(); }); @@ -133,45 +128,51 @@ class MyApp extends StatelessWidget { brightness: Brightness.dark, ); } + + final SnackBarThemeData snackBarThemeData = SnackBarThemeData( + actionTextColor: darkColorScheme.primary, + backgroundColor: darkColorScheme.secondaryContainer, + closeIconColor: darkColorScheme.secondary, + contentTextStyle: TextStyle(color: darkColorScheme.secondary), + elevation: 20, + ); + + ThemeData themeData = ThemeData( + // fontFamily: 'HarmonyOS', + colorScheme: currentThemeValue == ThemeType.dark + ? darkColorScheme + : lightColorScheme, + snackBarTheme: snackBarThemeData, + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.android: ZoomPageTransitionsBuilder( + allowEnterRouteSnapshotting: false, + ), + }, + ), + ); + + // 小白条、导航栏沉浸 + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( + systemNavigationBarColor: GlobalData().enableMYBar + ? themeData.colorScheme.surfaceVariant + : themeData.canvasColor, + systemNavigationBarDividerColor: GlobalData().enableMYBar + ? themeData.colorScheme.surfaceVariant + : themeData.canvasColor, + systemNavigationBarIconBrightness: currentThemeValue == ThemeType.dark + ? Brightness.light + : Brightness.dark, + statusBarColor: Colors.transparent, + )); + // 图片缓存 // PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20; return GetMaterialApp( title: 'PiLiPaLa', - theme: ThemeData( - // fontFamily: 'HarmonyOS', - colorScheme: currentThemeValue == ThemeType.dark - ? darkColorScheme - : lightColorScheme, - useMaterial3: true, - snackBarTheme: SnackBarThemeData( - actionTextColor: lightColorScheme.primary, - backgroundColor: lightColorScheme.secondaryContainer, - closeIconColor: lightColorScheme.secondary, - contentTextStyle: TextStyle(color: lightColorScheme.secondary), - elevation: 20, - ), - pageTransitionsTheme: const PageTransitionsTheme( - builders: { - TargetPlatform.android: ZoomPageTransitionsBuilder( - allowEnterRouteSnapshotting: false, - ), - }, - ), - ), - darkTheme: ThemeData( - // fontFamily: 'HarmonyOS', - colorScheme: currentThemeValue == ThemeType.light - ? lightColorScheme - : darkColorScheme, - useMaterial3: true, - snackBarTheme: SnackBarThemeData( - actionTextColor: darkColorScheme.primary, - backgroundColor: darkColorScheme.secondaryContainer, - closeIconColor: darkColorScheme.secondary, - contentTextStyle: TextStyle(color: darkColorScheme.secondary), - elevation: 20, - ), - ), + theme: themeData, + darkTheme: themeData, localizationsDelegates: const [ GlobalCupertinoLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index e4e980af..731134e9 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -10,6 +10,7 @@ import 'package:pilipala/pages/media/index.dart'; import 'package:pilipala/pages/rank/index.dart'; import 'package:pilipala/utils/event_bus.dart'; import 'package:pilipala/utils/feed_back.dart'; +import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/storage.dart'; import './controller.dart'; @@ -29,7 +30,6 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { int? _lastSelectTime; //上次点击时间 Box setting = GStrorage.setting; - late bool enableMYBar; @override void initState() { @@ -37,7 +37,6 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { _lastSelectTime = DateTime.now().millisecondsSinceEpoch; _mainController.pageController = PageController(initialPage: _mainController.selectedIndex); - enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true); } void setIndex(int value) async { @@ -138,7 +137,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { curve: Curves.easeInOutCubicEmphasized, duration: const Duration(milliseconds: 500), offset: Offset(0, snapshot.data ? 0 : 1), - child: enableMYBar + child: GlobalData().enableMYBar ? NavigationBar( onDestinationSelected: (value) => setIndex(value), selectedIndex: _mainController.selectedIndex, @@ -169,6 +168,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { ) : BottomNavigationBar( currentIndex: _mainController.selectedIndex, + type: BottomNavigationBarType.fixed, onTap: (value) => setIndex(value), iconSize: 16, selectedFontSize: 12, diff --git a/lib/utils/global_data.dart b/lib/utils/global_data.dart index ef3daf21..29791210 100644 --- a/lib/utils/global_data.dart +++ b/lib/utils/global_data.dart @@ -1,10 +1,16 @@ +import 'package:hive/hive.dart'; +import 'package:pilipala/utils/storage.dart'; import '../models/common/index.dart'; +Box setting = GStrorage.setting; + class GlobalData { int imgQuality = 10; FullScreenGestureMode fullScreenGestureMode = FullScreenGestureMode.values.last; bool enablePlayerControlAnimation = true; + final bool enableMYBar = + setting.get(SettingBoxKey.enableMYBar, defaultValue: true); // 私有构造函数 GlobalData._(); From ef6070aa8b1a6b52d840ce9e8cceb40d4ee4fd34 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 10:35:06 +0800 Subject: [PATCH 58/71] mod: systemNavBarColor --- lib/main.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c3f5814a..3996a5fd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -156,10 +156,10 @@ class MyApp extends StatelessWidget { SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( systemNavigationBarColor: GlobalData().enableMYBar - ? themeData.colorScheme.surfaceVariant + ? const Color(0x00010000) : themeData.canvasColor, systemNavigationBarDividerColor: GlobalData().enableMYBar - ? themeData.colorScheme.surfaceVariant + ? const Color(0x00010000) : themeData.canvasColor, systemNavigationBarIconBrightness: currentThemeValue == ThemeType.dark ? Brightness.light From 504d9e20653980e174876e6a002b9b6186da75c9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 10:55:14 +0800 Subject: [PATCH 59/71] opt: stream listener --- lib/pages/bangumi/view.dart | 19 ++------------ lib/pages/dynamics/detail/view.dart | 2 +- lib/pages/dynamics/view.dart | 14 ++-------- lib/pages/fav_detail/view.dart | 2 +- lib/pages/home/view.dart | 2 +- lib/pages/hot/view.dart | 19 ++------------ lib/pages/live/view.dart | 19 ++------------ lib/pages/main/view.dart | 2 +- lib/pages/media/view.dart | 19 ++------------ lib/pages/member/view.dart | 2 +- lib/pages/rank/zone/view.dart | 19 ++------------ lib/pages/rcmd/view.dart | 18 ++----------- lib/pages/subscription_detail/view.dart | 2 +- lib/pages/video/detail/view.dart | 2 +- lib/utils/main_stream.dart | 34 +++++++++++++++++++++++++ 15 files changed, 55 insertions(+), 120 deletions(-) create mode 100644 lib/utils/main_stream.dart diff --git a/lib/pages/bangumi/view.dart b/lib/pages/bangumi/view.dart index f59f94a2..8759af65 100644 --- a/lib/pages/bangumi/view.dart +++ b/lib/pages/bangumi/view.dart @@ -2,13 +2,11 @@ import 'dart:async'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:nil/nil.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/widgets/http_error.dart'; -import 'package:pilipala/pages/home/index.dart'; -import 'package:pilipala/pages/main/index.dart'; +import 'package:pilipala/utils/main_stream.dart'; import 'controller.dart'; import 'widgets/bangumu_card_v.dart'; @@ -34,10 +32,6 @@ class _BangumiPageState extends State void initState() { super.initState(); scrollController = _bangumidController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; - StreamController searchBarStream = - Get.find().searchBarStream; _futureBuilderFuture = _bangumidController.queryBangumiListFeed(); _futureBuilderFutureFollow = _bangumidController.queryBangumiFollow(); scrollController.addListener( @@ -49,16 +43,7 @@ class _BangumiPageState extends State _bangumidController.onLoad(); }); } - - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - searchBarStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - searchBarStream.add(false); - } + handleScrollEvent(scrollController); }, ); } diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index 840cd33f..9da085f4 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -194,7 +194,7 @@ class _DynamicDetailPageState extends State centerTitle: false, titleSpacing: 0, title: StreamBuilder( - stream: titleStreamC.stream, + stream: titleStreamC.stream.distinct(), initialData: false, builder: (context, AsyncSnapshot snapshot) { return AnimatedOpacity( diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart index fe594a43..82a555b1 100644 --- a/lib/pages/dynamics/view.dart +++ b/lib/pages/dynamics/view.dart @@ -3,15 +3,14 @@ import 'dart:async'; import 'package:custom_sliding_segmented_control/custom_sliding_segmented_control.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/skeleton/dynamic_card.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/no_data.dart'; import 'package:pilipala/models/dynamics/result.dart'; -import 'package:pilipala/pages/main/index.dart'; import 'package:pilipala/utils/feed_back.dart'; +import 'package:pilipala/utils/main_stream.dart'; import 'package:pilipala/utils/storage.dart'; import '../mine/controller.dart'; @@ -44,8 +43,6 @@ class _DynamicsPageState extends State _futureBuilderFuture = _dynamicsController.queryFollowDynamic(); _futureBuilderFutureUp = _dynamicsController.queryFollowUp(); scrollController = _dynamicsController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; scrollController.addListener( () async { if (scrollController.position.pixels >= @@ -55,14 +52,7 @@ class _DynamicsPageState extends State _dynamicsController.queryFollowDynamic(type: 'onLoad'); }); } - - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - } + handleScrollEvent(scrollController); }, ); diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index d94f5149..74faa829 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -67,7 +67,7 @@ class _FavDetailPageState extends State { pinned: true, titleSpacing: 0, title: StreamBuilder( - stream: titleStreamC.stream, + stream: titleStreamC.stream.distinct(), initialData: false, builder: (context, AsyncSnapshot snapshot) { return AnimatedOpacity( diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index b0cef90b..cc228f6b 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -171,7 +171,7 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { return StreamBuilder( - stream: stream, + stream: stream!.distinct(), initialData: true, builder: (BuildContext context, AsyncSnapshot snapshot) { final RxBool isUserLoggedIn = ctr!.userLogin; diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart index 7a0a57ea..e2e20e73 100644 --- a/lib/pages/hot/view.dart +++ b/lib/pages/hot/view.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/widgets/animated_dialog.dart'; @@ -9,9 +8,8 @@ import 'package:pilipala/common/widgets/overlay_pop.dart'; import 'package:pilipala/common/skeleton/video_card_h.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/video_card_h.dart'; -import 'package:pilipala/pages/home/index.dart'; import 'package:pilipala/pages/hot/controller.dart'; -import 'package:pilipala/pages/main/index.dart'; +import 'package:pilipala/utils/main_stream.dart'; class HotPage extends StatefulWidget { const HotPage({Key? key}) : super(key: key); @@ -34,10 +32,6 @@ class _HotPageState extends State with AutomaticKeepAliveClientMixin { super.initState(); _futureBuilderFuture = _hotController.queryHotFeed('init'); scrollController = _hotController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; - StreamController searchBarStream = - Get.find().searchBarStream; scrollController.addListener( () { if (scrollController.position.pixels >= @@ -47,16 +41,7 @@ class _HotPageState extends State with AutomaticKeepAliveClientMixin { _hotController.onLoad(); } } - - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - searchBarStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - searchBarStream.add(false); - } + handleScrollEvent(scrollController); }, ); } diff --git a/lib/pages/live/view.dart b/lib/pages/live/view.dart index f3f91c9e..c61d20b3 100644 --- a/lib/pages/live/view.dart +++ b/lib/pages/live/view.dart @@ -2,15 +2,13 @@ import 'dart:async'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/skeleton/video_card_v.dart'; import 'package:pilipala/common/widgets/animated_dialog.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/overlay_pop.dart'; -import 'package:pilipala/pages/home/index.dart'; -import 'package:pilipala/pages/main/index.dart'; +import 'package:pilipala/utils/main_stream.dart'; import 'controller.dart'; import 'widgets/live_item.dart'; @@ -36,10 +34,6 @@ class _LivePageState extends State super.initState(); _futureBuilderFuture = _liveController.queryLiveList('init'); scrollController = _liveController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; - StreamController searchBarStream = - Get.find().searchBarStream; scrollController.addListener( () { if (scrollController.position.pixels >= @@ -49,16 +43,7 @@ class _LivePageState extends State _liveController.onLoad(); }); } - - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - searchBarStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - searchBarStream.add(false); - } + handleScrollEvent(scrollController); }, ); } diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index c551e690..5353ac52 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -129,7 +129,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { ), bottomNavigationBar: StreamBuilder( stream: _mainController.hideTabBar - ? _mainController.bottomBarStream.stream + ? _mainController.bottomBarStream.stream.distinct() : StreamController.broadcast().stream, initialData: true, builder: (context, AsyncSnapshot snapshot) { diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 460c5648..0bb12039 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -1,13 +1,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; -import 'package:media_kit/media_kit.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/models/user/fav_folder.dart'; -import 'package:pilipala/pages/main/index.dart'; import 'package:pilipala/pages/media/index.dart'; +import 'package:pilipala/utils/main_stream.dart'; import 'package:pilipala/utils/utils.dart'; class MediaPage extends StatefulWidget { @@ -31,25 +29,12 @@ class _MediaPageState extends State mediaController = Get.put(MediaController()); _futureBuilderFuture = mediaController.queryFavFolder(); ScrollController scrollController = mediaController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; - mediaController.userLogin.listen((status) { setState(() { _futureBuilderFuture = mediaController.queryFavFolder(); }); }); - scrollController.addListener( - () { - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - } - }, - ); + handleScrollEvent(scrollController); } @override diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index c8a9f406..015750db 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -65,7 +65,7 @@ class _MemberPageState extends State children: [ AppBar( title: StreamBuilder( - stream: appbarStream.stream, + stream: appbarStream.stream.distinct(), initialData: false, builder: (BuildContext context, AsyncSnapshot snapshot) { return AnimatedOpacity( diff --git a/lib/pages/rank/zone/view.dart b/lib/pages/rank/zone/view.dart index fbf8a524..04631a8c 100644 --- a/lib/pages/rank/zone/view.dart +++ b/lib/pages/rank/zone/view.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/widgets/animated_dialog.dart'; @@ -9,9 +8,8 @@ import 'package:pilipala/common/widgets/overlay_pop.dart'; import 'package:pilipala/common/skeleton/video_card_h.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/video_card_h.dart'; -import 'package:pilipala/pages/home/index.dart'; -import 'package:pilipala/pages/main/index.dart'; import 'package:pilipala/pages/rank/zone/index.dart'; +import 'package:pilipala/utils/main_stream.dart'; class ZonePage extends StatefulWidget { const ZonePage({Key? key, required this.rid}) : super(key: key); @@ -38,10 +36,6 @@ class _ZonePageState extends State _zoneController = Get.put(ZoneController(), tag: widget.rid.toString()); _futureBuilderFuture = _zoneController.queryRankFeed('init', widget.rid); scrollController = _zoneController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; - StreamController searchBarStream = - Get.find().searchBarStream; scrollController.addListener( () { if (scrollController.position.pixels >= @@ -51,16 +45,7 @@ class _ZonePageState extends State _zoneController.onLoad(); } } - - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - searchBarStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - searchBarStream.add(false); - } + handleScrollEvent(scrollController); }, ); } diff --git a/lib/pages/rcmd/view.dart b/lib/pages/rcmd/view.dart index d732f370..acc1e654 100644 --- a/lib/pages/rcmd/view.dart +++ b/lib/pages/rcmd/view.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/skeleton/video_card_v.dart'; @@ -10,8 +9,7 @@ import 'package:pilipala/common/widgets/animated_dialog.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/overlay_pop.dart'; import 'package:pilipala/common/widgets/video_card_v.dart'; -import 'package:pilipala/pages/home/index.dart'; -import 'package:pilipala/pages/main/index.dart'; +import 'package:pilipala/utils/main_stream.dart'; import 'controller.dart'; @@ -35,10 +33,6 @@ class _RcmdPageState extends State super.initState(); _futureBuilderFuture = _rcmdController.queryRcmdFeed('init'); ScrollController scrollController = _rcmdController.scrollController; - StreamController mainStream = - Get.find().bottomBarStream; - StreamController searchBarStream = - Get.find().searchBarStream; scrollController.addListener( () { if (scrollController.position.pixels >= @@ -49,15 +43,7 @@ class _RcmdPageState extends State _rcmdController.onLoad(); }); } - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - searchBarStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - searchBarStream.add(false); - } + handleScrollEvent(scrollController); }, ); } diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index 93e0abbb..2c219e58 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -67,7 +67,7 @@ class _SubDetailPageState extends State { pinned: true, titleSpacing: 0, title: StreamBuilder( - stream: titleStreamC.stream, + stream: titleStreamC.stream.distinct(), initialData: false, builder: (context, AsyncSnapshot snapshot) { return AnimatedOpacity( diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 822d0a45..7bb4d909 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -618,7 +618,7 @@ class _VideoDetailPageState extends State /// 重新进入会刷新 // 播放完成/暂停播放 StreamBuilder( - stream: appbarStream.stream, + stream: appbarStream.stream.distinct(), initialData: 0, builder: ((context, snapshot) { return ScrollAppBar( diff --git a/lib/utils/main_stream.dart b/lib/utils/main_stream.dart new file mode 100644 index 00000000..20c160de --- /dev/null +++ b/lib/utils/main_stream.dart @@ -0,0 +1,34 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:easy_debounce/easy_throttle.dart'; +import 'package:flutter/rendering.dart'; +import 'package:get/get.dart'; + +import '../pages/home/index.dart'; +import '../pages/main/index.dart'; + +void handleScrollEvent( + ScrollController scrollController, + // StreamController mainStream, + // StreamController? searchBarStream, +) { + StreamController mainStream = + Get.find().bottomBarStream; + StreamController searchBarStream = + Get.find().searchBarStream; + EasyThrottle.throttle( + 'stream-throttler', + const Duration(milliseconds: 300), + () { + final ScrollDirection direction = + scrollController.position.userScrollDirection; + if (direction == ScrollDirection.forward) { + mainStream.add(true); + searchBarStream.add(true); + } else if (direction == ScrollDirection.reverse) { + mainStream.add(false); + searchBarStream.add(false); + } + }, + ); +} From 83d121fd9cd0d2978df8ce7ed9b5327c63f61c0b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 15:04:33 +0800 Subject: [PATCH 60/71] opt: sheetHeight --- lib/pages/video/detail/controller.dart | 2 + lib/pages/video/detail/introduction/view.dart | 6 +-- lib/pages/video/detail/reply_reply/view.dart | 44 +++++++++---------- lib/pages/video/detail/view.dart | 4 +- 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 2f750a24..4d40e535 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -106,6 +106,7 @@ class VideoDetailController extends GetxController BottomControlType.fit, BottomControlType.fullscreen, ].obs; + RxDouble sheetHeight = 0.0.obs; @override void onInit() { @@ -172,6 +173,7 @@ class VideoDetailController extends GetxController firstFloor: firstFloor, replyType: ReplyType.video, source: 'videoDetail', + sheetHeight: sheetHeight.value, ); }); replyReplyBottomSheetCtr?.closed.then((value) { diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 70fa578d..a7eae6d2 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -372,7 +372,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { ), /// 点赞收藏转发 - actionGrid(context, videoIntroController), + Material(child: actionGrid(context, videoIntroController)), // 合集 videoPart 简洁 if (widget.videoDetail!.ugcSeason != null) ...[ Obx( @@ -381,7 +381,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { cid: videoIntroController.lastPlayCid.value != 0 ? videoIntroController.lastPlayCid.value : widget.videoDetail!.pages!.first.cid, - sheetHeight: sheetHeight, + sheetHeight: videoDetailCtr.sheetHeight.value, changeFuc: (bvid, cid, aid) => videoIntroController.changeSeasonOrbangu( bvid, @@ -399,7 +399,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { () => PagesPanel( pages: widget.videoDetail!.pages!, cid: videoIntroController.lastPlayCid.value, - sheetHeight: sheetHeight, + sheetHeight: videoDetailCtr.sheetHeight.value, changeFuc: (cid) => videoIntroController.changeSeasonOrbangu( videoIntroController.bvid, cid, diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index 344ca1b1..3fe84c71 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -19,6 +19,7 @@ class VideoReplyReplyPanel extends StatefulWidget { this.firstFloor, this.source, this.replyType, + this.sheetHeight, super.key, }); final int? oid; @@ -27,6 +28,7 @@ class VideoReplyReplyPanel extends StatefulWidget { final ReplyItemModel? firstFloor; final String? source; final ReplyType? replyType; + final double? sheetHeight; @override State createState() => _VideoReplyReplyPanelState(); @@ -36,7 +38,6 @@ class _VideoReplyReplyPanelState extends State { late VideoReplyReplyController _videoReplyReplyController; late AnimationController replyAnimationCtl; final Box localCache = GStrorage.localCache; - late double sheetHeight; Future? _futureBuilderFuture; late ScrollController scrollController; @@ -62,7 +63,6 @@ class _VideoReplyReplyPanelState extends State { }, ); - sheetHeight = localCache.get('sheetHeight'); _futureBuilderFuture = _videoReplyReplyController.queryReplyList(); } @@ -77,33 +77,31 @@ class _VideoReplyReplyPanelState extends State { @override Widget build(BuildContext context) { return Container( - height: widget.source == 'videoDetail' ? sheetHeight : null, + height: widget.source == 'videoDetail' ? widget.sheetHeight : null, color: Theme.of(context).colorScheme.background, child: Column( children: [ if (widget.source == 'videoDetail') - Container( - height: 45, - padding: const EdgeInsets.only(left: 12, right: 2), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text('评论详情'), - IconButton( - icon: const Icon(Icons.close, size: 20), - onPressed: () { - _videoReplyReplyController.currentPage = 0; - widget.closePanel?.call; - Navigator.pop(context); - }, - ), - ], + AppBar( + toolbarHeight: 45, + automaticallyImplyLeading: false, + centerTitle: false, + title: Text( + '评论详情', + style: Theme.of(context).textTheme.titleSmall, ), + actions: [ + IconButton( + icon: const Icon(Icons.close, size: 20), + onPressed: () { + _videoReplyReplyController.currentPage = 0; + widget.closePanel?.call; + Navigator.pop(context); + }, + ), + const SizedBox(width: 14), + ], ), - Divider( - height: 1, - color: Theme.of(context).dividerColor.withOpacity(0.1), - ), Expanded( child: RefreshIndicator( onRefresh: () async { diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 10b60c10..05ce2f5e 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -67,6 +67,7 @@ class _VideoDetailPageState extends State super.initState(); heroTag = Get.arguments['heroTag']; vdCtr = Get.put(VideoDetailController(), tag: heroTag); + vdCtr.sheetHeight.value = localCache.get('sheetHeight'); videoIntroController = Get.put( VideoIntroController(bvid: Get.parameters['bvid']!), tag: heroTag); @@ -112,6 +113,8 @@ class _VideoDetailPageState extends State _extendNestCtr.addListener( () { final double offset = _extendNestCtr.position.pixels; + vdCtr.sheetHeight.value = + Get.size.height - videoHeight - statusBarHeight + offset; appbarStream.add(offset); }, ); @@ -271,7 +274,6 @@ class _VideoDetailPageState extends State @override Widget build(BuildContext context) { - // final double videoHeight = MediaQuery.sizeOf(context).width * 9 / 16; final sizeContext = MediaQuery.sizeOf(context); final _context = MediaQuery.of(context); late double defaultVideoHeight = sizeContext.width * 9 / 16; From ff5101d3d0cf71e9f2dd856f8886d8bd8ab86f11 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 15:46:12 +0800 Subject: [PATCH 61/71] =?UTF-8?q?opt:=20=E5=8F=AF=E6=8B=96=E5=8A=A8?= =?UTF-8?q?=E6=A0=87=E8=AF=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/view.dart | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 05ce2f5e..7a1de4e4 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -47,7 +47,7 @@ class _VideoDetailPageState extends State late BangumiIntroController bangumiIntroController; late String heroTag; - PlayerStatus playerStatus = PlayerStatus.playing; + Rx playerStatus = PlayerStatus.playing.obs; double doubleOffset = 0; final Box localCache = GStrorage.localCache; @@ -122,7 +122,7 @@ class _VideoDetailPageState extends State // 播放器状态监听 void playerListener(PlayerStatus? status) async { - playerStatus = status!; + playerStatus.value = status!; if (status == PlayerStatus.completed) { // 结束播放退出全屏 if (autoExitFullcreen) { @@ -368,6 +368,18 @@ class _VideoDetailPageState extends State child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ + Obx(() => AnimatedOpacity( + opacity: playerStatus.value != PlayerStatus.playing + ? 1 + : 0, + duration: const Duration(milliseconds: 100), + child: const Icon( + Icons.drag_handle_rounded, + size: 20, + color: Colors.grey, + ), + )), + const SizedBox(width: 8), SizedBox( height: 32, child: TextButton( @@ -406,7 +418,7 @@ class _VideoDetailPageState extends State ), ), ), - const SizedBox(width: 14), + const SizedBox(width: 18), ], ), )), @@ -559,7 +571,7 @@ class _VideoDetailPageState extends State Orientation.landscape || plPlayerController?.isFullScreen.value == true ? MediaQuery.sizeOf(context).height - : playerStatus != PlayerStatus.playing + : playerStatus.value != PlayerStatus.playing ? kToolbarHeight : pinnedHeaderHeight; }, @@ -626,7 +638,7 @@ class _VideoDetailPageState extends State return ScrollAppBar( snapshot.data!.toDouble(), () => continuePlay(), - playerStatus, + playerStatus.value, null, ); }), From b1c801c8c82f79006fb7e4157c9f686572c79f3b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 16:31:28 +0800 Subject: [PATCH 62/71] fix: mediaPage stream error --- lib/pages/media/view.dart | 2 -- lib/utils/main_stream.dart | 26 ++++++++++++-------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 0bb12039..6541680a 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -28,13 +28,11 @@ class _MediaPageState extends State super.initState(); mediaController = Get.put(MediaController()); _futureBuilderFuture = mediaController.queryFavFolder(); - ScrollController scrollController = mediaController.scrollController; mediaController.userLogin.listen((status) { setState(() { _futureBuilderFuture = mediaController.queryFavFolder(); }); }); - handleScrollEvent(scrollController); } @override diff --git a/lib/utils/main_stream.dart b/lib/utils/main_stream.dart index 20c160de..e63248f8 100644 --- a/lib/utils/main_stream.dart +++ b/lib/utils/main_stream.dart @@ -7,11 +7,7 @@ import 'package:get/get.dart'; import '../pages/home/index.dart'; import '../pages/main/index.dart'; -void handleScrollEvent( - ScrollController scrollController, - // StreamController mainStream, - // StreamController? searchBarStream, -) { +void handleScrollEvent(ScrollController scrollController) { StreamController mainStream = Get.find().bottomBarStream; StreamController searchBarStream = @@ -20,15 +16,17 @@ void handleScrollEvent( 'stream-throttler', const Duration(milliseconds: 300), () { - final ScrollDirection direction = - scrollController.position.userScrollDirection; - if (direction == ScrollDirection.forward) { - mainStream.add(true); - searchBarStream.add(true); - } else if (direction == ScrollDirection.reverse) { - mainStream.add(false); - searchBarStream.add(false); - } + try { + final ScrollDirection direction = + scrollController.position.userScrollDirection; + if (direction == ScrollDirection.forward) { + mainStream.add(true); + searchBarStream.add(true); + } else if (direction == ScrollDirection.reverse) { + mainStream.add(false); + searchBarStream.add(false); + } + } catch (_) {} }, ); } From 894f4fa68da085eeb30353d69ef69d980ba47c94 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 22:57:18 +0800 Subject: [PATCH 63/71] =?UTF-8?q?opt:=20index=E4=B8=BA0=E6=97=B6=E5=90=88?= =?UTF-8?q?=E9=9B=86=E8=B7=B3=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/bangumi/widgets/bangumi_panel.dart | 14 +++++++++----- .../detail/introduction/widgets/page_panel.dart | 17 +++++++++-------- .../introduction/widgets/season_panel.dart | 2 -- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index 988f8d4f..58078d80 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -92,11 +92,15 @@ class _BangumiPanelState extends State { // 在回调函数中获取更新后的状态 final double offset = min((currentIndex * 150) - 75, listViewScrollCtr.position.maxScrollExtent); - listViewScrollCtr.animateTo( - offset, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); + if (currentIndex.value == 0) { + listViewScrollCtr.jumpTo(0); + } else { + listViewScrollCtr.animateTo( + offset, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + } }); } diff --git a/lib/pages/video/detail/introduction/widgets/page_panel.dart b/lib/pages/video/detail/introduction/widgets/page_panel.dart index fc999ba8..83db2d52 100644 --- a/lib/pages/video/detail/introduction/widgets/page_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/page_panel.dart @@ -5,7 +5,6 @@ import 'package:get/get.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/introduction/index.dart'; -import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import '../../../../../common/pages_bottom_sheet.dart'; import '../../../../../models/common/video_episode_type.dart'; @@ -35,7 +34,6 @@ class _PagesPanelState extends State { final String heroTag = Get.arguments['heroTag']; late VideoDetailController _videoDetailController; final ScrollController listViewScrollCtr = ScrollController(); - final ItemScrollController itemScrollController = ItemScrollController(); late PersistentBottomSheetController? _bottomSheetController; @override @@ -60,7 +58,6 @@ class _PagesPanelState extends State { } void changeFucCall(item, i) async { - print('pages changeFucCall'); widget.changeFuc?.call(item.cid); currentIndex.value = i; _bottomSheetController?.close(); @@ -72,11 +69,15 @@ class _PagesPanelState extends State { // 在回调函数中获取更新后的状态 final double offset = min((currentIndex * 150) - 75, listViewScrollCtr.position.maxScrollExtent); - listViewScrollCtr.animateTo( - offset, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); + if (currentIndex.value == 0) { + listViewScrollCtr.jumpTo(0); + } else { + listViewScrollCtr.animateTo( + offset, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + } }); } diff --git a/lib/pages/video/detail/introduction/widgets/season_panel.dart b/lib/pages/video/detail/introduction/widgets/season_panel.dart index 745c081d..2afefcb4 100644 --- a/lib/pages/video/detail/introduction/widgets/season_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/season_panel.dart @@ -4,7 +4,6 @@ import 'package:pilipala/common/pages_bottom_sheet.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/utils/id_utils.dart'; -import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import '../../../../../models/common/video_episode_type.dart'; import '../controller.dart'; @@ -33,7 +32,6 @@ class _SeasonPanelState extends State { late RxInt currentIndex = (-1).obs; final String heroTag = Get.arguments['heroTag']; late VideoDetailController _videoDetailController; - final ItemScrollController itemScrollController = ItemScrollController(); late PersistentBottomSheetController? _bottomSheetController; @override From f1334b550554801074cac46bd8d22318f3164c9d Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 13 Apr 2024 23:34:46 +0800 Subject: [PATCH 64/71] =?UTF-8?q?feat:=20=E7=95=AA=E5=89=A7=E9=80=89?= =?UTF-8?q?=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bangumi/introduction/controller.dart | 5 +++++ lib/pages/bangumi/introduction/view.dart | 1 + lib/pages/bangumi/widgets/bangumi_panel.dart | 6 +++++- lib/pages/video/detail/view.dart | 19 ++++++++++++++----- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index 63eadacf..2098302d 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -56,6 +56,7 @@ class BangumiIntroController extends GetxController { RxMap followStatus = {}.obs; int _tempThemeValue = -1; var userInfo; + PersistentBottomSheetController? bottomSheetController; @override void onInit() { @@ -320,4 +321,8 @@ class BangumiIntroController extends GetxController { ).buildShowContent(Get.context!), ); } + + hiddenEpisodeBottomSheet() { + bottomSheetController?.close(); + } } diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index 13db7432..e47db480 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -325,6 +325,7 @@ class _BangumiInfoState extends State { changeFuc: (bvid, cid, aid) => bangumiIntroController.changeSeasonOrbangu(bvid, cid, aid), 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 58078d80..b01f3be7 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -10,6 +10,7 @@ import 'package:pilipala/utils/storage.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import '../../../common/pages_bottom_sheet.dart'; import '../../../models/common/video_episode_type.dart'; +import '../introduction/controller.dart'; class BangumiPanel extends StatefulWidget { const BangumiPanel({ @@ -19,6 +20,7 @@ class BangumiPanel extends StatefulWidget { this.sheetHeight, this.changeFuc, this.bangumiDetail, + this.bangumiIntroController, }); final List pages; @@ -26,6 +28,7 @@ class BangumiPanel extends StatefulWidget { final double? sheetHeight; final Function? changeFuc; final BangumiInfoModel? bangumiDetail; + final BangumiIntroController? bangumiIntroController; @override State createState() => _BangumiPanelState(); @@ -136,7 +139,8 @@ class _BangumiPanelState extends State { padding: MaterialStateProperty.all(EdgeInsets.zero), ), onPressed: () { - _bottomSheetController = EpisodeBottomSheet( + widget.bangumiIntroController?.bottomSheetController = + _bottomSheetController = EpisodeBottomSheet( currentCid: cid, episodes: widget.pages, changeFucCall: changeFucCall, diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 7a1de4e4..687baaf0 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -180,11 +180,20 @@ class _VideoDetailPageState extends State plPlayerController?.isFullScreen.listen((bool isFullScreen) { if (isFullScreen) { vdCtr.hiddenReplyReplyPanel(); - videoIntroController.hiddenEpisodeBottomSheet(); - if (videoIntroController.videoDetail.value.ugcSeason != null || - (videoIntroController.videoDetail.value.pages != null && - videoIntroController.videoDetail.value.pages!.length > 1)) { - vdCtr.bottomList.insert(3, BottomControlType.episode); + if (vdCtr.videoType == SearchType.video) { + videoIntroController.hiddenEpisodeBottomSheet(); + if (videoIntroController.videoDetail.value.ugcSeason != null || + (videoIntroController.videoDetail.value.pages != null && + videoIntroController.videoDetail.value.pages!.length > 1)) { + vdCtr.bottomList.insert(3, BottomControlType.episode); + } + } + if (vdCtr.videoType == SearchType.media_bangumi) { + bangumiIntroController.hiddenEpisodeBottomSheet(); + if (bangumiIntroController.bangumiDetail.value.episodes != null && + bangumiIntroController.bangumiDetail.value.episodes!.length > 1) { + vdCtr.bottomList.insert(3, BottomControlType.episode); + } } } else { if (vdCtr.bottomList.contains(BottomControlType.episode)) { From cc5e3705101f35390d2aad0f11af26824ec56cd1 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 14 Apr 2024 00:47:40 +0800 Subject: [PATCH 65/71] =?UTF-8?q?fix:=20=E8=B7=9F=E9=9A=8F=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=B8=BB=E9=A2=98=E6=A8=A1=E5=BC=8F=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 52 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 604441e8..3877685c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -130,27 +130,10 @@ class MyApp extends StatelessWidget { ); } - final SnackBarThemeData snackBarThemeData = SnackBarThemeData( - actionTextColor: darkColorScheme.primary, - backgroundColor: darkColorScheme.secondaryContainer, - closeIconColor: darkColorScheme.secondary, - contentTextStyle: TextStyle(color: darkColorScheme.secondary), - elevation: 20, - ); - ThemeData themeData = ThemeData( - // fontFamily: 'HarmonyOS', colorScheme: currentThemeValue == ThemeType.dark ? darkColorScheme : lightColorScheme, - snackBarTheme: snackBarThemeData, - pageTransitionsTheme: const PageTransitionsTheme( - builders: { - TargetPlatform.android: ZoomPageTransitionsBuilder( - allowEnterRouteSnapshotting: false, - ), - }, - ), ); // 小白条、导航栏沉浸 @@ -171,9 +154,38 @@ class MyApp extends StatelessWidget { // 图片缓存 // PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20; return GetMaterialApp( - title: 'PiLiPaLa', - theme: themeData, - darkTheme: themeData, + title: 'PiliPala', + theme: ThemeData( + colorScheme: currentThemeValue == ThemeType.dark + ? darkColorScheme + : lightColorScheme, + snackBarTheme: SnackBarThemeData( + actionTextColor: lightColorScheme.primary, + backgroundColor: lightColorScheme.secondaryContainer, + closeIconColor: lightColorScheme.secondary, + contentTextStyle: TextStyle(color: lightColorScheme.secondary), + elevation: 20, + ), + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.android: ZoomPageTransitionsBuilder( + allowEnterRouteSnapshotting: false, + ), + }, + ), + ), + darkTheme: ThemeData( + colorScheme: currentThemeValue == ThemeType.light + ? lightColorScheme + : darkColorScheme, + snackBarTheme: SnackBarThemeData( + actionTextColor: darkColorScheme.primary, + backgroundColor: darkColorScheme.secondaryContainer, + closeIconColor: darkColorScheme.secondary, + contentTextStyle: TextStyle(color: darkColorScheme.secondary), + elevation: 20, + ), + ), localizationsDelegates: const [ GlobalCupertinoLocalizations.delegate, GlobalMaterialLocalizations.delegate, From e7f46883ed94bbae03687432997845f1228946ca Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 14 Apr 2024 17:00:29 +0800 Subject: [PATCH 66/71] =?UTF-8?q?fix:=20=E6=9C=AA=E5=BC=80=E5=90=AF?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E6=92=AD=E6=94=BE=E6=97=B6=E5=BC=B9=E5=B9=95?= =?UTF-8?q?=E5=BC=80=E5=85=B3=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/video/detail/view.dart | 46 +++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 687baaf0..0152a2cb 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -404,27 +404,41 @@ class _VideoDetailPageState extends State width: 38, height: 38, child: Obx( - () => IconButton( - onPressed: () { - plPlayerController?.isOpenDanmu.value = - !(plPlayerController?.isOpenDanmu.value ?? - false); - }, - icon: !(plPlayerController?.isOpenDanmu.value ?? - false) - ? SvgPicture.asset( + () => !vdCtr.isShowCover.value + ? IconButton( + onPressed: () { + plPlayerController?.isOpenDanmu.value = + !(plPlayerController + ?.isOpenDanmu.value ?? + false); + }, + icon: + !(plPlayerController?.isOpenDanmu.value ?? + false) + ? SvgPicture.asset( + 'assets/images/video/danmu_close.svg', + // ignore: deprecated_member_use + color: Theme.of(context) + .colorScheme + .outline, + ) + : SvgPicture.asset( + 'assets/images/video/danmu_open.svg', + // ignore: deprecated_member_use + color: Theme.of(context) + .colorScheme + .primary, + ), + ) + : IconButton( + icon: SvgPicture.asset( 'assets/images/video/danmu_close.svg', // ignore: deprecated_member_use color: Theme.of(context).colorScheme.outline, - ) - : SvgPicture.asset( - 'assets/images/video/danmu_open.svg', - // ignore: deprecated_member_use - color: - Theme.of(context).colorScheme.primary, ), - ), + onPressed: () {}, + ), ), ), const SizedBox(width: 18), From d943e156d2337b5f1e81cec4bcfbb91f4c7513aa Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 14 Apr 2024 17:10:47 +0800 Subject: [PATCH 67/71] =?UTF-8?q?fix:=20=E5=85=B3=E9=97=AD=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=E6=97=B6=E5=88=87=E6=8D=A2=E5=90=88=E9=9B=86=E5=A4=B1?= =?UTF-8?q?=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video/detail/introduction/controller.dart | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index d81bda00..6469b5c5 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -58,6 +58,7 @@ class VideoIntroController extends GetxController { String heroTag = ''; late ModelResult modelResult; PersistentBottomSheetController? bottomSheetController; + late bool enableRelatedVideo; @override void onInit() { @@ -74,6 +75,8 @@ class VideoIntroController extends GetxController { queryOnlineTotal(); startTimer(); // 在页面加载时启动定时器 } + enableRelatedVideo = + setting.get(SettingBoxKey.enableRelatedVideo, defaultValue: true); } // 获取视频简介&分p @@ -447,15 +450,18 @@ class VideoIntroController extends GetxController { // 重新获取视频资源 final VideoDetailController videoDetailCtr = Get.find(tag: heroTag); - final ReleatedController releatedCtr = - Get.find(tag: heroTag); + if (enableRelatedVideo) { + final ReleatedController releatedCtr = + Get.find(tag: heroTag); + releatedCtr.bvid = bvid; + releatedCtr.queryRelatedVideo(); + } + videoDetailCtr.bvid = bvid; videoDetailCtr.oid.value = aid ?? IdUtils.bv2av(bvid); videoDetailCtr.cid.value = cid; videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.queryVideoUrl(); - releatedCtr.bvid = bvid; - releatedCtr.queryRelatedVideo(); // 重新请求评论 try { /// 未渲染回复组件时可能异常 From adba7b33d31a04a6720f4d6c7b671ee97988ed29 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 15 Apr 2024 22:59:35 +0800 Subject: [PATCH 68/71] =?UTF-8?q?fix:=20=E9=A2=84=E8=AE=BE=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E7=94=BB=E8=B4=A8=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/utils/utils.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index a7273f05..987f57c1 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -210,15 +210,18 @@ class Utils { int minDiff = 127; int closestNumber = 0; // 初始化为0,表示没有找到比目标值小的整数 + if (numbers.contains(target)) { + return target; + } // 向下查找 try { for (int number in numbers) { if (number < target) { int diff = target - number; // 计算目标值与当前整数的差值 - if (diff < minDiff) { minDiff = diff; closestNumber = number; + return closestNumber; } } } From 76f0d5fba2f8152cec2f16a68ba4601439872c38 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 16 Apr 2024 00:11:36 +0800 Subject: [PATCH 69/71] fix: zoneController error --- lib/models/common/rank_type.dart | 18 ------------------ lib/pages/rank/controller.dart | 13 ++++++++----- lib/pages/rank/view.dart | 2 +- lib/pages/rank/zone/controller.dart | 15 +++++++++------ 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/lib/models/common/rank_type.dart b/lib/models/common/rank_type.dart index 2ce6d3b5..07be15c2 100644 --- a/lib/models/common/rank_type.dart +++ b/lib/models/common/rank_type.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:pilipala/pages/rank/zone/index.dart'; enum RandType { @@ -74,7 +73,6 @@ List tabsConfig = [ ), 'label': '全站', 'type': RandType.all, - 'ctr': Get.put, 'page': const ZonePage(rid: 0), }, { @@ -84,7 +82,6 @@ List tabsConfig = [ ), 'label': '国创相关', 'type': RandType.creation, - 'ctr': Get.put, 'page': const ZonePage(rid: 168), }, { @@ -94,7 +91,6 @@ List tabsConfig = [ ), 'label': '动画', 'type': RandType.animation, - 'ctr': Get.put, 'page': const ZonePage(rid: 1), }, { @@ -104,7 +100,6 @@ List tabsConfig = [ ), 'label': '音乐', 'type': RandType.music, - 'ctr': Get.put, 'page': const ZonePage(rid: 3), }, { @@ -114,7 +109,6 @@ List tabsConfig = [ ), 'label': '舞蹈', 'type': RandType.dance, - 'ctr': Get.put, 'page': const ZonePage(rid: 129), }, { @@ -124,7 +118,6 @@ List tabsConfig = [ ), 'label': '游戏', 'type': RandType.game, - 'ctr': Get.put, 'page': const ZonePage(rid: 4), }, { @@ -134,7 +127,6 @@ List tabsConfig = [ ), 'label': '知识', 'type': RandType.knowledge, - 'ctr': Get.put, 'page': const ZonePage(rid: 36), }, { @@ -144,7 +136,6 @@ List tabsConfig = [ ), 'label': '科技', 'type': RandType.technology, - 'ctr': Get.put, 'page': const ZonePage(rid: 188), }, { @@ -154,7 +145,6 @@ List tabsConfig = [ ), 'label': '运动', 'type': RandType.sport, - 'ctr': Get.put, 'page': const ZonePage(rid: 234), }, { @@ -164,7 +154,6 @@ List tabsConfig = [ ), 'label': '汽车', 'type': RandType.car, - 'ctr': Get.put, 'page': const ZonePage(rid: 223), }, { @@ -174,7 +163,6 @@ List tabsConfig = [ ), 'label': '生活', 'type': RandType.life, - 'ctr': Get.put, 'page': const ZonePage(rid: 160), }, { @@ -184,7 +172,6 @@ List tabsConfig = [ ), 'label': '美食', 'type': RandType.food, - 'ctr': Get.put, 'page': const ZonePage(rid: 211), }, { @@ -194,7 +181,6 @@ List tabsConfig = [ ), 'label': '动物圈', 'type': RandType.animal, - 'ctr': Get.put, 'page': const ZonePage(rid: 217), }, { @@ -204,7 +190,6 @@ List tabsConfig = [ ), 'label': '鬼畜', 'type': RandType.madness, - 'ctr': Get.put, 'page': const ZonePage(rid: 119), }, { @@ -214,7 +199,6 @@ List tabsConfig = [ ), 'label': '时尚', 'type': RandType.fashion, - 'ctr': Get.put, 'page': const ZonePage(rid: 155), }, { @@ -224,7 +208,6 @@ List tabsConfig = [ ), 'label': '娱乐', 'type': RandType.entertainment, - 'ctr': Get.put, 'page': const ZonePage(rid: 5), }, { @@ -234,7 +217,6 @@ List tabsConfig = [ ), 'label': '影视', 'type': RandType.film, - 'ctr': Get.put, 'page': const ZonePage(rid: 181), } ]; diff --git a/lib/pages/rank/controller.dart b/lib/pages/rank/controller.dart index 6fe3d424..fa906fc9 100644 --- a/lib/pages/rank/controller.dart +++ b/lib/pages/rank/controller.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/models/common/rank_type.dart'; +import 'package:pilipala/pages/rank/zone/index.dart'; import 'package:pilipala/utils/storage.dart'; class RankController extends GetxController with GetTickerProviderStateMixin { @@ -29,20 +30,22 @@ class RankController extends GetxController with GetTickerProviderStateMixin { void onRefresh() { int index = tabController.index; - var ctr = tabsCtrList[index]; - ctr().onRefresh(); + final ZoneController ctr = tabsCtrList[index]; + ctr.onRefresh(); } void animateToTop() { int index = tabController.index; - var ctr = tabsCtrList[index]; - ctr().animateToTop(); + final ZoneController ctr = tabsCtrList[index]; + ctr.animateToTop(); } void setTabConfig() async { tabs.value = tabsConfig; initialIndex.value = 0; - tabsCtrList = tabs.map((e) => e['ctr']).toList(); + tabsCtrList = tabs + .map((e) => Get.put(ZoneController(), tag: e['rid'].toString())) + .toList(); tabsPageList = tabs.map((e) => e['page']).toList(); tabController = TabController( diff --git a/lib/pages/rank/view.dart b/lib/pages/rank/view.dart index 7b5b4906..4efa2b4e 100644 --- a/lib/pages/rank/view.dart +++ b/lib/pages/rank/view.dart @@ -102,7 +102,7 @@ class _RankPageState extends State onTap: (value) { feedBack(); if (_rankController.initialIndex.value == value) { - _rankController.tabsCtrList[value]().animateToTop(); + _rankController.tabsCtrList[value].animateToTop(); } _rankController.initialIndex.value = value; }, diff --git a/lib/pages/rank/zone/controller.dart b/lib/pages/rank/zone/controller.dart index f9f4dc6e..71f27b93 100644 --- a/lib/pages/rank/zone/controller.dart +++ b/lib/pages/rank/zone/controller.dart @@ -42,12 +42,15 @@ class ZoneController extends GetxController { // 返回顶部并刷新 void animateToTop() async { - if (scrollController.offset >= - MediaQuery.of(Get.context!).size.height * 5) { - scrollController.jumpTo(0); - } else { - await scrollController.animateTo(0, - duration: const Duration(milliseconds: 500), curve: Curves.easeInOut); + if (scrollController.hasClients) { + if (scrollController.offset >= + MediaQuery.of(Get.context!).size.height * 5) { + scrollController.jumpTo(0); + } else { + await scrollController.animateTo(0, + duration: const Duration(milliseconds: 500), + curve: Curves.easeInOut); + } } } } From a8cfe9fa1afa946454c70134666e68a34ede3816 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 16 Apr 2024 23:38:03 +0800 Subject: [PATCH 70/71] =?UTF-8?q?fix:=20seekTo=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/plugin/pl_player/controller.dart | 74 +++++++++++++++------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index f936526b..1ede7045 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -473,17 +473,17 @@ class PlPlayerController { } // 字幕 - if (dataSource.subFiles != '' && dataSource.subFiles != null) { - await pp.setProperty( - 'sub-files', - UniversalPlatform.isWindows - ? dataSource.subFiles!.replaceAll(';', '\\;') - : dataSource.subFiles!.replaceAll(':', '\\:'), - ); - await pp.setProperty("subs-with-matching-audio", "no"); - await pp.setProperty("sub-forced-only", "yes"); - await pp.setProperty("blend-subtitles", "video"); - } + // if (dataSource.subFiles != '' && dataSource.subFiles != null) { + // await pp.setProperty( + // 'sub-files', + // UniversalPlatform.isWindows + // ? dataSource.subFiles!.replaceAll(';', '\\;') + // : dataSource.subFiles!.replaceAll(':', '\\:'), + // ); + // await pp.setProperty("subs-with-matching-audio", "no"); + // await pp.setProperty("sub-forced-only", "yes"); + // await pp.setProperty("blend-subtitles", "video"); + // } _videoController = _videoController ?? VideoController( @@ -603,7 +603,9 @@ class PlPlayerController { makeHeartBeat(event.inSeconds); }), videoPlayerController!.stream.duration.listen((event) { - duration.value = event; + if (event > Duration.zero) { + duration.value = event; + } }), videoPlayerController!.stream.buffer.listen((event) { _buffered.value = event; @@ -646,32 +648,38 @@ class PlPlayerController { /// 跳转至指定位置 Future seekTo(Duration position, {type = 'seek'}) async { - if (position < Duration.zero) { - position = Duration.zero; - } - _position.value = position; - updatePositionSecond(); - _heartDuration = position.inSeconds; - if (duration.value.inSeconds != 0) { - if (type != 'slider') { - /// 拖动进度条调节时,不等待第一帧,防止抖动 - await _videoPlayerController?.stream.buffer.first; + try { + if (position < Duration.zero) { + position = Duration.zero; } - await _videoPlayerController?.seek(position); - } else { - _timerForSeek?.cancel(); - _timerForSeek ??= - Timer.periodic(const Duration(milliseconds: 200), (Timer t) async { - if (duration.value.inSeconds != 0) { - await _videoPlayerController!.stream.buffer.first; - await _videoPlayerController?.seek(position); - t.cancel(); - _timerForSeek = null; + _position.value = position; + updatePositionSecond(); + _heartDuration = position.inSeconds; + if (duration.value.inSeconds != 0) { + if (type != 'slider') { + await _videoPlayerController?.stream.buffer.first; } - }); + await _videoPlayerController?.seek(position); + } else { + _timerForSeek?.cancel(); + _timerForSeek ??= _startSeekTimer(position); + } + } catch (err) { + print('Error while seeking: $err'); } } + Timer? _startSeekTimer(Duration position) { + return Timer.periodic(const Duration(milliseconds: 200), (Timer t) async { + if (duration.value.inSeconds != 0) { + await _videoPlayerController!.stream.buffer.first; + await _videoPlayerController?.seek(position); + t.cancel(); + _timerForSeek = null; + } + }); + } + /// 设置倍速 Future setPlaybackSpeed(double speed) async { /// TODO _duration.value丢失 From 038801a3b9c114d781d0d25fa542051554b46027 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 16 Apr 2024 23:41:45 +0800 Subject: [PATCH 71/71] =?UTF-8?q?opt:=20=E8=A7=86=E9=A2=91=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/plugin/pl_player/controller.dart | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 1ede7045..be72eccb 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -522,7 +522,22 @@ class PlPlayerController { Duration seekTo = Duration.zero, Duration? duration, }) async { - // 设置倍速 + getVideoFit(); + // if (_looping) { + // await setLooping(_looping); + // } + + /// 跳转播放 + if (seekTo != Duration.zero) { + await this.seekTo(seekTo); + } + + /// 自动播放 + if (_autoPlay) { + await play(duration: duration); + } + + /// 设置倍速 if (videoType.value == 'live') { await setPlaybackSpeed(1.0); } else { @@ -532,20 +547,6 @@ class PlPlayerController { await setPlaybackSpeed(1.0); } } - getVideoFit(); - // if (_looping) { - // await setLooping(_looping); - // } - - // 跳转播放 - if (seekTo != Duration.zero) { - await this.seekTo(seekTo); - } - - // 自动播放 - if (_autoPlay) { - await play(duration: duration); - } } List subscriptions = []; @@ -716,11 +717,10 @@ class PlPlayerController { await seekTo(Duration.zero); } await _videoPlayerController?.play(); - + playerStatus.status.value = PlayerStatus.playing; await getCurrentVolume(); await getCurrentBrightness(); - playerStatus.status.value = PlayerStatus.playing; // screenManager.setOverlays(false); /// 临时fix _duration.value丢失