[web] ScreenOrientation singleton (flutter/engine#45304)

One more piece moving out of `FlutterViewEmbedder`.

`ScreenOrientation` is a singleton class that can be used to control the screen orientation of the browser.

Part of https://github.com/flutter/flutter/issues/134443
This commit is contained in:
Mouad Debbar 2023-09-18 11:43:08 -04:00 committed by GitHub
parent 3ef852f5de
commit b470cd2ab1
4 changed files with 81 additions and 80 deletions

View File

@ -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<bool> setPreferredOrientation(List<dynamic> 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<bool>.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;
}
}
}

View File

@ -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<bool> setPreferredOrientation(List<dynamic> orientations) {
final DomScreen? screen = domWindow.screen;
if (screen != null) {
final DomScreenOrientation? screenOrientation = screen.orientation;
if (screenOrientation != null) {
if (orientations.isEmpty) {
screenOrientation.unlock();
return Future<bool>.value(true);
} else {
final String? lockType =
_deviceOrientationToLockType(orientations.first as String?);
if (lockType != null) {
final Completer<bool> completer = Completer<bool>();
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<bool>.value(false);
}
return completer.future;
}
}
}
}
// API is not supported on this browser return false.
return Future<bool>.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

View File

@ -532,7 +532,7 @@ class EnginePlatformDispatcher extends ui.PlatformDispatcher {
return;
case 'SystemChrome.setPreferredOrientations':
final List<dynamic> arguments = decoded.arguments as List<dynamic>;
flutterViewEmbedder.setPreferredOrientation(arguments).then((bool success) {
ScreenOrientation.instance.setPreferredOrientation(arguments).then((bool success) {
replyToPlatformMessage(
callback, codec.encodeSuccessEnvelope(success));
});

View File

@ -358,25 +358,25 @@ Future<void> testMain() async {
unlockCount = 0;
expect(await sendSetPreferredOrientations(<dynamic>['DeviceOrientation.portraitUp']), isTrue);
expect(lockCalls, <String>[FlutterViewEmbedder.orientationLockTypePortraitPrimary]);
expect(lockCalls, <String>[ScreenOrientation.lockTypePortraitPrimary]);
expect(unlockCount, 0);
lockCalls.clear();
unlockCount = 0;
expect(await sendSetPreferredOrientations(<dynamic>['DeviceOrientation.portraitDown']), isTrue);
expect(lockCalls, <String>[FlutterViewEmbedder.orientationLockTypePortraitSecondary]);
expect(lockCalls, <String>[ScreenOrientation.lockTypePortraitSecondary]);
expect(unlockCount, 0);
lockCalls.clear();
unlockCount = 0;
expect(await sendSetPreferredOrientations(<dynamic>['DeviceOrientation.landscapeLeft']), isTrue);
expect(lockCalls, <String>[FlutterViewEmbedder.orientationLockTypeLandscapePrimary]);
expect(lockCalls, <String>[ScreenOrientation.lockTypeLandscapePrimary]);
expect(unlockCount, 0);
lockCalls.clear();
unlockCount = 0;
expect(await sendSetPreferredOrientations(<dynamic>['DeviceOrientation.landscapeRight']), isTrue);
expect(lockCalls, <String>[FlutterViewEmbedder.orientationLockTypeLandscapeSecondary]);
expect(lockCalls, <String>[ScreenOrientation.lockTypeLandscapeSecondary]);
expect(unlockCount, 0);
lockCalls.clear();
unlockCount = 0;
@ -389,7 +389,7 @@ Future<void> testMain() async {
simulateError = true;
expect(await sendSetPreferredOrientations(<dynamic>['DeviceOrientation.portraitDown']), isFalse);
expect(lockCalls, <String>[FlutterViewEmbedder.orientationLockTypePortraitSecondary]);
expect(lockCalls, <String>[ScreenOrientation.lockTypePortraitSecondary]);
expect(unlockCount, 0);
js_util.setProperty(domWindow, 'screen', original);