From 768595234f5e058949643415c021f1e4e3610602 Mon Sep 17 00:00:00 2001 From: ErBW_s <94068488+ErBWs@users.noreply.github.com> Date: Sun, 27 Oct 2024 00:29:55 +0800 Subject: [PATCH] Seperate tabBody, add scrollvoew observer --- lib/pages/player/player_item.dart | 11 +- lib/pages/video/video_controller.dart | 13 ++ lib/pages/video/video_page.dart | 180 ++++++++++++++++++++------ pubspec.yaml | 1 + 4 files changed, 164 insertions(+), 41 deletions(-) diff --git a/lib/pages/player/player_item.dart b/lib/pages/player/player_item.dart index d2182aa3..34feffd3 100644 --- a/lib/pages/player/player_item.dart +++ b/lib/pages/player/player_item.dart @@ -304,6 +304,7 @@ class _PlayerItemState extends State void onBackPressed(BuildContext context) async { if (videoPageController.androidFullscreen) { + videoPageController.menuJumpToCurrentEpisode(); setState(() { lockPanel = false; }); @@ -341,8 +342,10 @@ class _PlayerItemState extends State lockPanel = false; }); Utils.exitFullScreen(); + videoPageController.menuJumpToCurrentEpisode(); } else { Utils.enterFullScreen(); + videoPageController.showTabBody = false; } videoPageController.androidFullscreen = !videoPageController.androidFullscreen; @@ -1407,8 +1410,8 @@ class _PlayerItemState extends State _handleDanmaku(); }, ), - (videoPageController.androidFullscreen || - !Utils.isDesktop()) + (!videoPageController.androidFullscreen && + !Utils.isTablet() && !Utils.isDesktop()) ? Container() : IconButton( color: Colors.white, @@ -1420,6 +1423,10 @@ class _PlayerItemState extends State videoPageController.showTabBody = !videoPageController .showTabBody; + if (videoPageController.showTabBody) { + videoPageController.animation.forward(); + videoPageController.menuJumpToCurrentEpisode(); + } }, ), IconButton( diff --git a/lib/pages/video/video_controller.dart b/lib/pages/video/video_controller.dart index 4076de29..904e2cba 100644 --- a/lib/pages/video/video_controller.dart +++ b/lib/pages/video/video_controller.dart @@ -1,3 +1,4 @@ +import 'package:flutter/animation.dart'; import 'package:kazumi/modules/roads/road_module.dart'; import 'package:kazumi/plugins/plugins_controller.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -7,6 +8,7 @@ import 'package:kazumi/pages/history/history_controller.dart'; import 'package:mobx/mobx.dart'; import 'package:logger/logger.dart'; import 'package:kazumi/utils/logger.dart'; +import 'package:scrollview_observer/scrollview_observer.dart'; part 'video_controller.g.dart'; @@ -49,6 +51,8 @@ abstract class _VideoPageController with Store { var roadList = ObservableList(); late Plugin currentPlugin; + late GridObserverController observerController; + late AnimationController animation; final PluginsController pluginsController = Modular.get(); final HistoryController historyController = Modular.get(); @@ -74,5 +78,14 @@ abstract class _VideoPageController with Store { final webviewItemController = Modular.get(); await webviewItemController.loadUrl(urlItem, offset: offset); } + + menuJumpToCurrentEpisode() { + // if (showTabBody) { + Future.delayed(const Duration(milliseconds: 20), () { + observerController.jumpTo( + index: currentEspisode > 1 ? currentEspisode - 1 : currentEspisode); + }); + // } + } } diff --git a/lib/pages/video/video_page.dart b/lib/pages/video/video_page.dart index 23b0e97b..0f20521c 100644 --- a/lib/pages/video/video_page.dart +++ b/lib/pages/video/video_page.dart @@ -17,6 +17,7 @@ import 'package:flutter/services.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; import 'package:kazumi/bean/appbar/drag_to_move_bar.dart' as dtb; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:scrollview_observer/scrollview_observer.dart'; class VideoPage extends StatefulWidget { const VideoPage({super.key}); @@ -35,12 +36,27 @@ class _VideoPageState extends State final HistoryController historyController = Modular.get(); late bool playResume; + ScrollController scrollController = ScrollController(); + late Animation _rightOffsetAnimation; + // 当前播放列表 late int currentRoad; @override void initState() { super.initState(); + videoPageController.observerController = GridObserverController(controller: scrollController); + videoPageController.animation = AnimationController( + duration: const Duration(milliseconds: 100), + vsync: this, + ); + _rightOffsetAnimation = Tween( + begin: const Offset(1.0, 0.0), + end: const Offset(0.0, 0.0), + ).animate(CurvedAnimation( + parent: videoPageController.animation, + curve: Curves.easeInOut, + )); WakelockPlus.enable(); videoPageController.currentEspisode = 1; videoPageController.currentRoad = 0; @@ -69,6 +85,8 @@ class _VideoPageState extends State try { playerController.mediaPlayer.dispose(); } catch (_) {} + videoPageController.observerController.controller?.dispose(); + videoPageController.animation.dispose(); WakelockPlus.disable(); Utils.unlockScreenRotation(); super.dispose(); @@ -78,18 +96,32 @@ class _VideoPageState extends State videoPageController.showDebugLog = !videoPageController.showDebugLog; } + void closeTabBodyAnimated() { + videoPageController.animation.reverse(); + Future.delayed(const Duration(milliseconds: 100), () { + videoPageController.showTabBody = false; + }); + } + @override Widget build(BuildContext context) { - WidgetsBinding.instance.addPostFrameCallback((_) {}); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (videoPageController.showTabBody) { + videoPageController.animation.forward(); + videoPageController.menuJumpToCurrentEpisode(); + } + }); return OrientationBuilder(builder: (context, orientation) { if (!Utils.isTablet() && !Utils.isDesktop()) { if (orientation == Orientation.landscape && !videoPageController.androidFullscreen) { Utils.enterFullScreen(lockOrientation: false); videoPageController.androidFullscreen = true; + videoPageController.showTabBody = false; } else if (orientation == Orientation.portrait && videoPageController.androidFullscreen) { Utils.exitFullScreen(lockOrientation: false); + videoPageController.menuJumpToCurrentEpisode(); videoPageController.androidFullscreen = false; } } @@ -110,50 +142,99 @@ class _VideoPageState extends State ((Utils.isTablet()) && MediaQuery.of(context).size.height < MediaQuery.of(context).size.width) - ? Row( + ? Stack( + alignment: Alignment.centerRight, children: [ Container( color: Colors.black, height: MediaQuery.of(context).size.height, - width: (!videoPageController.androidFullscreen && - videoPageController.showTabBody) - ? MediaQuery.of(context).size.height - : MediaQuery.of(context).size.width, - child: playerBody), - (videoPageController.androidFullscreen || - !videoPageController.showTabBody) - ? Container() - : Expanded( - child: Column( - children: [ - tabBar, - tabBody, - ], - ), - ) - ], - ) - : Column( - children: [ - Container( - color: Colors.black, - height: videoPageController.androidFullscreen - ? MediaQuery.of(context).size.height - : MediaQuery.of(context).size.width * 9 / 16, width: MediaQuery.of(context).size.width, child: playerBody), - videoPageController.androidFullscreen - ? Container() - : Expanded( - child: Column( - children: [ - tabBar, - tabBody, - ], - ), - ) + if (videoPageController.showTabBody) ...[ + GestureDetector( + onTap: () { + closeTabBodyAnimated(); + }, + child: Container( + color: Colors.black38, + width: double.infinity, + height: double.infinity, + ), + ), + SlideTransition(position: _rightOffsetAnimation, + child: SizedBox( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width * 1 / 3 > 420 + ? 420 + : MediaQuery.of(context).size.width * 1 / 3, + child: Container( + color: Colors.black, + child: GridViewObserver( + controller: videoPageController.observerController, + child: Column( + children: [ + tabBar, + tabBody, + ], + ), + ))) + )] ], - ), + ) + : (!videoPageController.androidFullscreen) + ? Column( + children: [ + Container( + color: Colors.black, + height: MediaQuery.of(context).size.width * 9 / 16, + width: MediaQuery.of(context).size.width, + child: playerBody), + Expanded( + child: GridViewObserver( + controller: videoPageController.observerController, + child: Column( + children: [ + tabBar, + tabBody, + ], + ), + )) + ], + ) + : Stack(alignment: Alignment.centerRight, children: [ + Container( + color: Colors.black, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: playerBody), + if (videoPageController.showTabBody) ...[ + GestureDetector( + onTap: () { + closeTabBodyAnimated(); + }, + child: Container( + color: Colors.black38, + width: double.infinity, + height: double.infinity, + ), + ), + SlideTransition(position: _rightOffsetAnimation, + child: SizedBox( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.height, + child: Container( + color: Colors.black, + child: GridViewObserver( + controller: videoPageController.observerController, + child: Column( + children: [ + tabBar, + tabBody, + ], + ), + ))) + )] + ]), ), ); }); @@ -256,6 +337,7 @@ class _VideoPageState extends State if (videoPageController.androidFullscreen == true) { Utils.exitFullScreen(); + videoPageController.menuJumpToCurrentEpisode(); videoPageController.androidFullscreen = false; return; @@ -266,8 +348,27 @@ class _VideoPageState extends State const Expanded( child: dtb.DragToMoveArea( child: SizedBox(height: 40))), + Visibility( + visible: Utils.isDesktop() || Utils.isTablet(), + child: IconButton( + onPressed: () { + videoPageController.showTabBody = !videoPageController.showTabBody; + if (videoPageController.showTabBody) { + videoPageController.animation.forward(); + videoPageController.menuJumpToCurrentEpisode(); + } + }, + icon: Icon( + videoPageController.showTabBody + ? Icons.menu_open + : Icons.menu_open_outlined, + color: Colors.white, + ))), IconButton( - icon: const Icon(Icons.bug_report, + icon: Icon( + videoPageController.showDebugLog + ? Icons.bug_report + : Icons.bug_report_outlined, color: Colors.white), onPressed: () { showDebugConsole(); @@ -453,6 +554,7 @@ class _VideoPageState extends State padding: const EdgeInsets.only(top: 0, right: 8, left: 8), child: GridView.builder( scrollDirection: Axis.vertical, + controller: scrollController, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: (Utils.isDesktop() && !Utils.isWideScreen()) ? 2 : 3, diff --git a/pubspec.yaml b/pubspec.yaml index 002b5030..f45e4ad9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -82,6 +82,7 @@ dependencies: git: url: https://github.com/Predidit/linux_webview_window.git ref: no_texture + scrollview_observer: ^1.22.0 dev_dependencies: flutter_test: