Phones were locked to portrait outside the video player, and the mobile shell had no answer for a wide, short viewport: car head units (which use the mobile layout) and tablets in landscape spent their scarce height on a bottom navigation bar and a 500dp hero. In landscape the mobile shell now puts the bottom bar's destinations on a leading Material NavigationRail (MobileNavigationRail) and keeps every other mobile layout decision as it is. The rail keeps the bottom bar's extras: the offline reconnect affordance as its leading action and the long-press library quick picker on the Libraries destination. Labels follow the existing nav-bar-labels setting but give way automatically when the destinations cannot fit (a landscape phone is ~410dp tall), and the rail scrolls as a last resort. The content beside it drops the leading system inset the rail already absorbs. Phones now allow every orientation; OrientationHelper.restoreDefaultOrientations is context-free and the player exit path uses it instead of its own copy of the phone lock. The Discover hero fills the viewport in mobile landscape and compacts its logo and bottom offset when short, so its content stays below the top bar. The music mini-player learns a start inset (MiniPlayerInsetController.setNavInsets) so it floats beside the rail in landscape and above the bar in portrait; route suspension zeroes both. Known follow-up: the media detail header is not yet laid out for a landscape phone (logo runs under the status bar and back button).
36 lines
1.6 KiB
Dart
36 lines
1.6 KiB
Dart
import 'package:flutter/services.dart';
|
|
import 'platform_detector.dart';
|
|
|
|
class OrientationHelper {
|
|
/// Restores the app's default orientation preferences: every orientation
|
|
/// on every handheld. Phones rotate into the landscape shell (leading
|
|
/// navigation rail) like tablets do; the video player owns its own lock.
|
|
///
|
|
/// This should be called when leaving full-screen experiences like
|
|
/// the video player to restore the app's default orientation behavior.
|
|
static Future<void> restoreDefaultOrientations() async {
|
|
// Cars are fixed-orientation devices; asking would only pin a compact
|
|
// head unit that reads as a phone.
|
|
if (PlatformDetector.isAutomotive()) return;
|
|
await SystemChrome.setPreferredOrientations(DeviceOrientation.values);
|
|
}
|
|
|
|
/// Sets orientation to landscape-only mode.
|
|
///
|
|
/// Used by the video player to force landscape orientation during playback.
|
|
static void setLandscapeOrientation() {
|
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
|
if (PlatformDetector.isAutomotive()) return;
|
|
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
|
|
}
|
|
|
|
/// Restores the app's default visible system UI mode.
|
|
///
|
|
/// Should be called when exiting full-screen mode.
|
|
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);
|
|
}
|
|
}
|