diff --git a/.travis.yml b/.travis.yml index 92b586c86..813d74f80 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,43 +19,35 @@ git: depth: 3 before_cache: - - rm -rf $HOME/.cache/electron-builder/wine - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ cache: directories: - $HOME/.npm - - $HOME/.cache/electron - - $HOME/.cache/electron-builder - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ - $HOME/.android/build-cache before_script: - - if [ "$TRAVIS_OS_NAME" != 'windows' ] ; then npm install npm@latest -g ; fi + - npm install npm@latest -g - gulp jobs: include: - stage: check if: NOT branch =~ /(master|integration|desktop)$/ AND env(DEPLOY) IS blank - os: linux script: npm run build --bailOnLintError true --typeCheckOnLint true - stage: mirror if: branch IN (master, integration, desktop) AND repo = moodlehq/moodleapp AND type != cron - os: linux script: scripts/mirror.sh - stage: prepare - if: branch =~ /(master|^integration)$/ AND env(PREPARE) IS NOT blank AND env(PREPARE) = 1 AND type != cron - os: linux + if: branch =~ /(master|^integration)$/ AND env(PREPARE) IS present AND env(PREPARE) = 1 AND type != cron AND tag IS blank script: scripts/aot.sh - stage: build name: "Build Android" - if: env(DEPLOY) IS NOT blank AND ((env(DEPLOY) = 1 AND branch != desktop) OR (env(DEPLOY) IN (2,3) AND tag IS NOT blank)) - os: linux + if: env(DEPLOY) IS present AND type != cron AND ((env(DEPLOY) = 1 AND tag IS blank) OR (env(DEPLOY) = 2 AND tag IS present)) dist: trusty - group: edge language: android env: - BUILD_PLATFORM='android' @@ -67,56 +59,24 @@ jobs: - npm ci - npm install -g gulp script: scripts/aot.sh - - stage: build - name: "Build iOS" - if: env(DEPLOY) IS NOT blank AND ((env(DEPLOY) = 1 AND branch != desktop) OR (env(DEPLOY) IN (2,3) AND tag IS NOT blank)) - os: osx - osx_image: xcode12.2 - env: - - BUILD_PLATFORM='ios' - script: scripts/aot.sh - - stage: build - name: "Build Linux" - if: env(DEPLOY) IS NOT blank AND ((env(DEPLOY) = 1 AND branch = desktop) OR (env(DEPLOY) = 3 AND tag IS NOT blank)) - os: linux - env: - - ELECTRON_CACHE=$HOME/.cache/electron - - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder - - BUILD_PLATFORM='linux' - script: scripts/aot.sh - - stage: build - name: "Build MacOS" - if: env(DEPLOY) IS NOT blank AND ((env(DEPLOY) = 1 AND branch = desktop) OR (env(DEPLOY) = 3 AND tag IS NOT blank)) - os: osx - osx_image: xcode12.2 - env: - - ELECTRON_CACHE=$HOME/.cache/electron - - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder - - BUILD_PLATFORM='osx' - script: scripts/aot.sh - - stage: build - name: "Build Windows" - if: env(DEPLOY) IS NOT blank AND ((env(DEPLOY) = 1 AND branch = desktop) OR (env(DEPLOY) = 3 AND tag IS NOT blank)) - os: windows - env: - - ELECTRON_CACHE=$HOME/.cache/electron - - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder - - ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true - - DEBUG=electron-windows-store - - BUILD_PLATFORM='windows' - script: scripts/aot.sh - stage: test - name: "End to end tests (mod_forum, mod_messages and mod_comments)" + name: "End to end tests (mod_forum and mod_messages)" services: - docker if: type = cron - script: scripts/test_e2e.sh "@app&&@mod_forum" "@app&&@mod_messages" "@app&&@mod_comments" + script: scripts/test_e2e.sh "@app&&@mod_forum" "@app&&@mod_messages" - stage: test - name: "End to end tests (mod_data, mod_survey, mod_course, core_course and mod_courses)" + name: "End to end tests (mod_data and mod_survey)" services: - docker if: type = cron - script: scripts/test_e2e.sh "@app&&@mod_data" "@app&&@mod_survey" "@app&&@mod_course" "@app&&@core_course" "@app&&@mod_courses" + script: scripts/test_e2e.sh "@app&&@mod_data" "@app&&@mod_survey" + - stage: test + name: "End to end tests (mod_comments, mod_course, core_course and mod_courses)" + services: + - docker + if: type = cron + script: scripts/test_e2e.sh "@app&&@mod_comments" "@app&&@mod_course" "@app&&@core_course" "@app&&@mod_courses" - stage: test name: "End to end tests (others)" services: diff --git a/config.xml b/config.xml index 01aeaa0c1..0ed23b3f5 100644 --- a/config.xml +++ b/config.xml @@ -1,5 +1,5 @@ - + Moodle Moodle official app Moodle Mobile team @@ -244,7 +244,7 @@ - 3.9.3 + 3.9.4 YES diff --git a/desktop/assets/windows/AppXManifest.xml b/desktop/assets/windows/AppXManifest.xml index c74afc756..255062c68 100644 --- a/desktop/assets/windows/AppXManifest.xml +++ b/desktop/assets/windows/AppXManifest.xml @@ -6,7 +6,7 @@ + Version="3.9.4.0" /> Moodle Desktop Moodle Pty Ltd. diff --git a/package.json b/package.json index a4f73ed0d..7bcbe8706 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "moodlemobile", - "version": "3.9.3", + "version": "3.9.4", "description": "The official app for Moodle.", "author": { "name": "Moodle Pty Ltd.", @@ -266,7 +266,7 @@ "category": "public.app-category.education", "icon": "resources/desktop/icon.icns", "target": "mas", - "bundleVersion": "3.9.3", + "bundleVersion": "3.9.4", "extendInfo": { "ElectronTeamID": "2NU57U5PAW", "NSLocationWhenInUseUsageDescription": "We need your location so you can attach it as part of your submissions.", diff --git a/scripts/lang_functions.php b/scripts/lang_functions.php index 668070a60..17d6d8d2c 100644 --- a/scripts/lang_functions.php +++ b/scripts/lang_functions.php @@ -400,6 +400,9 @@ function override_component_lang_files($keys, $translations) { case 'assets': $path .= $type.'/'.$component; break; + default: + $path .= $type.'/lang'; + break; } diff --git a/src/config.json b/src/config.json index 652848597..e357cb95a 100644 --- a/src/config.json +++ b/src/config.json @@ -2,8 +2,8 @@ "app_id": "com.moodle.moodlemobile", "appname": "Moodle Mobile", "desktopappname": "Moodle Desktop", - "versioncode": 3930, - "versionname": "3.9.3", + "versioncode": 3940, + "versionname": "3.9.4", "cache_update_frequency_usually": 420000, "cache_update_frequency_often": 1200000, "cache_update_frequency_sometimes": 3600000, diff --git a/src/core/course/providers/course.ts b/src/core/course/providers/course.ts index 7e6d02696..74289d6f4 100644 --- a/src/core/course/providers/course.ts +++ b/src/core/course/providers/course.ts @@ -982,7 +982,7 @@ export class CoreCourseProvider { const loading = this.domUtils.showModalLoading(); // Wait for site plugins to be fetched. - await this.sitePluginsProvider.waitFetchPlugins(); + await this.utils.ignoreErrors(this.sitePluginsProvider.waitFetchPlugins()); if (typeof course.format == 'undefined') { // This block can be replaced by a call to CourseHelper.getCourse(), but it is circular dependant. @@ -1006,9 +1006,10 @@ export class CoreCourseProvider { if (!this.sitePluginsProvider.sitePluginPromiseExists('format_' + course.format)) { // No custom format plugin. We don't need to wait for anything. - await this.courseFormatDelegate.openCourse(navCtrl, course, params); loading.dismiss(); + await this.courseFormatDelegate.openCourse(navCtrl, course, params); + return; } @@ -1041,6 +1042,8 @@ export class CoreCourseProvider { this.domUtils.showConfirm(message, '', reload, ignore).then(() => { window.location.reload(); }); + } finally { + loading.dismiss(); } } diff --git a/src/core/course/providers/helper.ts b/src/core/course/providers/helper.ts index 87fcd202e..db2046f87 100644 --- a/src/core/course/providers/helper.ts +++ b/src/core/course/providers/helper.ts @@ -34,7 +34,7 @@ import { CoreCourseProvider } from './course'; import { CoreCourseOfflineProvider } from './course-offline'; import { CoreCourseModuleDelegate } from './module-delegate'; import { CoreCourseModulePrefetchDelegate } from './module-prefetch-delegate'; -import { CoreLoginHelperProvider } from '@core/login/providers/helper'; +import { CoreLoginHelper, CoreLoginHelperProvider } from '@core/login/providers/helper'; import { CoreConstants } from '@core/constants'; import { CoreSite } from '@classes/site'; import { CoreLoggerProvider } from '@providers/logger'; @@ -122,7 +122,6 @@ export class CoreCourseHelperProvider { private timeUtils: CoreTimeUtilsProvider, private utils: CoreUtilsProvider, private translate: TranslateService, - private loginHelper: CoreLoginHelperProvider, private courseOptionsDelegate: CoreCourseOptionsDelegate, private siteHomeProvider: CoreSiteHomeProvider, private eventsProvider: CoreEventsProvider, @@ -1302,7 +1301,7 @@ export class CoreCourseHelperProvider { if (courseId == site.getSiteHomeId()) { // Check if site home is available. return this.siteHomeProvider.isAvailable().then(() => { - this.loginHelper.redirect('CoreSiteHomeIndexPage', params, siteId); + CoreLoginHelper.instance.redirect('CoreSiteHomeIndexPage', params, siteId); }).finally(() => { modal.dismiss(); }); @@ -1610,7 +1609,7 @@ export class CoreCourseHelperProvider { params = params || {}; Object.assign(params, { course: course }); - return this.loginHelper.redirect(CoreLoginHelperProvider.OPEN_COURSE, params, siteId); + return CoreLoginHelper.instance.redirect(CoreLoginHelperProvider.OPEN_COURSE, params, siteId); } } diff --git a/src/core/login/providers/helper.ts b/src/core/login/providers/helper.ts index 05c517d98..84c2e0aca 100644 --- a/src/core/login/providers/helper.ts +++ b/src/core/login/providers/helper.ts @@ -34,6 +34,7 @@ import { CoreConstants } from '@core/constants'; import { Md5 } from 'ts-md5/dist/md5'; import { CoreSite } from '@classes/site'; import { CoreUrl } from '@singletons/url'; +import { makeSingleton } from '@singletons/core.singletons'; /** * Data related to a SSO authentication. @@ -1417,3 +1418,5 @@ export class CoreLoginHelperProvider { }); } } + +export class CoreLoginHelper extends makeSingleton(CoreLoginHelperProvider) {} diff --git a/src/core/siteplugins/providers/helper.ts b/src/core/siteplugins/providers/helper.ts index 7fa9790e9..619d2824f 100644 --- a/src/core/siteplugins/providers/helper.ts +++ b/src/core/siteplugins/providers/helper.ts @@ -439,7 +439,21 @@ export class CoreSitePluginsHelperProvider { styleEl.setAttribute('id', 'siteplugin-' + uniqueName); styleEl.innerHTML = cssCode; - document.head.appendChild(styleEl); + // To ensure consistency, insert in alphabetical order among other site plugin styles. + let lowestGreater = null; + Array.from(document.head.querySelectorAll('style')).forEach((other) => { + if (/^siteplugin-/.test(other.id) && other.id > styleEl.id) { + if (lowestGreater === null || other.id < lowestGreater.id) { + lowestGreater = other; + } + } + }); + + if (lowestGreater) { + document.head.insertBefore(styleEl, lowestGreater); + } else { + document.head.appendChild(styleEl); + } // Styles have been loaded, now treat the CSS. this.filepoolProvider.treatCSSCode(siteId, fileUrl, cssCode, CoreSitePluginsProvider.COMPONENT, uniqueName, version)