diff --git a/lib/web_ui/lib/src/engine/display.dart b/lib/web_ui/lib/src/engine/display.dart index dd05733025aef..1264b49865b09 100644 --- a/lib/web_ui/lib/src/engine/display.dart +++ b/lib/web_ui/lib/src/engine/display.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:async'; + import 'package:ui/ui.dart' as ui; import '../engine.dart'; @@ -59,3 +61,76 @@ class EngineFlutterDisplay extends ui.Display { double? _debugDevicePixelRatioOverride; } + +/// Controls the screen orientation using the browser's screen orientation API. +class ScreenOrientation { + const ScreenOrientation(); + + static ScreenOrientation get instance => _instance; + static const ScreenOrientation _instance = ScreenOrientation(); + + static const String lockTypeAny = 'any'; + static const String lockTypeNatural = 'natural'; + static const String lockTypeLandscape = 'landscape'; + static const String lockTypePortrait = 'portrait'; + static const String lockTypePortraitPrimary = 'portrait-primary'; + static const String lockTypePortraitSecondary = 'portrait-secondary'; + static const String lockTypeLandscapePrimary = 'landscape-primary'; + static const String lockTypeLandscapeSecondary = 'landscape-secondary'; + + /// Sets preferred screen orientation. + /// + /// Specifies the set of orientations the application interface can be + /// displayed in. + /// + /// The [orientations] argument is a list of DeviceOrientation values. + /// The empty list uses Screen unlock api and causes the application to + /// defer to the operating system default. + /// + /// See w3c screen api: https://www.w3.org/TR/screen-orientation/ + Future setPreferredOrientation(List orientations) async { + final DomScreen? screen = domWindow.screen; + if (screen != null) { + final DomScreenOrientation? screenOrientation = screen.orientation; + if (screenOrientation != null) { + if (orientations.isEmpty) { + screenOrientation.unlock(); + return true; + } else { + final String? lockType = + _deviceOrientationToLockType(orientations.first as String?); + if (lockType != null) { + try { + await screenOrientation.lock(lockType); + return true; + } catch (_) { + // On Chrome desktop an error with 'not supported on this device + // error' is fired. + return Future.value(false); + } + } + } + } + } + // API is not supported on this browser return false. + return false; + } + + // Converts device orientation to w3c OrientationLockType enum. + // + // See also: https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/lock + static String? _deviceOrientationToLockType(String? deviceOrientation) { + switch (deviceOrientation) { + case 'DeviceOrientation.portraitUp': + return lockTypePortraitPrimary; + case 'DeviceOrientation.portraitDown': + return lockTypePortraitSecondary; + case 'DeviceOrientation.landscapeLeft': + return lockTypeLandscapePrimary; + case 'DeviceOrientation.landscapeRight': + return lockTypeLandscapeSecondary; + default: + return null; + } + } +} diff --git a/lib/web_ui/lib/src/engine/embedder.dart b/lib/web_ui/lib/src/engine/embedder.dart index 623d6aa9bdd1c..aced6b1ba0c84 100644 --- a/lib/web_ui/lib/src/engine/embedder.dart +++ b/lib/web_ui/lib/src/engine/embedder.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; - import 'package:ui/src/engine/safe_browser_api.dart'; import 'package:ui/ui.dart' as ui; @@ -288,78 +286,6 @@ class FlutterViewEmbedder { } } - static const String orientationLockTypeAny = 'any'; - static const String orientationLockTypeNatural = 'natural'; - static const String orientationLockTypeLandscape = 'landscape'; - static const String orientationLockTypePortrait = 'portrait'; - static const String orientationLockTypePortraitPrimary = 'portrait-primary'; - static const String orientationLockTypePortraitSecondary = - 'portrait-secondary'; - static const String orientationLockTypeLandscapePrimary = 'landscape-primary'; - static const String orientationLockTypeLandscapeSecondary = - 'landscape-secondary'; - - /// Sets preferred screen orientation. - /// - /// Specifies the set of orientations the application interface can be - /// displayed in. - /// - /// The [orientations] argument is a list of DeviceOrientation values. - /// The empty list uses Screen unlock api and causes the application to - /// defer to the operating system default. - /// - /// See w3c screen api: https://www.w3.org/TR/screen-orientation/ - Future setPreferredOrientation(List orientations) { - final DomScreen? screen = domWindow.screen; - if (screen != null) { - final DomScreenOrientation? screenOrientation = screen.orientation; - if (screenOrientation != null) { - if (orientations.isEmpty) { - screenOrientation.unlock(); - return Future.value(true); - } else { - final String? lockType = - _deviceOrientationToLockType(orientations.first as String?); - if (lockType != null) { - final Completer completer = Completer(); - try { - screenOrientation.lock(lockType).then((dynamic _) { - completer.complete(true); - }).catchError((dynamic error) { - // On Chrome desktop an error with 'not supported on this device - // error' is fired. - completer.complete(false); - }); - } catch (_) { - return Future.value(false); - } - return completer.future; - } - } - } - } - // API is not supported on this browser return false. - return Future.value(false); - } - - // Converts device orientation to w3c OrientationLockType enum. - // - // See also: https://developer.mozilla.org/en-US/docs/Web/API/ScreenOrientation/lock - static String? _deviceOrientationToLockType(String? deviceOrientation) { - switch (deviceOrientation) { - case 'DeviceOrientation.portraitUp': - return orientationLockTypePortraitPrimary; - case 'DeviceOrientation.portraitDown': - return orientationLockTypePortraitSecondary; - case 'DeviceOrientation.landscapeLeft': - return orientationLockTypeLandscapePrimary; - case 'DeviceOrientation.landscapeRight': - return orientationLockTypeLandscapeSecondary; - default: - return null; - } - } - /// Add an element as a global resource to be referenced by CSS. /// /// This call create a global resource host element on demand and either diff --git a/lib/web_ui/lib/src/engine/platform_dispatcher.dart b/lib/web_ui/lib/src/engine/platform_dispatcher.dart index 424346aafd548..e2ddae4ff0e0a 100644 --- a/lib/web_ui/lib/src/engine/platform_dispatcher.dart +++ b/lib/web_ui/lib/src/engine/platform_dispatcher.dart @@ -532,7 +532,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher { return; case 'SystemChrome.setPreferredOrientations': final List arguments = decoded.arguments as List; - flutterViewEmbedder.setPreferredOrientation(arguments).then((bool success) { + ScreenOrientation.instance.setPreferredOrientation(arguments).then((bool success) { replyToPlatformMessage( callback, codec.encodeSuccessEnvelope(success)); }); diff --git a/lib/web_ui/test/engine/window_test.dart b/lib/web_ui/test/engine/window_test.dart index df39afb17adde..ff93016a59056 100644 --- a/lib/web_ui/test/engine/window_test.dart +++ b/lib/web_ui/test/engine/window_test.dart @@ -358,25 +358,25 @@ Future testMain() async { unlockCount = 0; expect(await sendSetPreferredOrientations(['DeviceOrientation.portraitUp']), isTrue); - expect(lockCalls, [FlutterViewEmbedder.orientationLockTypePortraitPrimary]); + expect(lockCalls, [ScreenOrientation.lockTypePortraitPrimary]); expect(unlockCount, 0); lockCalls.clear(); unlockCount = 0; expect(await sendSetPreferredOrientations(['DeviceOrientation.portraitDown']), isTrue); - expect(lockCalls, [FlutterViewEmbedder.orientationLockTypePortraitSecondary]); + expect(lockCalls, [ScreenOrientation.lockTypePortraitSecondary]); expect(unlockCount, 0); lockCalls.clear(); unlockCount = 0; expect(await sendSetPreferredOrientations(['DeviceOrientation.landscapeLeft']), isTrue); - expect(lockCalls, [FlutterViewEmbedder.orientationLockTypeLandscapePrimary]); + expect(lockCalls, [ScreenOrientation.lockTypeLandscapePrimary]); expect(unlockCount, 0); lockCalls.clear(); unlockCount = 0; expect(await sendSetPreferredOrientations(['DeviceOrientation.landscapeRight']), isTrue); - expect(lockCalls, [FlutterViewEmbedder.orientationLockTypeLandscapeSecondary]); + expect(lockCalls, [ScreenOrientation.lockTypeLandscapeSecondary]); expect(unlockCount, 0); lockCalls.clear(); unlockCount = 0; @@ -389,7 +389,7 @@ Future testMain() async { simulateError = true; expect(await sendSetPreferredOrientations(['DeviceOrientation.portraitDown']), isFalse); - expect(lockCalls, [FlutterViewEmbedder.orientationLockTypePortraitSecondary]); + expect(lockCalls, [ScreenOrientation.lockTypePortraitSecondary]); expect(unlockCount, 0); js_util.setProperty(domWindow, 'screen', original);