fix(playback): restore system ui after video

close #1152
This commit is contained in:
edde746
2026-05-27 06:52:03 +02:00
parent e45bfadc14
commit 08a806e457
3 changed files with 63 additions and 20 deletions
+26 -17
View File
@@ -998,6 +998,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
if (navigator.canPop()) {
_isExiting.value = true;
await _sendStoppedProgressOnce();
await _restoreSystemUiAndOrientation();
if (!mounted) return;
navigator.pop(true);
}
@@ -1012,6 +1013,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
if (navigator.canPop()) {
_isExiting.value = true;
await _sendStoppedProgressOnce();
await _restoreSystemUiAndOrientation();
if (!mounted) return;
navigator.pop(true);
}
@@ -1020,6 +1022,29 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
}
}
Future<void> _restoreSystemUiAndOrientation() async {
try {
await OrientationHelper.restoreSystemUI();
} catch (e) {
appLogger.w('Failed to restore system UI', error: e);
}
try {
if (_isPhone) {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
} else {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
} catch (e) {
appLogger.w('Failed to restore orientation', error: e);
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
@@ -1128,23 +1153,7 @@ class VideoPlayerScreenState extends State<VideoPlayerScreen> with WidgetsBindin
// Restore system UI and orientation preferences (skip if navigating to another video)
if (!_isReplacingWithVideo) {
OrientationHelper.restoreSystemUI();
// Restore orientation based on cached device type (no context needed)
try {
if (_isPhone) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
} else {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
} catch (e) {
appLogger.w('Failed to restore orientation in dispose', error: e);
}
unawaited(_restoreSystemUiAndOrientation());
}
Sentry.addBreadcrumb(Breadcrumb(message: 'Player dispose', category: 'player'));
+5 -3
View File
@@ -33,10 +33,12 @@ class OrientationHelper {
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
}
/// Restores edge-to-edge system UI mode.
/// Restores the app's default visible system UI mode.
///
/// Should be called when exiting full-screen mode.
static void restoreSystemUI() {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
static Future<void> restoreSystemUI() async {
// Explicitly show both overlays first to clear any legacy immersive flags.
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
}
}
+32
View File
@@ -0,0 +1,32 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:plezy/utils/orientation_helper.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('restoreSystemUI explicitly shows overlays before edge-to-edge', () async {
final calls = <MethodCall>[];
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
(call) async {
calls.add(call);
return null;
},
);
addTearDown(
() => TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(
SystemChannels.platform,
null,
),
);
await OrientationHelper.restoreSystemUI();
expect(calls, hasLength(2));
expect(calls[0].method, 'SystemChrome.setEnabledSystemUIOverlays');
expect(calls[0].arguments, ['SystemUiOverlay.top', 'SystemUiOverlay.bottom']);
expect(calls[1].method, 'SystemChrome.setEnabledSystemUIMode');
expect(calls[1].arguments, 'SystemUiMode.edgeToEdge');
});
}