diff --git a/config.xml b/config.xml index 4bab48e5452..9b72ead21be 100644 --- a/config.xml +++ b/config.xml @@ -1,5 +1,5 @@ - + Moodle Moodle official app Moodle Mobile team @@ -27,7 +27,7 @@ - + @@ -251,7 +251,7 @@ - 4.0.0 + 4.0.1 diff --git a/moodle.config.json b/moodle.config.json index 7e690774913..a5f1ca6b624 100644 --- a/moodle.config.json +++ b/moodle.config.json @@ -1,8 +1,8 @@ { "app_id": "com.moodle.moodlemobile", "appname": "Moodle Mobile", - "versioncode": 40000, - "versionname": "4.0.0", + "versioncode": 40100, + "versionname": "4.0.1", "cache_update_frequency_usually": 420000, "cache_update_frequency_often": 1200000, "cache_update_frequency_sometimes": 3600000, diff --git a/package-lock.json b/package-lock.json index ccfedf47124..d0d4cd5c612 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "moodlemobile", - "version": "4.0.0", + "version": "4.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "moodlemobile", - "version": "4.0.0", + "version": "4.0.1", "license": "Apache-2.0", "dependencies": { "@angular/animations": "10.0.14", diff --git a/package.json b/package.json index 3c3909d5ee4..87364341da4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "moodlemobile", - "version": "4.0.0", + "version": "4.0.1", "description": "The official app for Moodle.", "author": { "name": "Moodle Pty Ltd.", diff --git a/src/addons/mod/imscp/pages/view/view.html b/src/addons/mod/imscp/pages/view/view.html index e37142791d3..3b8cee09010 100644 --- a/src/addons/mod/imscp/pages/view/view.html +++ b/src/addons/mod/imscp/pages/view/view.html @@ -28,9 +28,7 @@

-
- -
+ { + Array.from(track.cues).forEach((cue: VTTCue) => { cue.snapToLines = false; - cue.line = line; + cue.line = 90; cue.size = 100; // This solves some Android issue. }); // Delete listener. diff --git a/src/core/features/courses/pages/my/my.ts b/src/core/features/courses/pages/my/my.ts index 56551726ed2..5bc3723d363 100644 --- a/src/core/features/courses/pages/my/my.ts +++ b/src/core/features/courses/pages/my/my.ts @@ -20,6 +20,7 @@ import { CoreCoursesDashboard, CoreCoursesDashboardProvider } from '@features/co import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager'; import { IonRefresher } from '@ionic/angular'; import { CoreSites } from '@services/sites'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreCourses } from '../../services/courses'; @@ -90,7 +91,9 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy { await CoreUtils.nextTicks(2); this.myOverviewBlock = this.block?.dynamicComponent?.instance as AddonBlockMyOverviewComponent; - } catch { + } catch (error) { + CoreDomUtils.showErrorModal(error); + // Cannot get the blocks, just show the block if needed. this.loadFallbackBlock(); } diff --git a/src/core/features/courses/services/handlers/dashboard-home.ts b/src/core/features/courses/services/handlers/dashboard-home.ts index 778b1d3d291..7eff9f0c8b9 100644 --- a/src/core/features/courses/services/handlers/dashboard-home.ts +++ b/src/core/features/courses/services/handlers/dashboard-home.ts @@ -18,6 +18,7 @@ import { CoreMainMenuHomeHandler, CoreMainMenuHomeHandlerToDisplay } from '@feat import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; import { makeSingleton } from '@singletons'; +import { CoreLogger } from '@singletons/logger'; import { CoreCoursesDashboard } from '../dashboard'; /** @@ -30,6 +31,11 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler name = 'CoreCoursesDashboard'; priority = 1200; + logger: CoreLogger; + + constructor() { + this.logger = CoreLogger.getInstance('CoreDashboardHomeHandlerService'); + } /** * Check if the handler is enabled on a site level. @@ -59,9 +65,17 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler const dashboardEnabled = !dashboardDisabled && dashboardConfig !== '0'; if (dashboardAvailable && dashboardEnabled && !blocksDisabled) { - const blocks = await CoreCoursesDashboard.getDashboardBlocks(undefined, siteId); + try { + const blocks = await CoreCoursesDashboard.getDashboardBlocks(undefined, siteId); + + return CoreBlockDelegate.hasSupportedBlock(blocks.mainBlocks) || + CoreBlockDelegate.hasSupportedBlock(blocks.sideBlocks); + } catch (error) { + // Error getting blocks, assume it's enabled. + this.logger.error('Error getting Dashboard blocks', error); - return CoreBlockDelegate.hasSupportedBlock(blocks.mainBlocks) || CoreBlockDelegate.hasSupportedBlock(blocks.sideBlocks); + return true; + } } // Dashboard is enabled but not available, we will fake blocks. diff --git a/src/core/initializers/prepare-automated-tests.ts b/src/core/initializers/prepare-automated-tests.ts index 0a78c2456d8..a0c9fdc449b 100644 --- a/src/core/initializers/prepare-automated-tests.ts +++ b/src/core/initializers/prepare-automated-tests.ts @@ -15,6 +15,7 @@ import { ApplicationRef, NgZone as NgZoneService } from '@angular/core'; import { CorePushNotifications, CorePushNotificationsProvider } from '@features/pushnotifications/services/pushnotifications'; import { CoreApp, CoreAppProvider } from '@services/app'; +import { CoreConfig, CoreConfigProvider } from '@services/config'; import { CoreCronDelegate, CoreCronDelegateService } from '@services/cron'; import { CoreDB, CoreDbProvider } from '@services/db'; import { CoreCustomURLSchemes, CoreCustomURLSchemesProvider } from '@services/urlschemes'; @@ -24,6 +25,7 @@ type AutomatedTestsWindow = Window & { appRef?: ApplicationRef; appProvider?: CoreAppProvider; dbProvider?: CoreDbProvider; + configProvider?: CoreConfigProvider; cronProvider?: CoreCronDelegateService; ngZone?: NgZoneService; pushNotifications?: CorePushNotificationsProvider; @@ -34,6 +36,7 @@ function initializeAutomatedTestsWindow(window: AutomatedTestsWindow) { window.appRef = Application.instance; window.appProvider = CoreApp.instance; window.dbProvider = CoreDB.instance; + window.configProvider = CoreConfig.instance; window.cronProvider = CoreCronDelegate.instance; window.ngZone = NgZone.instance; window.pushNotifications = CorePushNotifications.instance; diff --git a/src/core/initializers/prepare-devtools.ts b/src/core/initializers/prepare-devtools.ts index 7f9d565bbea..dbd3df0b157 100644 --- a/src/core/initializers/prepare-devtools.ts +++ b/src/core/initializers/prepare-devtools.ts @@ -16,9 +16,11 @@ import { CoreApp, CoreAppProvider } from '@services/app'; import { CoreConfig, CoreConfigProvider } from '@services/config'; import { CoreDB, CoreDbProvider } from '@services/db'; import { CoreCustomURLSchemes, CoreCustomURLSchemesProvider } from '@services/urlschemes'; +import { CoreBrowser } from '@singletons/browser'; import { CoreConstants } from '../constants'; type DevelopmentWindow = Window & { + browser?: typeof CoreBrowser; appProvider?: CoreAppProvider; configProvider?: CoreConfigProvider; dbProvider?: CoreDbProvider; @@ -26,6 +28,7 @@ type DevelopmentWindow = Window & { }; function initializeDevelopmentWindow(window: DevelopmentWindow) { + window.browser = CoreBrowser; window.appProvider = CoreApp.instance; window.configProvider = CoreConfig.instance; window.dbProvider = CoreDB.instance; diff --git a/src/core/services/config.ts b/src/core/services/config.ts index eb2221487ec..8522db4560a 100644 --- a/src/core/services/config.ts +++ b/src/core/services/config.ts @@ -201,11 +201,11 @@ export class CoreConfigProvider { * Load development config overrides. */ protected loadDevelopmentConfig(): void { - if (!CoreConstants.enableDevTools() || !CoreBrowser.hasCookie('MoodleAppConfig')) { + if (!CoreConstants.enableDevTools() || !CoreBrowser.hasDevelopmentSetting('Config')) { return; } - this.patchEnvironment(JSON.parse(CoreBrowser.getCookie('MoodleAppConfig') ?? '{}'), { patchDefault: true }); + this.patchEnvironment(JSON.parse(CoreBrowser.getDevelopmentSetting('Config') ?? '{}'), { patchDefault: true }); } /** diff --git a/src/core/services/db.ts b/src/core/services/db.ts index 26721e2a7c7..841f57aef44 100644 --- a/src/core/services/db.ts +++ b/src/core/services/db.ts @@ -36,7 +36,7 @@ export class CoreDbProvider { * @returns Whether queries should be logged. */ loggingEnabled(): boolean { - return CoreBrowser.hasCookie('MoodleAppDBLoggingEnabled') || CoreAppProvider.isAutomated(); + return CoreBrowser.hasDevelopmentSetting('DBLoggingEnabled') || CoreAppProvider.isAutomated(); } /** diff --git a/src/core/services/sites.ts b/src/core/services/sites.ts index 64c5af80481..9cddd8b965d 100644 --- a/src/core/services/sites.ts +++ b/src/core/services/sites.ts @@ -557,14 +557,14 @@ export class CoreSitesProvider { } // Add site to sites list. - this.addSite(siteId, siteUrl, token, info, privateToken, config, oauthId); + await this.addSite(siteId, siteUrl, token, info, privateToken, config, oauthId); this.sites[siteId] = candidateSite; if (login) { // Turn candidate site into current site. this.currentSite = candidateSite; // Store session. - this.login(siteId); + await this.login(siteId); } else if (this.currentSite && this.currentSite.getId() == siteId) { // Current site has just been updated, trigger the event. CoreEvents.trigger(CoreEvents.SITE_UPDATED, info, siteId); diff --git a/src/core/singletons/browser.ts b/src/core/singletons/browser.ts index 9ba90176bcf..c4138c07b18 100644 --- a/src/core/singletons/browser.ts +++ b/src/core/singletons/browser.ts @@ -27,6 +27,28 @@ export class CoreBrowser { return new RegExp(`(\\s|;|^)${name}=`).test(document.cookie ?? ''); } + /** + * Check whether a development setting is set. + * + * @param name Setting name. + * @returns Whether the development setting is set. + */ + static hasDevelopmentSetting(name: string): boolean { + const setting = this.getDevelopmentSettingKey(name); + + return this.hasCookie(setting) || this.hasLocalStorage(setting); + } + + /** + * Check whether the given localStorage key is set. + * + * @param key localStorage key. + * @returns Whether the key is set. + */ + static hasLocalStorage(key: string): boolean { + return localStorage.getItem(key) !== null; + } + /** * Read a cookie. * @@ -45,4 +67,60 @@ export class CoreBrowser { return cookies[name] ?? null; } + /** + * Read a localStorage key. + * + * @param key localStorage key. + * @return localStorage value. + */ + static getLocalStorage(key: string): string | null { + return localStorage.getItem(key); + } + + /** + * Get development setting value. + * + * @param name Setting name. + * @returns Development setting value. + */ + static getDevelopmentSetting(name: string): string | null { + const setting = this.getDevelopmentSettingKey(name); + + return this.getCookie(setting) ?? this.getLocalStorage(setting); + } + + /** + * Set development setting. + * + * @param name Setting name. + * @param value Setting value. + */ + static setDevelopmentSetting(name: string, value: string): void { + const setting = this.getDevelopmentSettingKey(name); + + document.cookie = `${setting}=${value};path=/`; + localStorage.setItem(setting, value); + } + + /** + * Unset development setting. + * + * @param name Setting name. + */ + static clearDevelopmentSetting(name: string): void { + const setting = this.getDevelopmentSettingKey(name); + + document.cookie = `${setting}=;path=/;expires=Thu, 01 Jan 1970 00:00:01 GMT`; + localStorage.removeItem(setting); + } + + /** + * Get development setting key. + * + * @param name Development setting name. + */ + protected static getDevelopmentSettingKey(name: string): string { + return `MoodleApp${name}`; + } + } diff --git a/src/core/singletons/logger.ts b/src/core/singletons/logger.ts index 27c61fe23b8..6d59785b8fd 100644 --- a/src/core/singletons/logger.ts +++ b/src/core/singletons/logger.ts @@ -69,7 +69,7 @@ export class CoreLogger { static getInstance(className: string): CoreLogger { // Disable log on production and testing. if ( - !CoreBrowser.hasCookie('MoodleAppLoggingEnabled') && + !CoreBrowser.hasDevelopmentSetting('LoggingEnabled') && (CoreConstants.BUILD.isProduction || CoreConstants.BUILD.isTesting) ) { if (CoreConstants.BUILD.isProduction) { diff --git a/src/theme/helpers/ionic.functions.string.scss b/src/theme/helpers/ionic.functions.string.scss index db045dc7563..34a01c114ec 100644 --- a/src/theme/helpers/ionic.functions.string.scss +++ b/src/theme/helpers/ionic.functions.string.scss @@ -147,9 +147,10 @@ // If the selector contains :host it means it is targeting just the host // element so we can change it to look for host-context } @else if str-contains($selector, ":host") { - $list: append($list, ":host-context(#{$addHostSelector})", comma); - // If the selector does not contain host at all it is either a shadow - // or normal element so append both the dir check and host-context + $shadow-element: str-replace($selector, ":host", ":host-context(#{$addHostSelector})"); + $list: append($list, $shadow-element, comma); + // If the selector does not contain host at all it is either a shadow + // or normal element so append both the dir check and host-context } @else { $list: append($list, "#{$addHostSelector} #{$selector}", comma); $list: append($list, ":host-context(#{$addHostSelector}) #{$selector}", comma); diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index d2d550b9ae4..7170248cafc 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -1725,3 +1725,8 @@ ion-header.no-title { bottom: 0; } } + +// Fix subtitles wider than video. +video::-webkit-media-text-track-display { + white-space: normal !important; +}