Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-04-24 10:48:51 +08:00
parent 490a08fa79
commit 73484f1f72
4 changed files with 273 additions and 236 deletions

View File

@@ -984,6 +984,7 @@ class _InheritedResetNotifier extends InheritedNotifier<_ResetNotifier> {
required _ResetNotifier super.notifier,
});
// ignore: unused_element
bool _sendReset() => notifier!.sendReset();
/// Specifies whether the [DraggableScrollableSheet] should reset to its

View File

@@ -168,21 +168,55 @@ class VideoDetailController extends GetxController
late final scrollKey = GlobalKey<ExtendedNestedScrollViewState>();
late final RxBool isVertical;
late final RxDouble scrollRatio = 0.0.obs;
ScrollController? _scrollCtr;
ScrollController get scrollCtr =>
_scrollCtr ??= ScrollController()..addListener(scrollListener);
late bool isExpanding = false;
late bool isCollapsing = false;
AnimationController? animController;
AnimationController get animationController =>
animController ??= AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
);
late double minVideoHeight;
late double maxVideoHeight;
late double videoHeight;
late double animHeight;
AnimationController? animController;
AnimationController get animationController =>
animController ??= (AnimationController(
vsync: this,
duration: const Duration(milliseconds: 200),
)..addListener(_animListener));
void refreshPage() {
if (scrollKey.currentState?.mounted ?? false) {
(scrollKey.currentState!.context as Element).markNeedsBuild();
}
}
void _animListener() {
if (animationController.isForwardOrCompleted) {
_calcAnimHeight();
refreshPage();
}
}
void _calcAnimHeight() {
if (isExpanding) {
animHeight = clampDouble(
videoHeight * animationController.value,
kToolbarHeight,
videoHeight,
);
} else if (isCollapsing) {
animHeight = clampDouble(
maxVideoHeight -
(maxVideoHeight - minVideoHeight) * animationController.value,
minVideoHeight,
maxVideoHeight,
);
}
}
void animToTop() {
final outerController = scrollKey.currentState!.outerController;
@@ -195,8 +229,18 @@ class VideoDetailController extends GetxController
}
}
bool _needAnimOnDimensionChanged(bool isVertical) {
if (isFullScreen) {
if (PlatformUtils.isMobile) {
plPlayerController.changeOrientation(isVertical: isVertical);
}
return false;
}
return true;
}
@pragma('vm:notify-debugger-on-exception')
void setVideoHeight() {
void _setVideoHeight() {
try {
var width = firstVideo.width;
var height = firstVideo.height;
@@ -205,10 +249,11 @@ class VideoDetailController extends GetxController
final ugcIntroCtr = Get.find<UgcIntroController>(tag: heroTag);
final data = ugcIntroCtr.videoDetail.value;
if (data.cid == cid.value) {
width = data.dimension!.width!;
height = data.dimension!.height!;
final dimension = data.dimension!;
width = dimension.width!;
height = dimension.height!;
} else {
ugcIntroCtr.queryVideoIntro().whenComplete(setVideoHeight);
ugcIntroCtr.queryVideoIntro().whenComplete(_setVideoHeight);
return;
}
} else {
@@ -227,10 +272,12 @@ class VideoDetailController extends GetxController
if (this.videoHeight != videoHeight) {
if (videoHeight > this.videoHeight) {
// current minVideoHeight
if (_needAnimOnDimensionChanged(isVertical)) {
isExpanding = true;
animationController.forward(
from: (minVideoHeight - scrollCtr.offset) / maxVideoHeight,
);
}
this.videoHeight = maxVideoHeight;
} else {
// current maxVideoHeight
@@ -238,20 +285,28 @@ class VideoDetailController extends GetxController
.toPrecision(2);
double minVideoHeightPrecise = minVideoHeight.toPrecision(2);
if (currentHeight == minVideoHeightPrecise) {
if (_needAnimOnDimensionChanged(isVertical)) {
isExpanding = true;
this.videoHeight = minVideoHeight;
}
animationController.forward(from: 1);
} else if (currentHeight < minVideoHeightPrecise) {
// expand
if (_needAnimOnDimensionChanged(isVertical)) {
isExpanding = true;
animationController.forward(from: currentHeight / minVideoHeight);
animationController.forward(
from: currentHeight / minVideoHeight,
);
}
this.videoHeight = minVideoHeight;
} else {
// collapse
if (_needAnimOnDimensionChanged(isVertical)) {
isCollapsing = true;
animationController.forward(
from: scrollCtr.offset / (maxVideoHeight - minVideoHeight),
);
}
this.videoHeight = minVideoHeight;
}
}
@@ -313,7 +368,7 @@ class VideoDetailController extends GetxController
defaultST = Duration.zero;
}
data = PlayUrlModel(timeLength: entry.totalTimeMilli);
setVideoHeight();
_setVideoHeight();
}
@override
@@ -844,7 +899,7 @@ class VideoDetailController extends GetxController
codecs: 'avc1',
quality: videoQuality,
);
setVideoHeight();
_setVideoHeight();
currentDecodeFormats = VideoDecodeFormatType.fromString('avc1');
currentVideoQa.value = videoQuality;
await _initPlayerIfNeeded(autoFullScreenFlag);
@@ -856,7 +911,7 @@ class VideoDetailController extends GetxController
_autoPlay.value = false;
videoState.value = false;
if (plPlayerController.isFullScreen.value) {
plPlayerController.toggleFullScreen(false);
plPlayerController.triggerFullScreen(status: false);
}
isQuerying = false;
return;
@@ -918,7 +973,7 @@ class VideoDetailController extends GetxController
(e) => currentDecodeFormats.codes.any(e.codecs!.startsWith),
orElse: () => videosList.first,
);
setVideoHeight();
_setVideoHeight();
videoUrl = VideoUtils.getCdnUrl(firstVideo.playUrls);
@@ -951,8 +1006,9 @@ class VideoDetailController extends GetxController
_autoPlay.value = false;
videoState.value = false;
if (plPlayerController.isFullScreen.value) {
plPlayerController.toggleFullScreen(false);
plPlayerController.triggerFullScreen(status: false);
}
result.toast();
}
isQuerying = false;
}
@@ -1217,7 +1273,9 @@ class VideoDetailController extends GetxController
_scrollCtr
?..removeListener(scrollListener)
..dispose();
animController?.dispose();
animController
?..removeListener(_animListener)
..dispose();
subtitles.clear();
vttSubtitles.clear();
super.onClose();

