MOBILE-3103 iframe: Manage orientation on iframes fullscreen

main
Pau Ferrer Ocaña 2021-10-04 16:40:06 +02:00
parent d8cc67eab1
commit a4f780b7b8
8 changed files with 70 additions and 25 deletions

22
package-lock.json generated
View File

@ -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"
}

View File

@ -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"
}
}
}

View File

@ -22,7 +22,7 @@
<core-navigation-bar [previous]="previousSco" [next]="nextSco" (action)="loadSco($event)"></core-navigation-bar>
<core-iframe *ngIf="loaded && src" [src]="src" [iframeWidth]="scormWidth" [iframeHeight]="scormHeight"
[showFullscreenOnToolbar]="true">
[showFullscreenOnToolbar]="true" [autoFullscreenOnRotate]="true">
</core-iframe>
<p *ngIf="!src && errorMessage">{{ errorMessage | translate }}</p>

View File

@ -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.
*/

View File

@ -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<HTMLIFrameElement> = new EventEmitter<HTMLIFrameElement>();
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<HTMLIFrameElement>();
@ -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

View File

@ -16,4 +16,6 @@ import { CoreScreen } from '@services/screen';
export default function(): void {
CoreScreen.watchViewport();
CoreScreen.watchOrientation();
}

View File

@ -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.
*/

View File

@ -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;
};