diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index e73e8eab..96a8b8fd 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -234,41 +234,43 @@ class _VideoDetailPageState extends State @override Widget build(BuildContext context) { final videoHeight = MediaQuery.of(context).size.width * 9 / 16; - // final double pinnedHeaderHeight = - // statusBarHeight + kToolbarHeight + videoHeight; - if (MediaQuery.of(context).orientation == Orientation.landscape) { + final double pinnedHeaderHeight = + statusBarHeight + kToolbarHeight + videoHeight; + if (MediaQuery.of(context).orientation == Orientation.landscape || + plPlayerController!.isFullScreen.value) { enterFullScreen(); } else { exitFullScreen(); } - Widget childWhenDisabled = PopScope( - canPop: !plPlayerController!.isFullScreen.value, - onPopInvoked: (bool didPop) { - if (plPlayerController!.isFullScreen.value) { - plPlayerController!.triggerFullScreen(status: false); - } - if (MediaQuery.of(context).orientation == Orientation.landscape) { - verticalScreen(); - } - }, - child: SafeArea( - top: MediaQuery.of(context).orientation == Orientation.portrait, - bottom: MediaQuery.of(context).orientation == Orientation.portrait, - left: !plPlayerController!.isFullScreen.value, - right: !plPlayerController!.isFullScreen.value, - child: Stack( - children: [ - Scaffold( - resizeToAvoidBottomInset: false, - key: videoDetailController.scaffoldKey, - backgroundColor: Colors.black, - body: ExtendedNestedScrollView( - controller: _extendNestCtr, - headerSliverBuilder: - (BuildContext context, bool innerBoxIsScrolled) { - return [ - Obx( - () => SliverAppBar( + Widget childWhenDisabled = SafeArea( + top: MediaQuery.of(context).orientation == Orientation.portrait, + bottom: MediaQuery.of(context).orientation == Orientation.portrait, + left: !plPlayerController!.isFullScreen.value, + right: !plPlayerController!.isFullScreen.value, + child: Stack( + children: [ + Scaffold( + resizeToAvoidBottomInset: false, + key: videoDetailController.scaffoldKey, + backgroundColor: Colors.black, + body: ExtendedNestedScrollView( + controller: _extendNestCtr, + headerSliverBuilder: + (BuildContext context, bool innerBoxIsScrolled) { + return [ + Obx(() => PopScope( + canPop: !plPlayerController!.isFullScreen.value, + onPopInvoked: (bool didPop) { + if (plPlayerController!.isFullScreen.value) { + plPlayerController! + .triggerFullScreen(status: false); + } + if (MediaQuery.of(context).orientation == + Orientation.landscape) { + verticalScreen(); + } + }, + child: SliverAppBar( automaticallyImplyLeading: false, pinned: false, elevation: 0, @@ -278,7 +280,11 @@ class _VideoDetailPageState extends State plPlayerController!.isFullScreen.value || MediaQuery.of(context).orientation == Orientation.landscape - ? MediaQuery.of(context).size.height + ? MediaQuery.of(context).size.height - + (MediaQuery.of(context).orientation == + Orientation.landscape + ? 0 + : statusBarHeight) : videoHeight, backgroundColor: Colors.black, flexibleSpace: FlexibleSpaceBar( @@ -416,116 +422,114 @@ class _VideoDetailPageState extends State }, ), )), - ), - ]; - }, - // pinnedHeaderSliverHeightBuilder: () { - // return playerStatus != PlayerStatus.playing - // ? statusBarHeight + kToolbarHeight - // : pinnedHeaderHeight; - // }, - /// 不收回 - // pinnedHeaderSliverHeightBuilder: () { - // return pinnedHeaderHeight; - // }, - onlyOneScrollInBody: true, - body: Container( - key: Key(heroTag), - color: Theme.of(context).colorScheme.background, - child: Column( - children: [ - Opacity( - opacity: 0, - child: SizedBox( - width: double.infinity, - height: 0, - child: Obx( - () => TabBar( - controller: videoDetailController.tabCtr, - dividerColor: Colors.transparent, - indicatorColor: - Theme.of(context).colorScheme.background, - tabs: videoDetailController.tabs - .map((String name) => Tab(text: name)) - .toList(), - ), - ), - ), - ), - Expanded( - child: TabBarView( + )), + ]; + }, + // pinnedHeaderSliverHeightBuilder: () { + // return playerStatus != PlayerStatus.playing + // ? statusBarHeight + kToolbarHeight + // : pinnedHeaderHeight; + // }, + /// 不收回 + pinnedHeaderSliverHeightBuilder: () { + return pinnedHeaderHeight; + }, + onlyOneScrollInBody: true, + body: Container( + key: Key(heroTag), + color: Theme.of(context).colorScheme.background, + child: Column( + children: [ + Opacity( + opacity: 0, + child: SizedBox( + width: double.infinity, + height: 0, + child: Obx( + () => TabBar( controller: videoDetailController.tabCtr, - children: [ - Builder( - builder: (context) { - return CustomScrollView( - key: const PageStorageKey('简介'), - slivers: [ - if (videoDetailController.videoType == - SearchType.video) ...[ - const VideoIntroPanel(), - ] else if (videoDetailController - .videoType == - SearchType.media_bangumi) ...[ - Obx(() => BangumiIntroPanel( - cid: videoDetailController - .cid.value)), - ], - // if (videoDetailController.videoType == - // SearchType.video) ...[ - // SliverPersistentHeader( - // floating: true, - // pinned: true, - // delegate: SliverHeaderDelegate( - // height: 50, - // child: - // const MenuRow(loadingStatus: false), - // ), - // ), - // ], - SliverToBoxAdapter( - child: Divider( - indent: 12, - endIndent: 12, - color: Theme.of(context) - .dividerColor - .withOpacity(0.06), - ), - ), - const RelatedVideoPanel(), - ], - ); - }, - ), - VideoReplyPanel( - bvid: videoDetailController.bvid, - ) - ], + dividerColor: Colors.transparent, + indicatorColor: + Theme.of(context).colorScheme.background, + tabs: videoDetailController.tabs + .map((String name) => Tab(text: name)) + .toList(), ), ), - ], + ), ), - ), + Expanded( + child: TabBarView( + controller: videoDetailController.tabCtr, + children: [ + Builder( + builder: (context) { + return CustomScrollView( + key: const PageStorageKey('简介'), + slivers: [ + if (videoDetailController.videoType == + SearchType.video) ...[ + const VideoIntroPanel(), + ] else if (videoDetailController.videoType == + SearchType.media_bangumi) ...[ + Obx(() => BangumiIntroPanel( + cid: videoDetailController.cid.value)), + ], + // if (videoDetailController.videoType == + // SearchType.video) ...[ + // SliverPersistentHeader( + // floating: true, + // pinned: true, + // delegate: SliverHeaderDelegate( + // height: 50, + // child: + // const MenuRow(loadingStatus: false), + // ), + // ), + // ], + SliverToBoxAdapter( + child: Divider( + indent: 12, + endIndent: 12, + color: Theme.of(context) + .dividerColor + .withOpacity(0.06), + ), + ), + const RelatedVideoPanel(), + ], + ); + }, + ), + VideoReplyPanel( + bvid: videoDetailController.bvid, + ) + ], + ), + ), + ], ), ), - - /// 重新进入会刷新 - // 播放完成/暂停播放 - // StreamBuilder( - // stream: appbarStream.stream, - // initialData: 0, - // builder: ((context, snapshot) { - // return ScrollAppBar( - // snapshot.data!.toDouble(), - // () => continuePlay(), - // playerStatus, - // null, - // ); - // }), - // ) - ], + ), ), - )); + + /// 重新进入会刷新 + // 播放完成/暂停播放 + // StreamBuilder( + // stream: appbarStream.stream, + // initialData: 0, + // builder: ((context, snapshot) { + // return ScrollAppBar( + // snapshot.data!.toDouble(), + // () => continuePlay(), + // playerStatus, + // null, + // ); + // }), + // ) + ], + ), + ); Widget childWhenEnabled = FutureBuilder( key: Key(heroTag), future: _futureBuilderFuture, diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 8b8b5780..f8c5a28b 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -25,6 +25,7 @@ import 'widgets/backward_seek.dart'; import 'widgets/bottom_control.dart'; import 'widgets/common_btn.dart'; import 'widgets/forward_seek.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; class PLVideoPlayer extends StatefulWidget { final PlPlayerController controller; @@ -76,6 +77,9 @@ class _PLVideoPlayerState extends State late bool enableBackgroundPlay; late double screenWidth; + // 用于记录上一次全屏切换手势触发时间,避免误触 + DateTime? lastFullScreenToggleTime; + void onDoubleTapSeekBackward() { _ctr.onDoubleTapSeekBackward(); } @@ -503,11 +507,15 @@ class _PLVideoPlayerState extends State final tapPosition = details.localPosition.dx; final sectionWidth = totalWidth / 3; final delta = details.delta.dy; - /// 锁定时禁用 if (_.controlsLock.value) { return; } + if (lastFullScreenToggleTime != null && + DateTime.now().difference(lastFullScreenToggleTime!) < + const Duration(milliseconds: 500)) { + return; + } if (tapPosition < sectionWidth) { // 左边区域 👈 double level = (_.isFullScreen.value @@ -523,12 +531,14 @@ class _PLVideoPlayerState extends State const double threshold = 7.0; // 滑动阈值 if (dy > _distance && dy > threshold) { if (_.isFullScreen.value) { + lastFullScreenToggleTime = DateTime.now(); // 下滑退出全屏 await widget.controller.triggerFullScreen(status: false); } _distance = 0.0; } else if (dy < _distance && dy < -threshold) { if (!_.isFullScreen.value) { + lastFullScreenToggleTime = DateTime.now(); // 上滑进入全屏 await widget.controller.triggerFullScreen(); }