Merge pull request #2562 from dpalou/MOBILE-3523

Mobile 3523
main
Juan Leyva 2020-10-16 13:13:28 +02:00 committed by GitHub
commit 3a27eda256
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 154 additions and 128 deletions

View File

@ -47,96 +47,96 @@
"windows.store": "npx electron-windows-store --input-directory .\\desktop\\dist\\win-unpacked --output-directory .\\desktop\\store -a .\\resources\\desktop -m .\\desktop\\assets\\windows\\AppXManifest.xml --package-version 0.0.0.0 --package-name MoodleDesktop"
},
"dependencies": {
"@angular/animations": "^5.2.11",
"@angular/common": "^5.2.11",
"@angular/compiler": "^5.2.11",
"@angular/compiler-cli": "^5.2.11",
"@angular/core": "^5.2.11",
"@angular/forms": "^5.2.11",
"@angular/platform-browser": "^5.2.11",
"@angular/platform-browser-dynamic": "^5.2.11",
"@ionic-native/badge": "^4.20.0",
"@ionic-native/camera": "^4.20.0",
"@ionic-native/chooser": "^4.20.0",
"@ionic-native/clipboard": "^4.20.0",
"@ionic-native/core": "^4.20.0",
"@ionic-native/device": "^4.20.0",
"@ionic-native/diagnostic": "^4.2.0",
"@ionic-native/file": "^4.20.0",
"@ionic-native/file-opener": "^4.20.0",
"@ionic-native/file-transfer": "^4.20.0",
"@ionic-native/geolocation": "^4.20.0",
"@ionic-native/globalization": "^4.20.0",
"@ionic-native/http": "^4.20.0",
"@ionic-native/in-app-browser": "^4.20.0",
"@ionic-native/keyboard": "^4.20.0",
"@ionic-native/local-notifications": "^4.20.0",
"@ionic-native/media": "^4.20.0",
"@ionic-native/media-capture": "^4.20.0",
"@ionic-native/network": "^4.20.0",
"@ionic-native/push": "^4.20.0",
"@ionic-native/qr-scanner": "^4.20.0",
"@ionic-native/screen-orientation": "^4.20.0",
"@ionic-native/splash-screen": "^4.20.0",
"@ionic-native/sqlite": "^4.20.0",
"@ionic-native/status-bar": "^4.20.0",
"@ionic-native/web-intent": "^4.20.0",
"@ionic-native/zip": "^4.20.0",
"@ngx-translate/core": "^8.0.0",
"@ngx-translate/http-loader": "^2.0.1",
"ajv": "^6.11.0",
"chart.js": "^2.9.3",
"com-darryncampbell-cordova-plugin-intent": "^1.3.0",
"cordova": "^10.0.0",
"cordova-android": "^8.1.0",
"cordova-android-support-gradle-release": "^3.0.1",
"cordova-clipboard": "^1.3.0",
"cordova-ios": "^5.1.1",
"cordova-plugin-advanced-http": "^2.4.1",
"cordova-plugin-badge": "^0.8.8",
"cordova-plugin-camera": "^4.1.0",
"cordova-plugin-chooser": "^1.3.2",
"cordova-plugin-customurlscheme": "^5.0.1",
"cordova-plugin-device": "^2.0.3",
"cordova-plugin-file": "^6.0.2",
"cordova-plugin-file-opener2": "^3.0.4",
"cordova-plugin-file-transfer": "^1.7.1",
"@angular/animations": "5.2.11",
"@angular/common": "5.2.11",
"@angular/compiler": "5.2.11",
"@angular/compiler-cli": "5.2.11",
"@angular/core": "5.2.11",
"@angular/forms": "5.2.11",
"@angular/platform-browser": "5.2.11",
"@angular/platform-browser-dynamic": "5.2.11",
"@ionic-native/badge": "4.20.0",
"@ionic-native/camera": "4.20.0",
"@ionic-native/chooser": "4.20.0",
"@ionic-native/clipboard": "4.20.0",
"@ionic-native/core": "4.20.0",
"@ionic-native/device": "4.20.0",
"@ionic-native/diagnostic": "4.2.0",
"@ionic-native/file": "4.20.0",
"@ionic-native/file-opener": "4.20.0",
"@ionic-native/file-transfer": "4.20.0",
"@ionic-native/geolocation": "4.20.0",
"@ionic-native/globalization": "4.20.0",
"@ionic-native/http": "4.20.0",
"@ionic-native/in-app-browser": "4.20.0",
"@ionic-native/keyboard": "4.20.0",
"@ionic-native/local-notifications": "4.20.0",
"@ionic-native/media": "4.20.0",
"@ionic-native/media-capture": "4.20.0",
"@ionic-native/network": "4.20.0",
"@ionic-native/push": "4.20.0",
"@ionic-native/qr-scanner": "4.20.0",
"@ionic-native/screen-orientation": "4.20.0",
"@ionic-native/splash-screen": "4.20.0",
"@ionic-native/sqlite": "4.20.0",
"@ionic-native/status-bar": "4.20.0",
"@ionic-native/web-intent": "4.20.0",
"@ionic-native/zip": "4.20.0",
"@ngx-translate/core": "8.0.0",
"@ngx-translate/http-loader": "2.0.1",
"ajv": "6.11.0",
"chart.js": "2.9.3",
"com-darryncampbell-cordova-plugin-intent": "1.3.0",
"cordova": "10.0.0",
"cordova-android": "8.1.0",
"cordova-android-support-gradle-release": "3.0.1",
"cordova-clipboard": "1.3.0",
"cordova-ios": "5.1.1",
"cordova-plugin-advanced-http": "2.4.1",
"cordova-plugin-badge": "0.8.8",
"cordova-plugin-camera": "4.1.0",
"cordova-plugin-chooser": "1.3.2",
"cordova-plugin-customurlscheme": "5.0.1",
"cordova-plugin-device": "2.0.3",
"cordova-plugin-file": "6.0.2",
"cordova-plugin-file-opener2": "3.0.4",
"cordova-plugin-file-transfer": "1.7.1",
"cordova-plugin-geolocation": "git+https://github.com/apache/cordova-plugin-geolocation.git#89cf51d222e8f225bdfb661965b3007d669c40ff",
"cordova-plugin-globalization": "^1.11.0",
"cordova-plugin-globalization": "1.11.0",
"cordova-plugin-inappbrowser": "git+https://github.com/moodlemobile/cordova-plugin-inappbrowser.git#moodle",
"cordova-plugin-ionic-keyboard": "2.1.3",
"cordova-plugin-ionic-webview": "git+https://github.com/moodlemobile/cordova-plugin-ionic-webview.git#500-moodle",
"cordova-plugin-local-notification": "git+https://github.com/moodlemobile/cordova-plugin-local-notification.git#moodle",
"cordova-plugin-media": "^5.0.3",
"cordova-plugin-media-capture": "^3.0.3",
"cordova-plugin-network-information": "^2.0.2",
"cordova-plugin-media": "5.0.3",
"cordova-plugin-media-capture": "3.0.3",
"cordova-plugin-network-information": "2.0.2",
"cordova-plugin-qrscanner": "git+https://github.com/moodlemobile/cordova-plugin-qrscanner.git#dist",
"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",
"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",
"cordova-plugin-wkuserscript": "git+https://github.com/moodlemobile/cordova-plugin-wkuserscript.git",
"cordova-plugin-wkwebview-cookies": "git+https://github.com/moodlemobile/cordova-plugin-wkwebview-cookies.git",
"cordova-plugin-zip": "^3.1.0",
"cordova-sqlite-storage": "^4.0.0",
"cordova-support-google-services": "^1.3.2",
"es6-promise-plugin": "^4.2.2",
"font-awesome": "^4.7.0",
"cordova-plugin-zip": "3.1.0",
"cordova-sqlite-storage": "4.0.0",
"cordova-support-google-services": "1.3.2",
"es6-promise-plugin": "4.2.2",
"font-awesome": "4.7.0",
"inquirer": "^7.3.2",
"ionic-angular": "3.9.9",
"ionicons": "3.0.0",
"jszip": "^3.1.5",
"jszip": "3.1.5",
"mathjax": "2.7.7",
"moment": "^2.24.0",
"nl.kingsquare.cordova.background-audio": "^1.0.1",
"phonegap-plugin-multidex": "^1.0.0",
"moment": "2.24.0",
"nl.kingsquare.cordova.background-audio": "1.0.1",
"phonegap-plugin-multidex": "1.0.0",
"phonegap-plugin-push": "git+https://github.com/moodlemobile/phonegap-plugin-push.git#moodle-v3",
"promise.prototype.finally": "3.1.0",
"rxjs": "^5.5.12",
"sw-toolbox": "^3.6.0",
"ts-md5": "^1.2.7",
"web-animations-js": "^2.3.2",
"zone.js": "^0.8.29"
"rxjs": "5.5.12",
"sw-toolbox": "3.6.0",
"ts-md5": "1.2.7",
"web-animations-js": "2.3.2",
"zone.js": "0.8.29"
},
"devDependencies": {
"@ionic/app-scripts": "3.2.3",

View File

@ -24,9 +24,6 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url';
import { CoreIframeUtilsProvider } from '@providers/utils/iframe';
import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreSplitViewComponent } from '@components/split-view/split-view';
import { CoreUrl } from '@singletons/url';
import { CoreApp } from '@providers/app';
import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
@Component({
selector: 'core-iframe',
@ -107,24 +104,7 @@ export class CoreIframeComponent implements OnChanges {
if (changes.src) {
const url = this.urlUtils.getYoutubeEmbedUrl(changes.src.currentValue) || changes.src.currentValue;
if (CoreApp.instance.isIOS() && url && !this.urlUtils.isLocalFileUrl(url)) {
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
try {
const win = <WKWebViewCookiesWindow> window;
const urlParts = CoreUrl.parse(url);
if (urlParts.domain) {
await win.WKWebViewCookies.setCookie({
name: 'MoodleAppCookieForWKWebView',
value: '1',
domain: urlParts.domain,
});
}
} catch (err) {
// Ignore errors.
this.logger.error('Error setting cookie', err);
}
}
await this.iframeUtils.fixIframeCookies(url);
this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(CoreFile.instance.convertFileSrc(url));

View File

@ -191,7 +191,7 @@ export class CoreContentLinksDelegate {
// Add them to the list.
linkActions.push({
priority: handler.priority,
priority: handler.priority || 0,
actions: actions
});
}

View File

@ -405,7 +405,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate {
promises.push(Promise.resolve(getFunction.call(handler, injector, course)).then((data) => {
handlersToDisplay.push({
data: data,
priority: handler.priority,
priority: handler.priority || 0,
prefetch: handler.prefetch && handler.prefetch.bind(handler),
name: handler.name
});

View File

@ -15,6 +15,7 @@
import { Component, Input, Output, EventEmitter, ViewChild, ElementRef, AfterContentInit, OnDestroy, Optional }
from '@angular/core';
import { TextInput, Content, Platform, Slides } from 'ionic-angular';
import { Device } from '@ionic-native/device';
import { CoreApp } from '@providers/app';
import { CoreSitesProvider } from '@providers/sites';
import { CoreFilepoolProvider } from '@providers/filepool';
@ -118,7 +119,8 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
protected events: CoreEventsProvider,
protected utils: CoreUtilsProvider,
protected platform: Platform,
protected editorOffline: CoreEditorOfflineProvider) {
protected editorOffline: CoreEditorOfflineProvider,
protected device: Device) {
this.contentChanged = new EventEmitter<string>();
this.element = elementRef.nativeElement as HTMLDivElement;
this.pageInstance = 'app_' + Date.now(); // Generate a "unique" ID based on timestamp.
@ -236,7 +238,7 @@ export class CoreEditorRichTextEditorComponent implements AfterContentInit, OnDe
if (CoreApp.instance.isAndroid()) {
// In Android we ignore the keyboard height because it is not part of the web view.
height = this.domUtils.getContentHeight(this.content) - this.getSurroundingHeight(this.element);
} else if (CoreApp.instance.isIOS() && this.kbHeight > 0 && this.platform.version().major < 12) {
} else if (CoreApp.instance.isIOS() && this.kbHeight > 0 && Number(this.device.version.split('.')[0]) < 12) {
// Keyboard open in iOS 11 or previous. The window height changes when the keyboard is open.
height = window.innerHeight - this.getSurroundingHeight(this.element);

View File

@ -177,7 +177,7 @@ export class CoreFileUploaderDelegate extends CoreDelegate {
}
const data: CoreFileUploaderHandlerDataToReturn = handler.getData();
data.priority = handler.priority;
data.priority = handler.priority || 0;
data.mimetypes = supportedMimetypes;
handlers.push(data);
}

View File

@ -44,8 +44,7 @@ export class CoreFileUploaderFileHandler implements CoreFileUploaderHandler {
* @return True or promise resolved with true if enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return CoreApp.instance.isAndroid() || !CoreApp.instance.isMobile() ||
(CoreApp.instance.isIOS() && this.platform.version().major >= 9);
return true;
}
/**

View File

@ -46,6 +46,7 @@ export class CoreMainMenuPage implements OnDestroy {
protected urlToOpen: string;
protected mainMenuId: number;
protected keyboardObserver: any;
protected resizeFunction;
@ViewChild('mainTabs') mainTabs: CoreIonTabsComponent;
@ -115,7 +116,8 @@ export class CoreMainMenuPage implements OnDestroy {
}
});
window.addEventListener('resize', this.initHandlers.bind(this));
this.resizeFunction = this.initHandlers.bind(this);
window.addEventListener('resize', this.resizeFunction);
if (CoreApp.instance.isIOS()) {
// In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
@ -241,7 +243,7 @@ export class CoreMainMenuPage implements OnDestroy {
ngOnDestroy(): void {
this.subscription && this.subscription.unsubscribe();
this.redirectObs && this.redirectObs.off();
window.removeEventListener('resize', this.initHandlers.bind(this));
window.removeEventListener('resize', this.resizeFunction);
CoreApp.instance.setMainMenuOpen(this.mainMenuId, false);
this.keyboardObserver && this.keyboardObserver.off();
}

View File

@ -162,7 +162,7 @@ export class CoreMainMenuDelegate extends CoreDelegate {
handlersData.push({
name: name,
data: data,
priority: handler.priority
priority: handler.priority || 0,
});
}

View File

@ -177,6 +177,7 @@ export class CorePushNotificationsDelegate {
this.logger.log(`Registered addon '${handler.name}'`);
this.clickHandlers[handler.name] = handler;
handler.priority = handler.priority || 0;
return true;
}

View File

@ -108,7 +108,7 @@ export class CoreSettingsDelegate extends CoreDelegate {
handlersData.push({
data: data,
priority: handler.priority
priority: handler.priority || 0,
});
}

View File

@ -35,7 +35,7 @@ export class CoreSitePluginsCourseOptionHandler extends CoreSitePluginsBaseHandl
protected utils: CoreUtilsProvider) {
super(name);
this.priority = handlerSchema.priority;
this.priority = handlerSchema.priority || 0;
this.isMenuHandler = !!handlerSchema.ismenuhandler;
}

View File

@ -25,7 +25,7 @@ export class CoreSitePluginsMainMenuHandler extends CoreSitePluginsBaseHandler i
protected initResult: any) {
super(name);
this.priority = handlerSchema.priority;
this.priority = handlerSchema.priority || 0;
}
/**

View File

@ -32,7 +32,7 @@ export class CoreSitePluginsMessageOutputHandler extends CoreSitePluginsBaseHand
*/
getDisplayData(): AddonMessageOutputHandlerData {
return {
priority: this.handlerSchema.priority,
priority: this.handlerSchema.priority || 0,
label: this.title,
icon: this.handlerSchema.displaydata.icon,
page: 'CoreSitePluginsPluginPage',

View File

@ -25,7 +25,7 @@ export class CoreSitePluginsSettingsHandler extends CoreSitePluginsBaseHandler i
protected initResult: any) {
super(name);
this.priority = handlerSchema.priority;
this.priority = handlerSchema.priority || 0;
}
/**

View File

@ -43,7 +43,7 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
protected utils: CoreUtilsProvider) {
super(name);
this.priority = handlerSchema.priority;
this.priority = handlerSchema.priority || 0;
// Only support TYPE_COMMUNICATION and TYPE_NEW_PAGE.
this.type = handlerSchema.type != CoreUserDelegate.TYPE_COMMUNICATION ?

View File

@ -260,7 +260,7 @@ export class CoreUserDelegate extends CoreDelegate {
userData.handlers.push({
name: name,
data: handler.getDisplayData(user, courseId),
priority: handler.priority,
priority: handler.priority || 0,
type: handler.type || CoreUserDelegate.TYPE_NEW_PAGE
});
}

View File

@ -450,6 +450,7 @@ export class CoreFormatTextDirective implements OnChanges {
const div = document.createElement('div'),
canTreatVimeo = site && site.isVersionGreaterEqualThan(['3.3.4', '3.4']),
navCtrl = this.svComponent ? this.svComponent.getMasterNav() : this.navCtrl;
const promises = [];
div.innerHTML = formatted;
@ -504,7 +505,7 @@ export class CoreFormatTextDirective implements OnChanges {
});
iframes.forEach((iframe) => {
this.treatIframe(iframe, site, canTreatVimeo, navCtrl);
promises.push(this.treatIframe(iframe, site, canTreatVimeo, navCtrl));
});
svgImages.forEach((image) => {
@ -543,10 +544,9 @@ export class CoreFormatTextDirective implements OnChanges {
this.domUtils.handleBootstrapTooltips(div);
// Wait for images to load.
let promise: Promise<any> = null;
if (externalImages.length) {
// Automatically reject the promise after 5 seconds to prevent blocking the user forever.
promise = this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => {
promises.push(this.utils.timeoutPromise(this.utils.allPromises(externalImages.map((externalImage): any => {
if (externalImage.loaded) {
// Image has already been loaded, no need to wait.
return Promise.resolve();
@ -558,12 +558,10 @@ export class CoreFormatTextDirective implements OnChanges {
resolve();
});
});
})), 5000);
} else {
promise = Promise.resolve();
})), 5000));
}
return promise.catch(() => {
return Promise.all(promises).catch(() => {
// Ignore errors. So content gets always shown.
}).then(() => {
result.div = div;
@ -665,7 +663,8 @@ export class CoreFormatTextDirective implements OnChanges {
* @param canTreatVimeo Whether Vimeo videos can be treated in the site.
* @param navCtrl NavController to use.
*/
protected treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController): void {
protected async treatIframe(iframe: HTMLIFrameElement, site: CoreSite, canTreatVimeo: boolean, navCtrl: NavController)
: Promise<void> {
const src = iframe.src,
currentSite = this.sitesProvider.getCurrentSite();
@ -673,15 +672,19 @@ export class CoreFormatTextDirective implements OnChanges {
if (currentSite && currentSite.containsUrl(src)) {
// URL points to current site, try to use auto-login.
currentSite.getAutoLoginUrl(src, false).then((finalUrl) => {
const finalUrl = await currentSite.getAutoLoginUrl(src, false);
await this.iframeUtils.fixIframeCookies(finalUrl);
iframe.src = finalUrl;
this.iframeUtils.treatFrame(iframe, false, navCtrl);
});
return;
}
await this.iframeUtils.fixIframeCookies(src);
if (src && canTreatVimeo) {
// Check if it's a Vimeo video. If it is, use the wsplayer script instead to make restricted videos work.
const matches = iframe.src.match(/https?:\/\/player\.vimeo\.com\/video\/([0-9]+)/);
@ -714,6 +717,9 @@ export class CoreFormatTextDirective implements OnChanges {
if (site && !site.isVersionGreaterEqualThan('3.7')) {
newUrl += '&width=' + width + '&height=' + height;
}
await this.iframeUtils.fixIframeCookies(newUrl);
iframe.src = newUrl;
if (!iframe.width) {

View File

@ -1549,11 +1549,16 @@ export class CoreSitesProvider {
await this.dbReady;
const site = await this.getSite(siteId);
const newValues = {
token: '', // Erase the token for security.
const newValues: any = {
loggedOut: loggedOut ? 1 : 0
};
if (loggedOut) {
// Erase the token for security.
newValues.token = '';
site.token = '';
}
site.setLoggedOut(loggedOut);
return this.appDB.updateRecords(CoreSitesProvider.SITES_TABLE, newValues, { id: siteId });

View File

@ -30,6 +30,7 @@ import { makeSingleton } from '@singletons/core.singletons';
import { CoreUrl } from '@singletons/url';
import { CoreWindow } from '@singletons/window';
import { WKUserScriptWindow, WKUserScriptInjectionTime } from 'cordova-plugin-wkuserscript';
import { WKWebViewCookiesWindow } from 'cordova-plugin-wkwebview-cookies';
/*
* "Utils" service with helper functions for iframes, embed and similar.
@ -488,6 +489,36 @@ export class CoreIframeUtilsProvider {
}
}
}
/**
* Fix cookies for an iframe URL.
*
* @param url URL of the iframe.
* @return Promise resolved when done.
*/
async fixIframeCookies(url: string): Promise<void> {
if (!CoreApp.instance.isIOS() || !url || this.urlUtils.isLocalFileUrl(url)) {
// No need to fix cookies.
return;
}
// Save a "fake" cookie for the iframe's domain to fix a bug in WKWebView.
try {
const win = <WKWebViewCookiesWindow> window;
const urlParts = CoreUrl.parse(url);
if (urlParts.domain) {
await win.WKWebViewCookies.setCookie({
name: 'MoodleAppCookieForWKWebView',
value: '1',
domain: urlParts.domain,
});
}
} catch (err) {
// Ignore errors.
this.logger.error('Error setting cookie', err);
}
}
}
export class CoreIframeUtils extends makeSingleton(CoreIframeUtilsProvider) {}