Closes #1680

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-10-24 12:12:56 +08:00
parent bbcf0dec1b
commit 4256c2b023
5 changed files with 98 additions and 149 deletions

View File

@@ -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<LiveRoomPage>
);
}
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<SystemUiOverlayStyle>(
value: _systemOverlayStyleForBrightness(
Brightness.dark,
Theme.of(context).useMaterial3 ? const Color(0x00000000) : null,
),
child: ColoredBox(
color: Colors.black,
child: Stack(
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<LiveRoomPage>
);
},
),
if (isPortrait)
Obx(
Scaffold(
backgroundColor: Colors.transparent,
appBar: _buildAppBar(isFullScreen),
body: isPortrait
? Obx(
() {
if (_liveRoomController.isPortrait.value) {
return _buildPP;
return _buildPP(isFullScreen);
}
return _buildPH;
return _buildPH(isFullScreen);
},
)
else
_buildBodyH,
: _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<LiveRoomPage>
);
}
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<LiveRoomPage>
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<LiveRoomPage>
);
}
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,34 +640,24 @@ class _LiveRoomPageState extends State<LiveRoomPage>
);
}
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,
),
Expanded(
child: Padding(
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(
margin: EdgeInsets.only(bottom: padding.bottom),
width: width,
height: height,
margin: EdgeInsets.only(bottom: padding.bottom),
child: videoPlayerPanel(
isFullScreen,
fill: Colors.transparent,
@@ -722,11 +675,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
),
],
),
),
),
],
);
},
);
}

View File

@@ -181,7 +181,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
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<VideoDetailPageV>
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<VideoDetailPageV>
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<VideoDetailPageV>
},
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<VideoDetailPageV>
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<VideoDetailPageV>
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<VideoDetailPageV>
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<VideoDetailPageV>
controller: videoDetailController.tabCtr,
children: [
videoIntro(
width: maxWidth - width,
width: introWidth,
height: maxHeight,
),
if (videoDetailController.showReply) videoReplyPanel(),
@@ -1010,7 +1006,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
}
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<VideoDetailPageV>
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<VideoDetailPageV>
}
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<VideoDetailPageV>
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<VideoDetailPageV>
showEpisodes: showEpisodes,
onShowMemberPage: onShowMemberPage,
isPortrait: isPortrait,
isHorizontal: isHorizontal ?? width! > height! * 1.25,
isHorizontal: isHorizontal ?? width! > height! * kScreenRatio,
),
if (needRelated &&
videoDetailController

View File

@@ -1256,7 +1256,9 @@ class PlPlayerController {
}
await _videoPlayerController?.setRate(speed);
_playbackSpeed.value = speed;
if (danmakuController != null) {
try {
DanmakuOption currentOption = danmakuController!.option;
double defaultDuration = currentOption.duration * lastPlaybackSpeed;
double defaultStaticDuration =
@@ -1266,8 +1268,8 @@ class PlPlayerController {
staticDuration: defaultStaticDuration / speed,
);
danmakuController!.updateOption(updatedOption);
} catch (_) {}
}
_playbackSpeed.value = speed;
}
// 还原默认速度
@@ -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();

View File

@@ -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('忽略系统方向锁定,强制按重力转屏(仅安卓)');

View File

@@ -1185,7 +1185,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
)
..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<bool>? _danmakuListener;