From a4f780b7b8acdb0612fdb4e3849275680ab591c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Mon, 4 Oct 2021 16:40:06 +0200 Subject: [PATCH] MOBILE-3103 iframe: Manage orientation on iframes fullscreen --- package-lock.json | 22 +++--------- package.json | 4 +-- src/addons/mod/scorm/pages/player/player.html | 2 +- src/app/app.component.ts | 1 - src/core/components/iframe/iframe.ts | 20 +++++++++-- ...een-viewport.ts => watch-screen-status.ts} | 2 ++ src/core/services/screen.ts | 35 +++++++++++++++++++ src/core/singletons/events.ts | 9 +++++ 8 files changed, 70 insertions(+), 25 deletions(-) rename src/core/initializers/{watch-screen-viewport.ts => watch-screen-status.ts} (95%) diff --git a/package-lock.json b/package-lock.json index e781ced49..1310a5e2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -77,7 +77,6 @@ "cordova-plugin-media-capture": "^3.0.3", "cordova-plugin-network-information": "^2.0.2", "cordova-plugin-prevent-override": "^1.0.0", - "cordova-plugin-screen-orientation": "^3.0.2", "cordova-plugin-splashscreen": "^6.0.0", "cordova-plugin-statusbar": "^2.4.3", "cordova-plugin-whitelist": "^1.3.4", @@ -11201,18 +11200,6 @@ } } }, - "node_modules/cordova-plugin-screen-orientation": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cordova-plugin-screen-orientation/-/cordova-plugin-screen-orientation-3.0.2.tgz", - "integrity": "sha512-2w6CMC+HGvbhogJetalwGurL2Fx8DQCCPy3wlSZHN1/W7WoQ5n9ujVozcoKrY4VaagK6bxrPFih+ElkO8Uqfzg==", - "engines": { - "cordovaDependencies": { - "4.0.0": { - "cordova": ">100" - } - } - } - }, "node_modules/cordova-plugin-splashscreen": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.0.tgz", @@ -12799,6 +12786,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "devOptional": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -12807,6 +12795,7 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "devOptional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -39888,11 +39877,6 @@ "resolved": "https://registry.npmjs.org/cordova-plugin-prevent-override/-/cordova-plugin-prevent-override-1.0.0.tgz", "integrity": "sha512-/+3q5r4K5RahCpiYVmZQBjq10x4jj+6CMjYtZyx9jdMWeV+yFE+ItFcO1NeUAEWd2iHC5YPD0P2tHiHx5kscsw==" }, - "cordova-plugin-screen-orientation": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cordova-plugin-screen-orientation/-/cordova-plugin-screen-orientation-3.0.2.tgz", - "integrity": "sha512-2w6CMC+HGvbhogJetalwGurL2Fx8DQCCPy3wlSZHN1/W7WoQ5n9ujVozcoKrY4VaagK6bxrPFih+ElkO8Uqfzg==" - }, "cordova-plugin-splashscreen": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.0.tgz", @@ -41147,6 +41131,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "devOptional": true, "requires": { "iconv-lite": "^0.6.2" }, @@ -41155,6 +41140,7 @@ "version": "0.6.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "devOptional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } diff --git a/package.json b/package.json index cc8e30643..bff141856 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,6 @@ "cordova-plugin-media-capture": "^3.0.3", "cordova-plugin-network-information": "^2.0.2", "cordova-plugin-prevent-override": "^1.0.0", - "cordova-plugin-screen-orientation": "^3.0.2", "cordova-plugin-splashscreen": "^6.0.0", "cordova-plugin-statusbar": "^2.4.3", "cordova-plugin-whitelist": "^1.3.4", @@ -217,7 +216,6 @@ }, "cordova-plugin-network-information": {}, "@moodlehq/cordova-plugin-qrscanner": {}, - "cordova-plugin-screen-orientation": {}, "cordova-plugin-splashscreen": {}, "cordova-plugin-statusbar": {}, "cordova-plugin-whitelist": {}, @@ -247,4 +245,4 @@ "optionalDependencies": { "keytar": "^7.2.0" } -} +} \ No newline at end of file diff --git a/src/addons/mod/scorm/pages/player/player.html b/src/addons/mod/scorm/pages/player/player.html index a2074e95b..02e55ff42 100644 --- a/src/addons/mod/scorm/pages/player/player.html +++ b/src/addons/mod/scorm/pages/player/player.html @@ -22,7 +22,7 @@ + [showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="true">

{{ errorMessage | translate }}

diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 038345fff..4701e426f 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -63,7 +63,6 @@ export class AppComponent implements OnInit, AfterViewInit { * - IAB events listening. * - Platform pause/resume subscriptions. * - handleOpenURL and openWindowSafely. - * - Screen orientation events (probably it can be removed). * - Back button registering to close modal first. * - Note: HideKeyboardFormAccessoryBar has been moved to config.xml. */ diff --git a/src/core/components/iframe/iframe.ts b/src/core/components/iframe/iframe.ts index 4d733438b..bf57b1443 100644 --- a/src/core/components/iframe/iframe.ts +++ b/src/core/components/iframe/iframe.ts @@ -22,7 +22,9 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreIframeUtils } from '@services/utils/iframe'; import { CoreUtils } from '@services/utils/utils'; -import { DomSanitizer } from '@singletons'; +import { DomSanitizer, StatusBar } from '@singletons'; +import { CoreEventObserver, CoreEvents } from '@singletons/events'; +import { CoreScreen, CoreScreenOrientation } from '@services/screen'; @Component({ selector: 'core-iframe', @@ -39,6 +41,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { @Input() iframeHeight?: string; @Input() allowFullscreen?: boolean | string; @Input() showFullscreenOnToolbar?: boolean | string; + @Input() autoFullscreenOnRotate?: boolean | string; @Output() loaded: EventEmitter = new EventEmitter(); loading?: boolean; @@ -49,6 +52,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { initialized = false; protected style?: HTMLStyleElement; + protected orientationObs?: CoreEventObserver; constructor() { this.loaded = new EventEmitter(); @@ -73,14 +77,23 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { this.iframeHeight = (this.iframeHeight && CoreDomUtils.formatPixelsSize(this.iframeHeight)) || '100%'; this.allowFullscreen = CoreUtils.isTrueOrOne(this.allowFullscreen); this.showFullscreenOnToolbar = CoreUtils.isTrueOrOne(this.showFullscreenOnToolbar); + this.autoFullscreenOnRotate = CoreUtils.isTrueOrOne(this.autoFullscreenOnRotate); - if (this.showFullscreenOnToolbar) { + if (this.showFullscreenOnToolbar || this.autoFullscreenOnRotate) { const shadow = iframe.closest('.ion-page')?.querySelector('ion-header ion-toolbar')?.shadowRoot; if (shadow) { this.style = document.createElement('style'); shadow.appendChild(this.style); } + + if (this.autoFullscreenOnRotate) { + this.toggleFullscreen(CoreScreen.isLandscape); + + this.orientationObs = CoreEvents.on(CoreEvents.ORIENTATION_CHANGE, (data) => { + this.toggleFullscreen(data.orientation == CoreScreenOrientation.LANDSCAPE); + }); + } } // Show loading only with external URLs. @@ -136,6 +149,7 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { */ ngOnDestroy(): void { this.toggleFullscreen(false); + this.orientationObs?.off(); } /** @@ -148,6 +162,8 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { this.fullscreen = !this.fullscreen; } + this.fullscreen ? StatusBar.hide() : StatusBar.show(); + if (this.style) { // Done this way because of the shadow DOM. this.style.textContent = this.fullscreen diff --git a/src/core/initializers/watch-screen-viewport.ts b/src/core/initializers/watch-screen-status.ts similarity index 95% rename from src/core/initializers/watch-screen-viewport.ts rename to src/core/initializers/watch-screen-status.ts index 23e1210b0..ee4d5fcf1 100644 --- a/src/core/initializers/watch-screen-viewport.ts +++ b/src/core/initializers/watch-screen-status.ts @@ -16,4 +16,6 @@ import { CoreScreen } from '@services/screen'; export default function(): void { CoreScreen.watchViewport(); + + CoreScreen.watchOrientation(); } diff --git a/src/core/services/screen.ts b/src/core/services/screen.ts index b53dcbcb7..6228f7700 100644 --- a/src/core/services/screen.ts +++ b/src/core/services/screen.ts @@ -17,6 +17,7 @@ import { BehaviorSubject, Observable } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs/operators'; import { makeSingleton } from '@singletons'; +import { CoreEvents } from '@singletons/events'; /** * Screen breakpoints. @@ -48,6 +49,14 @@ export enum CoreScreenLayout { TABLET = 'tablet', } +/** + * Screen orientation. + */ +export enum CoreScreenOrientation { + LANDSCAPE = 'landscape', + PORTRAIT = 'portrait', +} + /** * Manage application screen. */ @@ -93,6 +102,32 @@ export class CoreScreenService { return this.layout === CoreScreenLayout.TABLET; } + get orientation(): CoreScreenOrientation { + const mql = window.matchMedia('(orientation: portrait)'); + + return mql.matches ? CoreScreenOrientation.PORTRAIT : CoreScreenOrientation.LANDSCAPE; + } + + get isPortrait(): boolean { + return this.orientation === CoreScreenOrientation.PORTRAIT; + } + + get isLandscape(): boolean { + return this.orientation === CoreScreenOrientation.LANDSCAPE; + } + + /** + * Watch orientation changes. + */ + watchOrientation(): void { + // Listen media orientation CSS queries. + window.matchMedia('(orientation: portrait)').addEventListener('change', (m) => { + const orientation = m.matches ? CoreScreenOrientation.PORTRAIT : CoreScreenOrientation.LANDSCAPE; + + CoreEvents.trigger(CoreEvents.ORIENTATION_CHANGE, { orientation }); + }); + } + /** * Watch viewport changes. */ diff --git a/src/core/singletons/events.ts b/src/core/singletons/events.ts index 0c622f77b..49aa650a5 100644 --- a/src/core/singletons/events.ts +++ b/src/core/singletons/events.ts @@ -19,6 +19,7 @@ import { CoreSite, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from '@c import { CoreFilepoolComponentFileEventData } from '@services/filepool'; import { CoreNavigationOptions } from '@services/navigator'; import { CoreCourseModuleCompletionData } from '@features/course/services/course-helper'; +import { CoreScreenOrientation } from '@services/screen'; /** * Observer instance to stop listening to an event. @@ -55,6 +56,7 @@ export interface CoreEventsData { [CoreEvents.COMPONENT_FILE_ACTION]: CoreFilepoolComponentFileEventData; [CoreEvents.FILE_SHARED]: CoreEventFileSharedData; [CoreEvents.APP_LAUNCHED_URL]: CoreEventAppLaunchedData; + [CoreEvents.ORIENTATION_CHANGE]: CoreEventOrientationData; } /* @@ -387,3 +389,10 @@ export type CoreEventFileSharedData = { export type CoreEventAppLaunchedData = { url: string; }; + +/** + * Data passed to ORIENTATION_CHANGE event. + */ +export type CoreEventOrientationData = { + orientation: CoreScreenOrientation; +};