From 4256c2b023ed5e856eb7c94ae979025956a9dc6e Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Fri, 24 Oct 2025 12:12:56 +0800 Subject: [PATCH] opt ui Closes #1680 Signed-off-by: bggRGjQaUbCoE --- lib/pages/live_room/view.dart | 170 ++++++------------ lib/pages/video/view.dart | 39 ++-- lib/plugin/pl_player/controller.dart | 28 +-- .../pl_player/models/fullscreen_mode.dart | 6 +- lib/plugin/pl_player/view.dart | 4 +- 5 files changed, 98 insertions(+), 149 deletions(-) diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 498cccc2..beb04dba 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -33,7 +33,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:flutter/foundation.dart' show kDebugMode; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart' show SystemUiOverlayStyle; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart' hide ContextExtensionss; import 'package:screen_brightness_platform_interface/screen_brightness_platform_interface.dart'; @@ -351,38 +350,16 @@ class _LiveRoomPageState extends State ); } - SystemUiOverlayStyle _systemOverlayStyleForBrightness( - Brightness brightness, [ - Color? backgroundColor, - ]) { - final SystemUiOverlayStyle style = brightness == Brightness.dark - ? SystemUiOverlayStyle.light - : SystemUiOverlayStyle.dark; - // For backward compatibility, create an overlay style without system navigation bar settings. - return SystemUiOverlayStyle( - statusBarColor: backgroundColor, - statusBarBrightness: style.statusBarBrightness, - statusBarIconBrightness: style.statusBarIconBrightness, - systemStatusBarContrastEnforced: style.systemStatusBarContrastEnforced, - ); - } - Widget get childWhenDisabled { - return AnnotatedRegion( - value: _systemOverlayStyleForBrightness( - Brightness.dark, - Theme.of(context).useMaterial3 ? const Color(0x00000000) : null, - ), - child: ColoredBox( - color: Colors.black, - child: Stack( - clipBehavior: Clip.none, - children: [ + return Obx(() { + final isFullScreen = this.isFullScreen; + return Stack( + clipBehavior: Clip.none, + children: [ + const SizedBox.expand(child: ColoredBox(color: Colors.black)), + if (!isFullScreen) Obx( () { - if (isFullScreen) { - return const SizedBox.shrink(); - } final appBackground = _liveRoomController .roomInfoH5 .value @@ -407,34 +384,31 @@ class _LiveRoomPageState extends State ); }, ), - if (isPortrait) - Obx( - () { - if (_liveRoomController.isPortrait.value) { - return _buildPP; - } - return _buildPH; - }, - ) - else - _buildBodyH, - ], - ), - ), - ); + Scaffold( + backgroundColor: Colors.transparent, + appBar: _buildAppBar(isFullScreen), + body: isPortrait + ? Obx( + () { + if (_liveRoomController.isPortrait.value) { + return _buildPP(isFullScreen); + } + return _buildPH(isFullScreen); + }, + ) + : _buildBodyH(isFullScreen), + ), + ], + ); + }); } - Widget get _buildPH { - final isFullScreen = this.isFullScreen; + Widget _buildPH(bool isFullScreen) { final height = maxWidth * 9 / 16; - final videoHeight = isFullScreen ? maxHeight : height; + final videoHeight = isFullScreen ? maxHeight - padding.top : height; final bottomHeight = maxHeight - padding.top - height - kToolbarHeight; return Column( children: [ - Offstage( - offstage: isFullScreen, - child: _buildAppBar, - ), SizedBox( width: maxWidth, height: videoHeight, @@ -456,18 +430,15 @@ class _LiveRoomPageState extends State ); } - Widget get _buildPP { - final isFullScreen = this.isFullScreen; + Widget _buildPP(bool isFullScreen) { final bottomHeight = 70 + padding.bottom; - final topPadding = padding.top + kToolbarHeight; final videoHeight = isFullScreen ? maxHeight - padding.top - : maxHeight - bottomHeight - topPadding; + : maxHeight - bottomHeight; return Stack( clipBehavior: Clip.none, children: [ Positioned.fill( - top: isFullScreen ? padding.top : topPadding, bottom: isFullScreen ? 0 : bottomHeight, child: videoPlayerPanel( width: maxWidth, @@ -477,15 +448,6 @@ class _LiveRoomPageState extends State alignment: isFullScreen ? Alignment.center : Alignment.topCenter, ), ), - Positioned( - top: 0, - left: 0, - right: 0, - child: Offstage( - offstage: isFullScreen, - child: _buildAppBar, - ), - ), Positioned( left: 0, right: 0, @@ -514,9 +476,10 @@ class _LiveRoomPageState extends State ); } - PreferredSizeWidget get _buildAppBar { + PreferredSizeWidget _buildAppBar(bool isFullScreen) { final color = Theme.of(context).colorScheme.onSurfaceVariant; return AppBar( + toolbarHeight: isFullScreen ? 0 : null, backgroundColor: Colors.transparent, foregroundColor: Colors.white, titleTextStyle: const TextStyle(color: Colors.white), @@ -677,56 +640,41 @@ class _LiveRoomPageState extends State ); } - Widget get _buildBodyH { + Widget _buildBodyH(bool isFullScreen) { double videoWidth = clampDouble(maxHeight / maxWidth * 1.08, 0.56, 0.7) * maxWidth; final rigthWidth = min(400.0, maxWidth - videoWidth - padding.horizontal); - videoWidth = maxWidth - rigthWidth; + videoWidth = maxWidth - rigthWidth - padding.horizontal; final videoHeight = maxHeight - padding.top; - return Obx( - () { - final isFullScreen = this.isFullScreen; - final width = isFullScreen ? maxWidth : videoWidth; - final height = isFullScreen ? maxHeight : videoHeight; - return Column( - children: [ - Offstage( - offstage: isFullScreen, - child: _buildAppBar, + final width = isFullScreen ? maxWidth : videoWidth; + final height = isFullScreen ? maxHeight - padding.top : videoHeight; + return Padding( + padding: isFullScreen + ? EdgeInsets.zero + : EdgeInsets.only(left: padding.left, right: padding.right), + child: Row( + children: [ + Container( + width: width, + height: height, + margin: EdgeInsets.only(bottom: padding.bottom), + child: videoPlayerPanel( + isFullScreen, + fill: Colors.transparent, + width: width, + height: height, ), - Expanded( - child: Padding( - padding: isFullScreen - ? EdgeInsets.zero - : EdgeInsets.only(left: padding.left, right: padding.right), - child: Row( - children: [ - Container( - margin: EdgeInsets.only(bottom: padding.bottom), - width: width, - height: height, - child: videoPlayerPanel( - isFullScreen, - fill: Colors.transparent, - width: width, - height: height, - ), - ), - Offstage( - offstage: isFullScreen, - child: SizedBox( - width: rigthWidth, - height: videoHeight, - child: _buildBottomWidget, - ), - ), - ], - ), - ), + ), + Offstage( + offstage: isFullScreen, + child: SizedBox( + width: rigthWidth, + height: videoHeight, + child: _buildBottomWidget, ), - ], - ); - }, + ), + ], + ), ); } diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 38e50ebd..2fd68637 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -181,7 +181,7 @@ class _VideoDetailPageVState extends State if (!(mode == FullScreenMode.vertical || (mode == FullScreenMode.auto && isVertical) || (mode == FullScreenMode.ratio && - (isVertical || maxHeight / maxWidth < 1.25)))) { + (isVertical || maxHeight / maxWidth < kScreenRatio)))) { landscape(); } }); @@ -581,9 +581,7 @@ class _VideoDetailPageVState extends State if (shouldShow) AppBar( backgroundColor: themeData.colorScheme.surface - .withValues( - alpha: scrollRatio, - ), + .withValues(alpha: scrollRatio), toolbarHeight: 0, systemOverlayStyle: Platform.isAndroid ? SystemUiOverlayStyle( @@ -605,7 +603,7 @@ class _VideoDetailPageVState extends State onlyOneScrollInBody: true, pinnedHeaderSliverHeightBuilder: () { double pinnedHeight = this.isFullScreen || !isPortrait - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - padding.top : videoDetailController.isExpanding || videoDetailController.isCollapsing ? animHeight @@ -632,7 +630,7 @@ class _VideoDetailPageVState extends State }, headerSliverBuilder: (context, innerBoxIsScrolled) { final height = isFullScreen || !isPortrait - ? maxHeight - (isPortrait ? padding.top : 0) + ? maxHeight - padding.top : videoDetailController.isExpanding || videoDetailController.isCollapsing ? animHeight @@ -875,13 +873,10 @@ class _VideoDetailPageVState extends State final isFullScreen = this.isFullScreen; return Scaffold( resizeToAvoidBottomInset: false, - appBar: isFullScreen - ? null - : AppBar(backgroundColor: Colors.black, toolbarHeight: 0), - extendBodyBehindAppBar: true, + appBar: AppBar(backgroundColor: Colors.black, toolbarHeight: 0), body: Padding( padding: !isFullScreen - ? padding.copyWith(bottom: 0) + ? padding.copyWith(top: 0, bottom: 0) : EdgeInsets.zero, child: childWhenDisabledLandscapeInner(isFullScreen, padding), ), @@ -893,6 +888,7 @@ class _VideoDetailPageVState extends State final double videoHeight = maxHeight - padding.vertical; final double width = videoHeight * ratio; final videoWidth = isFullScreen ? maxWidth : width; + final introWidth = maxWidth - width - padding.horizontal; return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -907,7 +903,7 @@ class _VideoDetailPageVState extends State Offstage( offstage: isFullScreen, child: SizedBox( - width: maxWidth - width - padding.horizontal, + width: introWidth, height: maxHeight - padding.top, child: Scaffold( key: videoDetailController.childKey, @@ -922,7 +918,7 @@ class _VideoDetailPageVState extends State controller: videoDetailController.tabCtr, children: [ videoIntro( - width: maxWidth - width, + width: introWidth, height: maxHeight, ), if (videoDetailController.showReply) videoReplyPanel(), @@ -1010,7 +1006,7 @@ class _VideoDetailPageVState extends State } final videoWidth = isFullScreen ? maxWidth : width; final double height = width * 9 / 16; - final videoHeight = isFullScreen ? maxHeight : height; + final videoHeight = isFullScreen ? maxHeight - padding.top : height; if (height > maxHeight) { return childSplit(16 / 9); } @@ -1101,12 +1097,11 @@ class _VideoDetailPageVState extends State final isFullScreen = this.isFullScreen; return Scaffold( resizeToAvoidBottomInset: false, - appBar: isFullScreen - ? null - : AppBar(backgroundColor: Colors.black, toolbarHeight: 0), - extendBodyBehindAppBar: true, + appBar: AppBar(backgroundColor: Colors.black, toolbarHeight: 0), body: Padding( - padding: !isFullScreen ? padding.copyWith(bottom: 0) : EdgeInsets.zero, + padding: !isFullScreen + ? padding.copyWith(top: 0, bottom: 0) + : EdgeInsets.zero, child: childWhenDisabledAlmostSquareInner(isFullScreen, padding), ), ); @@ -1125,7 +1120,7 @@ class _VideoDetailPageVState extends State } final shouldShowSeasonPanel = _shouldShowSeasonPanel; final double height = maxHeight / 2.5; - final videoHeight = isFullScreen ? maxHeight : height; + final videoHeight = isFullScreen ? maxHeight - padding.top : height; final bottomHeight = maxHeight - height - padding.top; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -1376,7 +1371,7 @@ class _VideoDetailPageVState extends State child = plPlayer(width: maxWidth, height: maxHeight, isPipMode: true); } else if (!videoDetailController.horizontalScreen) { child = childWhenDisabled; - } else if (maxWidth > maxHeight * 1.25) { + } else if (maxWidth > maxHeight * kScreenRatio) { child = childWhenDisabledLandscape; } else if (maxWidth * (9 / 16) < (2 / 5) * maxHeight) { child = childWhenDisabled; @@ -1748,7 +1743,7 @@ class _VideoDetailPageVState extends State showEpisodes: showEpisodes, onShowMemberPage: onShowMemberPage, isPortrait: isPortrait, - isHorizontal: isHorizontal ?? width! > height! * 1.25, + isHorizontal: isHorizontal ?? width! > height! * kScreenRatio, ), if (needRelated && videoDetailController diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 3b409027..1255f2ff 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -1256,18 +1256,20 @@ class PlPlayerController { } await _videoPlayerController?.setRate(speed); - if (danmakuController != null) { - DanmakuOption currentOption = danmakuController!.option; - double defaultDuration = currentOption.duration * lastPlaybackSpeed; - double defaultStaticDuration = - currentOption.staticDuration * lastPlaybackSpeed; - DanmakuOption updatedOption = currentOption.copyWith( - duration: defaultDuration / speed, - staticDuration: defaultStaticDuration / speed, - ); - danmakuController!.updateOption(updatedOption); - } _playbackSpeed.value = speed; + if (danmakuController != null) { + try { + DanmakuOption currentOption = danmakuController!.option; + double defaultDuration = currentOption.duration * lastPlaybackSpeed; + double defaultStaticDuration = + currentOption.staticDuration * lastPlaybackSpeed; + DanmakuOption updatedOption = currentOption.copyWith( + duration: defaultDuration / speed, + staticDuration: defaultStaticDuration / speed, + ); + danmakuController!.updateOption(updatedOption); + } catch (_) {} + } } // 还原默认速度 @@ -1591,7 +1593,7 @@ class PlPlayerController { if ((mode == FullScreenMode.vertical || (mode == FullScreenMode.auto && isVertical) || (mode == FullScreenMode.ratio && - (isVertical || size.height / size.width < 1.25)))) { + (isVertical || size.height / size.width < kScreenRatio)))) { await verticalScreenForTwoSeconds(); } else { await landscape(); @@ -1740,10 +1742,10 @@ class PlPlayerController { } return; } + _playerCount = 0; disableAutoEnterPip(); setPlayCallBack(null); dmState.clear(); - _playerCount = 0; _clearPreview(); Utils.channel.setMethodCallHandler(null); _timer?.cancel(); diff --git a/lib/plugin/pl_player/models/fullscreen_mode.dart b/lib/plugin/pl_player/models/fullscreen_mode.dart index 31d0e147..3de8bb9f 100644 --- a/lib/plugin/pl_player/models/fullscreen_mode.dart +++ b/lib/plugin/pl_player/models/fullscreen_mode.dart @@ -1,3 +1,5 @@ +const double kScreenRatio = 1.2; + // 全屏模式 enum FullScreenMode { // 根据内容自适应 @@ -8,8 +10,8 @@ enum FullScreenMode { vertical('强制竖屏'), // 始终横屏 horizontal('强制横屏'), - // 屏幕长宽比<1.25或为竖屏视频时竖屏,否则横屏 - ratio('屏幕长宽比<1.25或为竖屏视频时竖屏,否则横屏'), + // 屏幕长宽比 < kScreenRatio 或为竖屏视频时竖屏,否则横屏 + ratio('屏幕长宽比<$kScreenRatio或为竖屏视频时竖屏,否则横屏'), // 强制重力转屏(仅安卓) gravity('忽略系统方向锁定,强制按重力转屏(仅安卓)'); diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 5d549436..94b117e4 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -1185,7 +1185,9 @@ class _PLVideoPlayerState extends State ) ..onLongPressStart = ((_) => plPlayerController.setLongPressStatus(true)) - ..onLongPressEnd = (_) => plPlayerController.setLongPressStatus(false); + ..onLongPressEnd = ((_) => plPlayerController.setLongPressStatus(false)) + ..onLongPressCancel = (() => + plPlayerController.setLongPressStatus(false)); late final OneSequenceGestureRecognizer _tapGestureRecognizer; late final DoubleTapGestureRecognizer _doubleTapGestureRecognizer; StreamSubscription? _danmakuListener;