diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index 4f5527ff5..dd7558d5a 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -95,9 +95,9 @@ class _PlDanmakuState extends State { // 根据position判断是否有已缓存弹幕。没有则请求对应段 int segIndex = (currentPosition / (6 * 60 * 1000)).ceil(); segIndex = segIndex < 1 ? 1 : segIndex; - print('🌹🌹: ${segIndex}'); - print('🌹🌹: ${ctr.dmSegList.length}'); - print('🌹🌹: ${ctr.hasrequestSeg.contains(segIndex - 1)}'); + // print('🌹🌹: ${segIndex}'); + // print('🌹🌹: ${ctr.dmSegList.length}'); + // print('🌹🌹: ${ctr.hasrequestSeg.contains(segIndex - 1)}'); if (segIndex - 1 >= ctr.dmSegList.length || (ctr.dmSegList[segIndex - 1].elems.isEmpty && !ctr.hasrequestSeg.contains(segIndex - 1))) { diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 6fa0df6f0..c3bb7b4ba 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -138,8 +138,8 @@ class VideoDetailController extends GetxController } showReplyReplyPanel() { - PersistentBottomSheetController? ctr = - scaffoldKey.currentState?.showBottomSheet((BuildContext context) { + PersistentBottomSheetController? ctr = + scaffoldKey.currentState?.showBottomSheet((BuildContext context) { return VideoReplyReplyPanel( oid: oid, rpid: fRpid, diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index d67f9b66f..96a8b8fd0 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -21,6 +21,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 'package:pilipala/plugin/pl_player/utils/fullscreen.dart'; import 'widgets/header_control.dart'; class VideoDetailPage extends StatefulWidget { @@ -235,9 +236,17 @@ class _VideoDetailPageState extends State final videoHeight = MediaQuery.of(context).size.width * 9 / 16; final double pinnedHeaderHeight = statusBarHeight + kToolbarHeight + videoHeight; + if (MediaQuery.of(context).orientation == Orientation.landscape || + plPlayerController!.isFullScreen.value) { + enterFullScreen(); + } else { + exitFullScreen(); + } Widget childWhenDisabled = SafeArea( - top: false, - bottom: false, + 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( @@ -249,145 +258,171 @@ class _VideoDetailPageState extends State headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { return [ - SliverAppBar( - automaticallyImplyLeading: false, - pinned: false, - elevation: 0, - scrolledUnderElevation: 0, - forceElevated: innerBoxIsScrolled, - expandedHeight: videoHeight, - backgroundColor: Colors.black, - flexibleSpace: FlexibleSpaceBar( - background: Padding( - padding: EdgeInsets.only(top: statusBarHeight), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - FutureBuilder( - future: _futureBuilderFuture, - builder: ((context, snapshot) { - if (snapshot.hasData && - snapshot.data['status']) { - return Obx( - () => !videoDetailController - .autoPlay.value - ? const SizedBox() - : PLVideoPlayer( - controller: plPlayerController!, - headerControl: - videoDetailController - .headerControl, - danmuWidget: Obx( - () => PlDanmaku( - key: Key( - videoDetailController - .danmakuCid.value - .toString()), - cid: videoDetailController - .danmakuCid.value, - playerController: - plPlayerController!, - ), - ), - ), - ); - } else { - return const SizedBox(); - } - }), - ), - - Obx( - () => Visibility( - visible: - videoDetailController.isShowCover.value, - child: Positioned( - top: 0, - left: 0, - right: 0, - child: NetworkImgLayer( - type: 'emote', - src: videoDetailController - .videoItem['pic'], - width: maxWidth, - height: maxHeight, + 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, + scrolledUnderElevation: 0, + forceElevated: innerBoxIsScrolled, + expandedHeight: + plPlayerController!.isFullScreen.value || + MediaQuery.of(context).orientation == + Orientation.landscape + ? MediaQuery.of(context).size.height - + (MediaQuery.of(context).orientation == + Orientation.landscape + ? 0 + : statusBarHeight) + : videoHeight, + backgroundColor: Colors.black, + flexibleSpace: FlexibleSpaceBar( + background: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + children: [ + FutureBuilder( + future: _futureBuilderFuture, + builder: ((context, snapshot) { + if (snapshot.hasData && + snapshot.data['status']) { + return Obx( + () => !videoDetailController + .autoPlay.value + ? const SizedBox() + : PLVideoPlayer( + controller: + plPlayerController!, + headerControl: + videoDetailController + .headerControl, + danmuWidget: Obx( + () => PlDanmaku( + key: Key( + videoDetailController + .danmakuCid + .value + .toString()), + cid: + videoDetailController + .danmakuCid + .value, + playerController: + plPlayerController!, + ), + ), + ), + ); + } else { + return const SizedBox(); + } + }), ), - ), - ), - ), - /// 关闭自动播放时 手动播放 - Obx( - () => Visibility( - visible: videoDetailController - .isShowCover.value && - videoDetailController - .isEffective.value && - !videoDetailController.autoPlay.value, - child: Stack( - children: [ - Positioned( + Obx( + () => Visibility( + visible: videoDetailController + .isShowCover.value, + child: Positioned( top: 0, left: 0, right: 0, - child: AppBar( - primary: false, - foregroundColor: Colors.white, - backgroundColor: - Colors.transparent, - actions: [ - IconButton( - tooltip: '稍后再看', - onPressed: () async { - var res = await UserHttp - .toViewLater( - bvid: - videoDetailController - .bvid); - SmartDialog.showToast( - res['msg']); - }, - icon: const Icon( - Icons.history_outlined), + child: NetworkImgLayer( + type: 'emote', + src: videoDetailController + .videoItem['pic'], + width: maxWidth, + height: maxHeight, + ), + ), + ), + ), + + /// 关闭自动播放时 手动播放 + Obx( + () => Visibility( + visible: videoDetailController + .isShowCover.value && + videoDetailController + .isEffective.value && + !videoDetailController + .autoPlay.value, + child: Stack( + children: [ + Positioned( + top: 0, + left: 0, + right: 0, + child: AppBar( + primary: false, + foregroundColor: + Colors.white, + backgroundColor: + Colors.transparent, + actions: [ + IconButton( + tooltip: '稍后再看', + onPressed: () async { + var res = await UserHttp + .toViewLater( + bvid: + videoDetailController + .bvid); + SmartDialog.showToast( + res['msg']); + }, + icon: const Icon(Icons + .history_outlined), + ), + const SizedBox(width: 14) + ], + ), + ), + Positioned( + right: 12, + bottom: 10, + child: TextButton.icon( + style: ButtonStyle( + backgroundColor: + MaterialStateProperty + .resolveWith( + (states) { + return Theme.of(context) + .colorScheme + .primaryContainer; + }), + ), + onPressed: () => + handlePlay(), + icon: const Icon( + Icons.play_circle_outline, + size: 20, + ), + label: const Text('Play'), + ), ), - const SizedBox(width: 14) ], - ), - ), - Positioned( - right: 12, - bottom: 10, - child: TextButton.icon( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty - .resolveWith((states) { - return Theme.of(context) - .colorScheme - .primaryContainer; - }), - ), - onPressed: () => handlePlay(), - icon: const Icon( - Icons.play_circle_outline, - size: 20, - ), - label: const Text('Play'), - ), - ), - ], - )), - ), - ], - ); - }, - ), - ), - ), - ), + )), + ), + ], + ); + }, + ), + )), + )), ]; }, // pinnedHeaderSliverHeightBuilder: () { diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 103839002..5c2491a06 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -880,7 +880,18 @@ class _HeaderControlState extends State { size: 15, color: Colors.white, ), - fuc: () => Get.back(), + fuc: () => { + if (widget.controller!.isFullScreen.value){ + widget.controller!.triggerFullScreen(status: false) + } else { + if (MediaQuery.of(context).orientation == Orientation.landscape){ + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + ]) + }, + Get.back() + } + }, ), SizedBox(width: buttonSpace), ComBtn( diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 80fd66717..706209e1b 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -899,6 +899,7 @@ class PlPlayerController { await StatusBarControl.setHidden(true, animation: StatusBarAnimation.FADE); if (!isFullScreen.value && status) { /// 按照视频宽高比决定全屏方向 + toggleFullScreen(true); switch (mode) { case FullScreenMode.auto: if (direction.value == 'horizontal') { @@ -927,41 +928,40 @@ class PlPlayerController { break; } - toggleFullScreen(true); - bool isValid = - direction.value == 'vertical' || mode == FullScreenMode.vertical - ? true - : false; - var result = await showDialog( - context: Get.context!, - useSafeArea: false, - builder: (context) => Dialog.fullscreen( - backgroundColor: Colors.black, - child: SafeArea( - // 忽略手机安全区域 - top: isValid, - left: false, - right: false, - bottom: isValid, - child: PLVideoPlayer( - controller: this, - headerControl: headerControl, - bottomControl: bottomControl, - danmuWidget: danmuWidget, - ), - ), - ), - ); - if (result == null) { - // 退出全屏 - StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE); - exitFullScreen(); - await verticalScreen(); - toggleFullScreen(false); - } + // bool isValid = + // direction.value == 'vertical' || mode == FullScreenMode.vertical + // ? true + // : false; + // var result = await showDialog( + // context: Get.context!, + // useSafeArea: false, + // builder: (context) => Dialog.fullscreen( + // backgroundColor: Colors.black, + // child: SafeArea( + // // 忽略手机安全区域 + // top: isValid, + // left: false, + // right: false, + // bottom: isValid, + // child: PLVideoPlayer( + // controller: this, + // headerControl: headerControl, + // bottomControl: bottomControl, + // danmuWidget: danmuWidget, + // ), + // ), + // ), + // ); + // if (result == null) { + // // 退出全屏 + // StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE); + // exitFullScreen(); + // await verticalScreen(); + // toggleFullScreen(false); + // } } else if (isFullScreen.value) { StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE); - Get.back(); + // Get.back(); exitFullScreen(); await verticalScreen(); toggleFullScreen(false); diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 8b8b5780a..f8c5a28b6 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(); }