refactor device orientation

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-04-06 15:16:21 +08:00
parent db74eccf77
commit 3097b56816
16 changed files with 218 additions and 264 deletions

View File

@@ -56,6 +56,7 @@ import 'package:get/get.dart';
import 'package:hive_ce/hive.dart';
import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart';
import 'package:native_device_orientation/native_device_orientation.dart';
import 'package:path/path.dart' as path;
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:window_manager/window_manager.dart';
@@ -513,26 +514,68 @@ class PlPlayerController with BlockConfigMixin {
Box video = GStorage.video;
bool visible = true;
StreamSubscription<NativeDeviceOrientation>? _orientationListener;
void _stopOrientationListener() {
_orientationListener?.cancel();
_orientationListener = null;
}
void _onOrientationChanged(NativeDeviceOrientation value) {
if (!visible) return;
switch (value) {
case .portraitUp:
if (!_isVertical && controlsLock.value) return;
if (!horizontalScreen && !_isVertical && isFullScreen.value) {
triggerFullScreen(status: false, orientation: value);
} else {
portraitUpMode();
}
case .landscapeLeft:
if (!horizontalScreen && !isFullScreen.value) {
triggerFullScreen(orientation: value);
} else {
landscapeLeftMode();
}
case .landscapeRight:
if (!horizontalScreen && !isFullScreen.value) {
triggerFullScreen(orientation: value);
} else {
landscapeRightMode();
}
case _:
}
}
// 添加一个私有构造函数
PlPlayerController._() {
if (PlatformUtils.isMobile) {
_orientationListener = NativeDeviceOrientationPlatform.instance
.onOrientationChanged(
useSensor: Platform.isAndroid,
checkIsAutoRotate: mode != .gravity,
)
.listen(_onOrientationChanged);
}
if (!Accounts.heartbeat.isLogin || Pref.historyPause) {
enableHeart = false;
}
if (Platform.isAndroid && autoPiP) {
Utils.sdkInt.then((sdkInt) {
if (sdkInt < 36) {
Utils.channel.setMethodCallHandler((call) async {
if (call.method == 'onUserLeaveHint') {
if (playerStatus.isPlaying && _isCurrVideoPage) {
enterPip();
}
if (Utils.sdkInt < 36) {
Utils.channel.setMethodCallHandler((call) async {
if (call.method == 'onUserLeaveHint') {
if (playerStatus.isPlaying && _isCurrVideoPage) {
enterPip();
}
});
} else {
_shouldSetPip = true;
}
});
}
});
} else {
_shouldSetPip = true;
}
}
}
@@ -1360,69 +1403,71 @@ class PlPlayerController with BlockConfigMixin {
updateSubtitleStyle();
}
late bool isManualFS = true;
double screenRatio = 0.0;
late final FullScreenMode mode = Pref.fullScreenMode;
late final horizontalScreen = Pref.horizontalScreen;
// 全屏
bool fsProcessing = false;
bool _fsProcessing = false;
Future<void> triggerFullScreen({
bool status = true,
bool inAppFullScreen = false,
bool isManualFS = true,
FullScreenMode? mode,
NativeDeviceOrientation? orientation,
}) async {
if (isDesktopPip) return;
if (isFullScreen.value == status) return;
if (fsProcessing) {
return;
}
fsProcessing = true;
if (_fsProcessing) return;
_fsProcessing = true;
toggleFullScreen(status);
try {
mode ??= this.mode;
this.isManualFS = isManualFS;
if (status) {
if (PlatformUtils.isMobile) {
hideStatusBar();
if (mode == FullScreenMode.none) {
if (orientation == null && mode == .none) {
return;
}
if (mode == FullScreenMode.gravity) {
await fullAutoModeForceSensor();
return;
}
late final size = MediaQuery.sizeOf(Get.context!);
if ((mode == FullScreenMode.vertical ||
(mode == FullScreenMode.auto && isVertical) ||
(mode == FullScreenMode.ratio &&
(isVertical || size.height / size.width < kScreenRatio)))) {
await verticalScreenForTwoSeconds();
if (orientation == null &&
(mode == .vertical ||
(mode == .auto && isVertical) ||
(mode == .ratio &&
(isVertical || screenRatio < kScreenRatio)))) {
await portraitUpMode();
} else {
await landscape();
// https://github.com/flutter/flutter/issues/73651
// https://github.com/flutter/flutter/issues/183708
if (Platform.isAndroid) {
if (orientation == .landscapeRight) {
await landscapeRightMode();
} else {
await landscapeLeftMode();
}
} else {
if (orientation == .landscapeLeft) {
await landscapeLeftMode();
} else {
await landscapeRightMode();
}
}
}
} else {
await enterDesktopFullscreen(inAppFullScreen: inAppFullScreen);
await enterDesktopFullScreen(inAppFullScreen: inAppFullScreen);
}
} else {
if (PlatformUtils.isMobile) {
showStatusBar();
if (mode == FullScreenMode.none) {
if (orientation == null && mode == .none) {
return;
}
if (!horizontalScreen) {
await verticalScreenForTwoSeconds();
} else {
await autoScreen();
await portraitUpMode();
}
} else {
await exitDesktopFullscreen();
await exitDesktopFullScreen();
}
}
} finally {
fsProcessing = false;
_fsProcessing = false;
}
}
@@ -1520,12 +1565,29 @@ class PlPlayerController with BlockConfigMixin {
});
}
bool isCloseAll = false;
bool _isCloseAll = false;
bool get isCloseAll => _isCloseAll;
void resetScreenRotation() {
if (horizontalScreen) {
fullMode();
} else {
portraitUpMode();
}
}
void onCloseAll() {
_isCloseAll = true;
dispose();
Get.until((route) => route.isFirst);
}
void dispose() {
// 每次减1最后销毁
resetScreenRotation();
cancelLongPressTimer();
_cancelSubForSeek();
if (!isCloseAll && _playerCount > 1) {
if (!_isCloseAll && _playerCount > 1) {
_playerCount -= 1;
_heartDuration = 0;
if (!_isPreviousVideoPage) {
@@ -1536,6 +1598,7 @@ class PlPlayerController with BlockConfigMixin {
_playerCount = 0;
danmakuController = null;
_stopOrientationListener();
_disableAutoEnterPip();
setPlayCallBack(null);
dmState.clear();
@@ -1683,25 +1746,27 @@ class PlPlayerController with BlockConfigMixin {
});
}
bool onPopInvokedWithResult(bool didPop, Object? result) {
void onPopInvokedWithResult(bool didPop, Object? result, bool isPortrait) {
if (didPop) {
if (Platform.isAndroid) {
_disableAutoEnterPipIfNeeded();
}
return true;
return;
}
if (controlsLock.value) {
onLockControl(false);
return true;
return;
}
if (isDesktopPip) {
exitDesktopPip();
return true;
return;
}
if (isFullScreen.value) {
triggerFullScreen(status: false);
return true;
return;
}
if (!horizontalScreen && !isPortrait) {
Get.back();
}
return false;
}
}

View File

@@ -1,16 +1,14 @@
import 'dart:async';
import 'dart:io';
import 'dart:io' show Platform;
import 'package:PiliPlus/utils/platform_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/services.dart';
import 'package:flutter/services.dart'
show SystemChrome, MethodChannel, SystemUiOverlay, DeviceOrientation;
bool _isDesktopFullScreen = false;
@pragma('vm:notify-debugger-on-exception')
Future<void> enterDesktopFullscreen({bool inAppFullScreen = false}) async {
Future<void> enterDesktopFullScreen({bool inAppFullScreen = false}) async {
if (!inAppFullScreen && !_isDesktopFullScreen) {
_isDesktopFullScreen = true;
try {
@@ -22,7 +20,7 @@ Future<void> enterDesktopFullscreen({bool inAppFullScreen = false}) async {
}
@pragma('vm:notify-debugger-on-exception')
Future<void> exitDesktopFullscreen() async {
Future<void> exitDesktopFullScreen() async {
if (_isDesktopFullScreen) {
_isDesktopFullScreen = false;
try {
@@ -33,60 +31,50 @@ Future<void> exitDesktopFullscreen() async {
}
}
//横屏
@pragma('vm:notify-debugger-on-exception')
Future<void> landscape() async {
try {
await AutoOrientation.landscapeAutoMode(forceSensor: true);
} catch (_) {}
}
//竖屏
Future<void> verticalScreenForTwoSeconds() async {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
await autoScreen();
}
//全向
bool allowRotateScreen = Pref.allowRotateScreen;
Future<void> autoScreen() async {
if (PlatformUtils.isMobile && allowRotateScreen) {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
// DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
List<DeviceOrientation>? _lastOrientation;
Future<void>? _setPreferredOrientations(List<DeviceOrientation> orientations) {
if (_lastOrientation == orientations) {
return null;
}
_lastOrientation = orientations;
return SystemChrome.setPreferredOrientations(orientations);
}
Future<void> fullAutoModeForceSensor() {
return AutoOrientation.fullAutoMode(forceSensor: true);
Future<void>? portraitUpMode() {
return _setPreferredOrientations(const [.portraitUp]);
}
Future<void>? landscapeLeftMode() {
return _setPreferredOrientations(const [.landscapeLeft]);
}
Future<void>? landscapeRightMode() {
return _setPreferredOrientations(const [.landscapeRight]);
}
Future<void>? fullMode() {
return _setPreferredOrientations(
const [.portraitUp, .landscapeLeft, .landscapeRight],
);
}
bool _showStatusBar = true;
Future<void> hideStatusBar() async {
Future<void>? hideStatusBar() {
if (!_showStatusBar) {
return;
return null;
}
_showStatusBar = false;
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
return SystemChrome.setEnabledSystemUIMode(.immersiveSticky);
}
//退出全屏显示
Future<void> showStatusBar() async {
Future<void>? showStatusBar() {
if (_showStatusBar) {
return;
return null;
}
_showStatusBar = true;
SystemUiMode mode;
if (Platform.isAndroid && (await Utils.sdkInt < 29)) {
mode = SystemUiMode.manual;
} else {
mode = SystemUiMode.edgeToEdge;
}
await SystemChrome.setEnabledSystemUIMode(
mode,
return SystemChrome.setEnabledSystemUIMode(
Platform.isAndroid && Utils.sdkInt < 29 ? .manual : .edgeToEdge,
overlays: SystemUiOverlay.values,
);
}

View File

@@ -300,10 +300,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
void didChangeAppLifecycleState(AppLifecycleState state) {
if (!plPlayerController.continuePlayInBackground.value) {
late final player = plPlayerController.videoPlayerController;
if (const [
AppLifecycleState.paused,
AppLifecycleState.detached,
].contains(state)) {
if (const <AppLifecycleState>[.paused, .detached].contains(state)) {
if (player != null && player.state.playing) {
_pauseDueToPauseUponEnteringBackgroundMode = true;
player.pause();