commit
8b1113ab37
|
@ -2,7 +2,7 @@ name: Mirror
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, integration ]
|
||||
branches: [ master, main, unscheduled, integration, beta ]
|
||||
|
||||
jobs:
|
||||
mirror:
|
||||
|
|
|
@ -2,7 +2,7 @@ name: Prepare
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, integration, freemium-master ]
|
||||
branches: [ master, main, unscheduled, integration, beta, freemium-master, freemium-main ]
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
os: linux
|
||||
dist: trusty
|
||||
node_js: 14
|
||||
jdk:
|
||||
- oraclejdk11
|
||||
|
||||
git:
|
||||
depth: 3
|
||||
|
@ -51,7 +53,10 @@ jobs:
|
|||
- npm --version
|
||||
- nvm --version
|
||||
- npm ci
|
||||
- export JAVA_HOME_COPY=$JAVA_HOME
|
||||
- export JAVA_HOME=/usr/lib/jvm/java-8-oracle
|
||||
- yes | sdkmanager "build-tools;30.0.3"
|
||||
- export JAVA_HOME=$JAVA_HOME_COPY
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
|
|
19
config.xml
19
config.xml
|
@ -40,7 +40,7 @@
|
|||
<preference name="SplashMaintainAspectRatio" value="true" />
|
||||
<preference name="SplashShowOnlyFirstTime" value="false" />
|
||||
<preference name="android-minSdkVersion" value="22" />
|
||||
<preference name="android-targetSdkVersion" value="30" />
|
||||
<preference name="android-targetSdkVersion" value="31" />
|
||||
<preference name="AndroidPersistentFileLocation" value="Compatibility" />
|
||||
<preference name="AndroidInsecureFileModeEnabled" value="true" />
|
||||
<preference name="CustomURLSchemePluginClearsAndroidIntent" value="true" />
|
||||
|
@ -64,7 +64,7 @@
|
|||
<resource-file src="resources/android/icon/drawable-xhdpi-smallicon.png" target="app/src/main/res/mipmap-xhdpi/smallicon.png" />
|
||||
<resource-file src="resources/android/xml/network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" />
|
||||
<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application/activity[@android:name='MainActivity']">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|screenLayout|smallestScreenSize" />
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|screenLayout|smallestScreenSize" android:exported="true" />
|
||||
</edit-config>
|
||||
<edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application">
|
||||
<application android:largeHeap="true" android:networkSecurityConfig="@xml/network_security_config" />
|
||||
|
@ -196,21 +196,6 @@
|
|||
<param name="android-package" value="com.adobe.phonegap.push.PushPlugin" />
|
||||
</feature>
|
||||
</config-file>
|
||||
<config-file parent="/manifest/application" target="AndroidManifest.xml">
|
||||
<activity android:exported="true" android:name="com.adobe.phonegap.push.PushHandlerActivity" android:permission="${applicationId}.permission.PushHandlerActivity" />
|
||||
<receiver android:name="com.adobe.phonegap.push.BackgroundActionButtonHandler" />
|
||||
<receiver android:name="com.adobe.phonegap.push.PushDismissedHandler" />
|
||||
<service android:name="com.adobe.phonegap.push.FCMService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name="com.adobe.phonegap.push.PushInstanceIDListenerService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</config-file>
|
||||
<config-file parent="/*" target="res/xml/config.xml">
|
||||
<feature name="Media">
|
||||
<param name="android-package" value="org.apache.cordova.media.AudioHandler" />
|
||||
|
|
|
@ -241,13 +241,13 @@
|
|||
"publisher": "Ionic Team",
|
||||
"licenseFile": "LICENSE"
|
||||
},
|
||||
"@moodlehq/cordova-plugin-local-notification@0.9.0-moodle.3": {
|
||||
"@moodlehq/cordova-plugin-local-notification@0.9.0-moodle.7": {
|
||||
"licenses": "Apache*",
|
||||
"repository": "https://github.com/moodlemobile/cordova-plugin-local-notification",
|
||||
"publisher": "Sebastián Katzer",
|
||||
"licenseFile": "LICENSE"
|
||||
},
|
||||
"@moodlehq/cordova-plugin-qrscanner@3.0.1-moodle.2": {
|
||||
"@moodlehq/cordova-plugin-qrscanner@3.0.1-moodle.4": {
|
||||
"licenses": "MIT",
|
||||
"repository": "https://github.com/moodlemobile/cordova-plugin-qrscanner",
|
||||
"publisher": "Jason Dreyzehner",
|
||||
|
@ -258,7 +258,7 @@
|
|||
"repository": "https://github.com/moodlemobile/cordova-plugin-zip",
|
||||
"licenseFile": "LICENSE"
|
||||
},
|
||||
"@moodlehq/phonegap-plugin-push@2.0.0-moodle.4": {
|
||||
"@moodlehq/phonegap-plugin-push@4.0.0-moodle.2": {
|
||||
"licenses": "MIT",
|
||||
"repository": "https://github.com/moodlemobile/phonegap-plugin-push",
|
||||
"publisher": "Erisu",
|
||||
|
@ -2669,7 +2669,7 @@
|
|||
"url": "https://github.com/ichernev",
|
||||
"licenseFile": "LICENSE"
|
||||
},
|
||||
"moodlemobile@4.0.0": {
|
||||
"moodlemobile@4.0.2": {
|
||||
"licenses": "Apache-2.0",
|
||||
"repository": "https://github.com/moodlehq/moodleapp",
|
||||
"publisher": "Moodle Pty Ltd.",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -77,10 +77,10 @@
|
|||
"@moodlehq/cordova-plugin-file-transfer": "1.7.1-moodle.5",
|
||||
"@moodlehq/cordova-plugin-inappbrowser": "5.0.0-moodle.3",
|
||||
"@moodlehq/cordova-plugin-ionic-webview": "5.0.0-moodle.1",
|
||||
"@moodlehq/cordova-plugin-local-notification": "0.9.0-moodle.3",
|
||||
"@moodlehq/cordova-plugin-local-notification": "0.9.0-moodle.7",
|
||||
"@moodlehq/cordova-plugin-qrscanner": "3.0.1-moodle.4",
|
||||
"@moodlehq/cordova-plugin-zip": "3.1.0-moodle.1",
|
||||
"@moodlehq/phonegap-plugin-push": "2.0.0-moodle.4",
|
||||
"@moodlehq/phonegap-plugin-push": "4.0.0-moodle.2",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"@types/chart.js": "^2.9.31",
|
||||
|
@ -232,9 +232,8 @@
|
|||
"@moodlehq/cordova-plugin-zip": {},
|
||||
"cordova-sqlite-storage": {},
|
||||
"@moodlehq/phonegap-plugin-push": {
|
||||
"ANDROID_SUPPORT_V13_VERSION": "28.0.0",
|
||||
"FCM_VERSION": "18.+",
|
||||
"IOS_FIREBASE_MESSAGING_VERSION": "~> 6.32.2"
|
||||
"ANDROIDX_CORE_VERSION": "1.6.+",
|
||||
"FCM_VERSION": "23.+"
|
||||
},
|
||||
"com-darryncampbell-cordova-plugin-intent": {},
|
||||
"nl.kingsquare.cordova.background-audio": {},
|
||||
|
|
|
@ -14,7 +14,7 @@ print_title 'Generating language from code...'
|
|||
npx gulp lang
|
||||
|
||||
print_title 'Getting local mobile langs'
|
||||
git clone --branch integration --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp.git ../../moodle-local_moodlemobileapp
|
||||
git clone --branch master --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp.git ../../moodle-local_moodlemobileapp
|
||||
|
||||
if [ -z $forceLang ]; then
|
||||
get_languages
|
||||
|
|
|
@ -15,7 +15,10 @@
|
|||
import { CoreConstants, ModPurpose } from '@/core/constants';
|
||||
import { Injectable, Type } from '@angular/core';
|
||||
import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler';
|
||||
import { CoreCourseModuleHandler } from '@features/course/services/module-delegate';
|
||||
import { CoreCourseModuleData } from '@features/course/services/course-helper';
|
||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { AddonModFolderIndexComponent } from '../../components/index';
|
||||
|
||||
|
@ -44,6 +47,41 @@ export class AddonModFolderModuleHandlerService extends CoreModuleHandlerBase im
|
|||
[CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT,
|
||||
};
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async getData(
|
||||
module: CoreCourseModuleData,
|
||||
courseId: number,
|
||||
sectionId?: number,
|
||||
forCoursePage?: boolean,
|
||||
): Promise<CoreCourseModuleHandlerData> {
|
||||
const data = await super.getData(module, courseId, sectionId, forCoursePage);
|
||||
|
||||
if (module.description) {
|
||||
// Module description can contain the folder contents if it's inline, remove it.
|
||||
const descriptionElement = CoreDomUtils.convertToElement(module.description);
|
||||
|
||||
Array.from(descriptionElement.querySelectorAll('.foldertree, .folderbuttons, .tertiary-navigation'))
|
||||
.forEach(element => element.remove());
|
||||
|
||||
module.description = descriptionElement.innerHTML;
|
||||
}
|
||||
|
||||
// @todo: Temporary fix to open inline folders. We should use a more generic solution.
|
||||
data.action = async (event, module, courseId, options): Promise<void> => {
|
||||
options = options || {};
|
||||
options.params = options.params || {};
|
||||
Object.assign(options.params, { module });
|
||||
|
||||
const routeParams = '/' + courseId + '/' + module.id;
|
||||
|
||||
await CoreNavigator.navigateToSitePath(this.pageName + routeParams, options);
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
|
|
|
@ -845,8 +845,6 @@ export class AddonModForumProvider {
|
|||
forumId: number,
|
||||
options: AddonModForumGetDiscussionsInPagesOptions = {},
|
||||
): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> {
|
||||
options.page = options.page || 0;
|
||||
|
||||
const result = {
|
||||
discussions: [] as AddonModForumDiscussion[],
|
||||
error: false,
|
||||
|
@ -859,7 +857,10 @@ export class AddonModForumProvider {
|
|||
|
||||
const getPage = (page: number): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> =>
|
||||
// Get page discussions.
|
||||
this.getDiscussions(forumId, options).then((response) => {
|
||||
this.getDiscussions(forumId, {
|
||||
...options,
|
||||
page,
|
||||
}).then((response) => {
|
||||
result.discussions = result.discussions.concat(response.discussions);
|
||||
numPages--;
|
||||
|
||||
|
@ -876,7 +877,7 @@ export class AddonModForumProvider {
|
|||
})
|
||||
;
|
||||
|
||||
return getPage(options.page);
|
||||
return getPage(options.page ?? 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -916,7 +917,7 @@ export class AddonModForumProvider {
|
|||
.getDiscussionsInPages(forum.id, {
|
||||
cmId: forum.cmid,
|
||||
sortOrder: sortOrder.value,
|
||||
readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE,
|
||||
readingStrategy: CoreSitesReadingStrategy.ONLY_CACHE,
|
||||
})
|
||||
.then((response) => {
|
||||
// Now invalidate the WS calls.
|
||||
|
|
|
@ -128,7 +128,7 @@
|
|||
<core-download-refresh *ngIf="downloadEnabled && module.handlerData?.showDownloadButton &&
|
||||
module.downloadStatus != statusDownloaded" [status]="module.downloadStatus" [enabled]="true"
|
||||
[canTrustDownload]="true" [loading]="module.spinner || module.handlerData.spinner"
|
||||
(action)="prefetchModule(module, section)">
|
||||
(action)="prefetchModule(module, $event)">
|
||||
</core-download-refresh>
|
||||
<ion-button fill="clear" (click)="deleteForModule(module, section)"
|
||||
*ngIf="!module.calculatingSize && module.totalSize > 0" color="danger">
|
||||
|
|
|
@ -104,7 +104,7 @@ export class CoreSite {
|
|||
'3.9': 2020061500,
|
||||
'3.10': 2020110900,
|
||||
'3.11': 2021051700,
|
||||
'4.0': 2021100300, // @todo [4.0] replace with right value when released. Using a tmp value to be able to test new things.
|
||||
'4.0': 2022041900,
|
||||
};
|
||||
|
||||
// Possible cache update frequencies.
|
||||
|
|
|
@ -195,7 +195,9 @@ export class CoreBlockDelegateService extends CoreDelegate<CoreBlockHandler> {
|
|||
* @return Whether is enabled or disabled in site.
|
||||
*/
|
||||
protected isFeatureDisabled(handler: CoreBlockHandler, site: CoreSite): boolean {
|
||||
return this.areBlocksDisabledInSite(site) || super.isFeatureDisabled(handler, site);
|
||||
// Allow displaying my overview even if all blocks are disabled, to avoid having an empty My Courses.
|
||||
return (this.areBlocksDisabledInSite(site) && handler.blockName !== 'myoverview') ||
|
||||
super.isFeatureDisabled(handler, site);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
</core-format-text>
|
||||
</h1>
|
||||
</ion-label>
|
||||
<ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser" [href]="externalUrl" core-link [showBrowserWarning]="false"
|
||||
[attr.aria-label]="'core.openinbrowser' | translate" slot="end">
|
||||
<ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser && externalUrl" [href]="externalUrl" core-link
|
||||
[showBrowserWarning]="false" [attr.aria-label]="'core.openinbrowser' | translate" slot="end">
|
||||
<ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
|
|
|
@ -27,8 +27,7 @@
|
|||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ion-item class="ion-text-wrap" button detail="false" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname"
|
||||
[class.item-disabled]="course.visible == 0">
|
||||
<ion-item class="ion-text-wrap" button detail="false" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname">
|
||||
|
||||
<ng-container *ngIf="layout == 'list' || layout == 'listwithenrol'">
|
||||
<ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" slot="start" class="course-icon core-course-thumb"
|
||||
|
@ -74,6 +73,13 @@
|
|||
</core-format-text>
|
||||
</ion-label>
|
||||
</ion-chip>
|
||||
|
||||
<ion-chip color="info" *ngIf="course.visible == 0"
|
||||
class="core-course-additional-info ion-text-wrap core-course-hidden-message">
|
||||
<ion-label>
|
||||
{{ 'core.course.hiddenfromstudents' | translate }}
|
||||
</ion-label>
|
||||
</ion-chip>
|
||||
</div>
|
||||
|
||||
<div *ngIf="layout != 'summarycard' && isEnrolled && progress >= 0 && completionUserTracked !== false"
|
||||
|
|
|
@ -97,6 +97,10 @@ ion-chip {
|
|||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
max-width: 100%;
|
||||
|
||||
&.core-course-category {
|
||||
@include margin-horizontal(0px, 8px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
<img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt="" />
|
||||
</div>
|
||||
<ion-item button (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" class="core-course-header"
|
||||
[class.item-disabled]="course.visible == 0"
|
||||
[class.core-course-only-title]="!showAll || progress < 0 && completionUserTracked === false" detail="false">
|
||||
<ion-label class="ion-text-wrap core-course-title"
|
||||
[class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)"
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
// Common styles.
|
||||
:host-context(.core-horizontal-scroll) {
|
||||
@include horizontal_scroll_item(80%, 250px, 300px);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import { AsyncComponent } from '@classes/async-component';
|
|||
import { PageLoadsManager } from '@classes/page-loads-manager';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CoreBlockComponent } from '@features/block/components/block/block';
|
||||
import { CoreBlockDelegate } from '@features/block/services/block-delegate';
|
||||
import { CoreCourseBlock } from '@features/course/services/course';
|
||||
import { CoreCoursesDashboard, CoreCoursesDashboardProvider } from '@features/courses/services/dashboard';
|
||||
import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager';
|
||||
|
@ -98,22 +99,30 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy, AsyncCompone
|
|||
const available = await CoreCoursesDashboard.isAvailable();
|
||||
const disabled = await CoreCourses.isMyCoursesDisabled();
|
||||
|
||||
const supportsMyParam = !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('4.0');
|
||||
|
||||
if (available && !disabled) {
|
||||
try {
|
||||
const blocks = await loadWatcher.watchRequest(
|
||||
CoreCoursesDashboard.getDashboardBlocksObservable({
|
||||
myPage: this.myPageCourses,
|
||||
myPage: supportsMyParam ? this.myPageCourses : undefined,
|
||||
readingStrategy: loadWatcher.getReadingStrategy(),
|
||||
}),
|
||||
);
|
||||
|
||||
// My overview block should always be in main blocks, but check side blocks too just in case.
|
||||
this.loadedBlock = blocks.mainBlocks.concat(blocks.sideBlocks).find((block) => block.name == 'myoverview');
|
||||
this.hasSideBlocks = blocks.sideBlocks.length > 0;
|
||||
this.hasSideBlocks = supportsMyParam && CoreBlockDelegate.hasSupportedBlock(blocks.sideBlocks);
|
||||
|
||||
await CoreUtils.nextTicks(2);
|
||||
|
||||
this.myOverviewBlock = this.block?.dynamicComponent?.instance as AddonBlockMyOverviewComponent;
|
||||
|
||||
if (!this.loadedBlock && !supportsMyParam) {
|
||||
// In old sites, display the block even if not found in Dashboard.
|
||||
// This is because the "My courses" page doesn't exist in the site so it can't be configured.
|
||||
this.loadFallbackBlock();
|
||||
}
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModal(error);
|
||||
|
||||
|
@ -121,10 +130,9 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy, AsyncCompone
|
|||
this.loadFallbackBlock();
|
||||
}
|
||||
} else if (!available) {
|
||||
// WS not available, or my courses page not available. show fallback block.
|
||||
// WS not available, show fallback block.
|
||||
this.loadFallbackBlock();
|
||||
} else {
|
||||
// Disabled.
|
||||
this.loadedBlock = undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -667,9 +667,14 @@ export class CorePushNotificationsProvider {
|
|||
|
||||
const pushObject = Push.init(options);
|
||||
|
||||
pushObject.on('notification').subscribe((notification: NotificationEventResponse) => {
|
||||
pushObject.on('notification').subscribe((notification: NotificationEventResponse | {registrationType: string}) => {
|
||||
// Execute the callback in the Angular zone, so change detection doesn't stop working.
|
||||
NgZone.run(() => {
|
||||
if ('registrationType' in notification) {
|
||||
// Not a valid notification, ignore.
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log('Received a notification', notification);
|
||||
this.onMessageReceived(notification);
|
||||
});
|
||||
|
|
|
@ -84,7 +84,8 @@ import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/class
|
|||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
|
||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
|
||||
import { CoreObject } from '@singletons/object';
|
||||
import { CoreUrl } from '@singletons/url';
|
||||
import { CoreUrlUtils } from '@services/utils/url';
|
||||
import { CoreText } from '@singletons/text';
|
||||
|
||||
const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled';
|
||||
|
||||
|
@ -164,8 +165,11 @@ export class CoreSitePluginsHelperProvider {
|
|||
): Promise<string> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
// Make sure it's an absolute URL.
|
||||
let url = handlerSchema.styles?.url ? CoreUrl.toAbsoluteURL(site.getURL(), handlerSchema.styles.url) : undefined;
|
||||
// Make sure it's an absolute URL. Do not use toAbsoluteURL because it can change the behaviour and break plugin styles.
|
||||
let url = handlerSchema.styles?.url;
|
||||
if (url && !CoreUrlUtils.isAbsoluteURL(url)) {
|
||||
url = CoreText.concatenatePaths(site.getURL(), url);
|
||||
}
|
||||
|
||||
if (url && handlerSchema.styles?.version) {
|
||||
// Add the version to the URL to prevent getting a cached file.
|
||||
|
|
Loading…
Reference in New Issue