View File

@@ -219,10 +219,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.videoHeight,
);
} else {
refreshPage();
videoDetailController.refreshPage();
}
} else {
refreshPage();
videoDetailController.refreshPage();
}
}
} catch (e) {
@@ -326,8 +326,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
?..removeStatusLister(playerListener)
..removePositionListener(positionListener);
videoDetailController.animController?.removeListener(animListener);
Get.delete<HorizontalMemberPageController>(
tag: videoDetailController.heroTag,
);
@@ -480,48 +478,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
: Theme.of(context);
}
void animListener() {
if (videoDetailController.animationController.isForwardOrCompleted) {
cal();
refreshPage();
}
}
late double animHeight;
void cal() {
if (videoDetailController.isExpanding) {
animHeight = clampDouble(
videoDetailController.videoHeight *
videoDetailController.animationController.value,
kToolbarHeight,
videoDetailController.videoHeight,
);
} else if (videoDetailController.isCollapsing) {
animHeight = clampDouble(
videoDetailController.maxVideoHeight -
(videoDetailController.maxVideoHeight -
videoDetailController.minVideoHeight) *
videoDetailController.animationController.value,
videoDetailController.minVideoHeight,
videoDetailController.maxVideoHeight,
);
}
}
void refreshPage() {
if (videoDetailController.scrollKey.currentState?.mounted == true) {
videoDetailController.scrollKey.currentState?.setState(() {});
}
}
bool get removeAppBar =>
videoDetailController.removeSafeArea || (isFullScreen && !isPortrait);
Widget get childWhenDisabled {
videoDetailController.animationController
..removeListener(animListener)
..addListener(animListener);
return Obx(
() {
final isFullScreen = this.isFullScreen;
@@ -570,7 +530,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
? maxHeight - (isPortrait ? padding.top : 0)
: videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
? videoDetailController.animHeight
: videoDetailController.isCollapsing ||
(plPlayerController?.playerStatus.isPlaying ?? false)
? videoDetailController.minVideoHeight
@@ -580,13 +540,13 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.isExpanding = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
videoDetailController.scrollRatio.value = 0;
refreshPage();
videoDetailController.refreshPage();
});
} else if (videoDetailController.isCollapsing &&
videoDetailController.animationController.value == 1) {
videoDetailController.isCollapsing = false;
WidgetsBinding.instance.addPostFrameCallback((_) {
refreshPage();
videoDetailController.refreshPage();
});
}
return pinnedHeight;
@@ -596,7 +556,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
? maxHeight - (isPortrait ? padding.top : 0)
: videoDetailController.isExpanding ||
videoDetailController.isCollapsing
? animHeight
? videoDetailController.animHeight
: videoDetailController.videoHeight;
return [
SliverPinnedDynamicHeader(
@@ -833,10 +793,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
? null
: AppBar(backgroundColor: Colors.black, toolbarHeight: 0),
body: Padding(
padding: !isFullScreen
? padding.copyWith(top: 0, bottom: 0)
: EdgeInsets.zero,
child: childWhenDisabledLandscapeInner(isFullScreen, padding),
padding: isFullScreen
? EdgeInsets.zero
: padding.copyWith(top: 0, bottom: 0),
child: childWhenDisabledLandscapeInner(isFullScreen),
),
);
},
@@ -893,13 +853,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
);
}
Widget childWhenDisabledLandscapeInner(
bool isFullScreen,
EdgeInsets padding,
) => Obx(() {
if (videoDetailController.isVertical.value &&
enableVerticalExpand &&
!isPortrait) {
Widget childWhenDisabledLandscapeInner(bool isFullScreen) {
if (enableVerticalExpand) {
return Obx(() {
if (videoDetailController.isVertical.value && !isPortrait) {
final double videoHeight = maxHeight - padding.vertical;
final double width = videoHeight / Style.aspectRatio16x9;
final videoWidth = isFullScreen ? maxWidth : width;
@@ -957,6 +914,14 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
],
);
}
return _childWhenDisabledLandscapeInner(isFullScreen);
});
}
return _childWhenDisabledLandscapeInner(isFullScreen);
}
Widget _childWhenDisabledLandscapeInner(bool isFullScreen) {
double width =
clampDouble(maxHeight / maxWidth * 1.08, 0.5, 0.7) * maxWidth;
if (maxWidth >= 560) {
@@ -1053,7 +1018,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
),
],
);
});
}
Widget get childWhenDisabledAlmostSquare => Obx(() {
final isFullScreen = this.isFullScreen;
@@ -1063,25 +1028,31 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
? null
: AppBar(backgroundColor: Colors.black, toolbarHeight: 0),
body: Padding(
padding: !isFullScreen
? padding.copyWith(top: 0, bottom: 0)
: EdgeInsets.zero,
child: childWhenDisabledAlmostSquareInner(isFullScreen, padding),
padding: isFullScreen
? EdgeInsets.zero
: padding.copyWith(top: 0, bottom: 0),
child: childWhenDisabledAlmostSquareInner(isFullScreen),
),
);
});
Widget childWhenDisabledAlmostSquareInner(
bool isFullScreen,
EdgeInsets padding,
) => Obx(
Widget childWhenDisabledAlmostSquareInner(bool isFullScreen) {
if (enableVerticalExpand) {
return Obx(
() {
final isFullScreen = this.isFullScreen;
if (videoDetailController.isVertical.value &&
enableVerticalExpand &&
!isPortrait) {
if (videoDetailController.isVertical.value && !isPortrait) {
return childSplit(9 / 16);
}
return _childWhenDisabledAlmostSquareInner(isFullScreen);
},
);
}
return _childWhenDisabledAlmostSquareInner(isFullScreen);
}
Widget _childWhenDisabledAlmostSquareInner(bool isFullScreen) {
final shouldShowSeasonPanel = _shouldShowSeasonPanel;
final double height = maxHeight / 2.5;
final videoHeight = isFullScreen
@@ -1129,8 +1100,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
),
if (videoDetailController.showReply)
Expanded(child: videoReplyPanel()),
if (shouldShowSeasonPanel)
Expanded(child: seasonPanel),
if (shouldShowSeasonPanel) Expanded(child: seasonPanel),
],
),
),
@@ -1141,8 +1111,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
),
],
);
},
);
}
Widget get manualPlayerWidget => Obx(() {
if (!videoDetailController.autoPlay) {

View File

@@ -1415,7 +1415,7 @@ class PlPlayerController with BlockConfigMixin {
controls = !val;
}
void toggleFullScreen(bool val) {
void _setFullScreen(bool val) {
isFullScreen.value = val;
updateSubtitleStyle();
}
@@ -1426,6 +1426,37 @@ class PlPlayerController with BlockConfigMixin {
late final horizontalScreen = Pref.horizontalScreen;
late final removeSafeArea = Pref.removeSafeArea;
Future<void>? changeOrientation({
required bool isVertical,
DeviceOrientation? orientation,
}) {
if (orientation == null && (mode == .none || mode == .gravity)) {
return null;
}
if (orientation == null &&
(mode == .vertical ||
(mode == .auto && isVertical) ||
(mode == .ratio && (isVertical || screenRatio < kScreenRatio)))) {
return portraitUpMode();
} else {
// https://github.com/flutter/flutter/issues/73651
// https://github.com/flutter/flutter/issues/183708
if (Platform.isAndroid) {
if ((orientation ?? _orientation) == .landscapeRight) {
return landscapeRightMode();
} else {
return landscapeLeftMode();
}
} else {
if (orientation == .landscapeLeft) {
return landscapeLeftMode();
} else {
return landscapeRightMode();
}
}
}
}
// 全屏
bool _fsProcessing = false;
Future<void> triggerFullScreen({
@@ -1439,38 +1470,15 @@ class PlPlayerController with BlockConfigMixin {
if (_fsProcessing) return;
_fsProcessing = true;
toggleFullScreen(status);
this.isManualFS = isManualFS;
try {
if (status) {
if (PlatformUtils.isMobile) {
hideStatusBar();
if (orientation == null && mode == .none) {
return;
}
if (orientation == null &&
(mode == .vertical ||
(mode == .auto && isVertical) ||
(mode == .ratio &&
(isVertical || screenRatio < kScreenRatio)))) {
await portraitUpMode();
} else {
// https://github.com/flutter/flutter/issues/73651
// https://github.com/flutter/flutter/issues/183708
if (Platform.isAndroid) {
if ((orientation ?? _orientation) == .landscapeRight) {
await landscapeRightMode();
} else {
await landscapeLeftMode();
}
} else {
if (orientation == .landscapeLeft) {
await landscapeLeftMode();
} else {
await landscapeRightMode();
}
}
}
await changeOrientation(
isVertical: isVertical,
orientation: orientation,
);
} else {
await enterDesktopFullScreen(inAppFullScreen: inAppFullScreen);
}
@@ -1502,6 +1510,7 @@ class PlPlayerController with BlockConfigMixin {
}
}
} finally {
_setFullScreen(status);
_fsProcessing = false;
}
}