MOBILE-4348 module: Re-estructure activity card
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
@ -21,7 +21,6 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/
|
||||||
import { CoreConstants, ModPurpose } from '@/core/constants';
|
import { CoreConstants, ModPurpose } from '@/core/constants';
|
||||||
import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler';
|
import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler';
|
||||||
import { CoreCourseModuleData } from '@features/course/services/course-helper';
|
import { CoreCourseModuleData } from '@features/course/services/course-helper';
|
||||||
import { CoreIonicColorNames } from '@singletons/colors';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to support forum modules.
|
* Handler to support forum modules.
|
||||||
|
@ -57,7 +56,6 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp
|
||||||
const data = await super.getData(module, courseId);
|
const data = await super.getData(module, courseId);
|
||||||
|
|
||||||
if ('afterlink' in module && !!module.afterlink) {
|
if ('afterlink' in module && !!module.afterlink) {
|
||||||
data.extraBadgeColor = undefined;
|
|
||||||
const match = />(\d+)[^<]+/.exec(module.afterlink);
|
const match = />(\d+)[^<]+/.exec(module.afterlink);
|
||||||
data.extraBadge = match ? Translate.instant('addon.mod_forum.unreadpostsnumber', { $a : match[1] }) : '';
|
data.extraBadge = match ? Translate.instant('addon.mod_forum.unreadpostsnumber', { $a : match[1] }) : '';
|
||||||
} else {
|
} else {
|
||||||
|
@ -113,7 +111,6 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp
|
||||||
}
|
}
|
||||||
|
|
||||||
data.extraBadge = Translate.instant('core.loading');
|
data.extraBadge = Translate.instant('core.loading');
|
||||||
data.extraBadgeColor = CoreIonicColorNames.DARK;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Handle unread posts.
|
// Handle unread posts.
|
||||||
|
@ -122,7 +119,6 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp
|
||||||
siteId,
|
siteId,
|
||||||
});
|
});
|
||||||
|
|
||||||
data.extraBadgeColor = undefined;
|
|
||||||
data.extraBadge = forum.unreadpostscount
|
data.extraBadge = forum.unreadpostscount
|
||||||
? Translate.instant(
|
? Translate.instant(
|
||||||
'addon.mod_forum.unreadpostsnumber',
|
'addon.mod_forum.unreadpostsnumber',
|
||||||
|
@ -131,7 +127,6 @@ export class AddonModForumModuleHandlerService extends CoreModuleHandlerBase imp
|
||||||
: '';
|
: '';
|
||||||
} catch {
|
} catch {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
data.extraBadgeColor = undefined;
|
|
||||||
data.extraBadge = '';
|
data.extraBadge = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
@ -59,7 +59,7 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple
|
||||||
): Promise<CoreCourseModuleHandlerData> {
|
): Promise<CoreCourseModuleHandlerData> {
|
||||||
const data = await super.getData(module, courseId, sectionId, forCoursePage);
|
const data = await super.getData(module, courseId, sectionId, forCoursePage);
|
||||||
data.showDownloadButton = false;
|
data.showDownloadButton = false;
|
||||||
data.buttons = [{
|
data.button = {
|
||||||
icon: 'fas-up-right-from-square',
|
icon: 'fas-up-right-from-square',
|
||||||
label: 'addon.mod_lti.launchactivity',
|
label: 'addon.mod_lti.launchactivity',
|
||||||
action: (event: Event, module: CoreCourseModuleData, courseId: number): void => {
|
action: (event: Event, module: CoreCourseModuleData, courseId: number): void => {
|
||||||
|
@ -68,7 +68,7 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple
|
||||||
|
|
||||||
CoreCourse.storeModuleViewed(courseId, module.id);
|
CoreCourse.storeModuleViewed(courseId, module.id);
|
||||||
},
|
},
|
||||||
}];
|
};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
@ -73,14 +73,14 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
|
|
||||||
const handlerData = await super.getData(module, courseId, sectionId, forCoursePage);
|
const handlerData = await super.getData(module, courseId, sectionId, forCoursePage);
|
||||||
handlerData.updateStatus = (status) => {
|
handlerData.updateStatus = (status) => {
|
||||||
if (!handlerData.buttons) {
|
if (!handlerData.button) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerData.buttons[0].hidden = status !== CoreConstants.DOWNLOADED ||
|
handlerData.button.hidden = status !== CoreConstants.DOWNLOADED ||
|
||||||
AddonModResourceHelper.isDisplayedInIframe(module);
|
AddonModResourceHelper.isDisplayedInIframe(module);
|
||||||
};
|
};
|
||||||
handlerData.buttons = [{
|
handlerData.button = {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
icon: openWithPicker ? 'fas-share-from-square' : 'fas-file',
|
icon: openWithPicker ? 'fas-share-from-square' : 'fas-file',
|
||||||
label: module.name + ': ' + Translate.instant(openWithPicker ? 'core.openwith' : 'addon.mod_resource.openthefile'),
|
label: module.name + ': ' + Translate.instant(openWithPicker ? 'core.openwith' : 'addon.mod_resource.openthefile'),
|
||||||
|
@ -92,7 +92,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
CoreCourse.storeModuleViewed(courseId, module.id);
|
CoreCourse.storeModuleViewed(courseId, module.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}];
|
};
|
||||||
|
|
||||||
this.getResourceData(module, courseId, handlerData).then((extra) => {
|
this.getResourceData(module, courseId, handlerData).then((extra) => {
|
||||||
handlerData.extraBadge = extra;
|
handlerData.extraBadge = extra;
|
||||||
|
@ -144,11 +144,11 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
|
|
||||||
// Check if the button needs to be shown or not.
|
// Check if the button needs to be shown or not.
|
||||||
promises.push(this.hideOpenButton(module).then((hideOpenButton) => {
|
promises.push(this.hideOpenButton(module).then((hideOpenButton) => {
|
||||||
if (!handlerData.buttons) {
|
if (!handlerData.button) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerData.buttons[0].hidden = hideOpenButton;
|
handlerData.button.hidden = hideOpenButton;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}));
|
}));
|
||||||
|
@ -166,14 +166,18 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
const extra: string[] = [];
|
|
||||||
|
|
||||||
if (module.contentsinfo) {
|
if (module.contentsinfo) {
|
||||||
// No need to use the list of files.
|
// No need to use the list of files.
|
||||||
extra.push(CoreTextUtils.cleanTags(module.afterlink));
|
return CoreTextUtils.cleanTags(module.afterlink);
|
||||||
} else if (module.contents && module.contents[0]) {
|
}
|
||||||
|
|
||||||
|
if (!module.contents || !module.contents[0]) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const extra: string[] = [];
|
||||||
const files = module.contents;
|
const files = module.contents;
|
||||||
const file = files[0];
|
const mainFile = files[0];
|
||||||
|
|
||||||
if (options.showsize) {
|
if (options.showsize) {
|
||||||
const size = options.filedetails
|
const size = options.filedetails
|
||||||
|
@ -185,11 +189,11 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
|
|
||||||
if (options.showtype) {
|
if (options.showtype) {
|
||||||
// We should take it from options.filedetails.size if available but it's already translated.
|
// We should take it from options.filedetails.size if available but it's already translated.
|
||||||
extra.push(CoreMimetypeUtils.getMimetypeDescription(file));
|
extra.push(CoreMimetypeUtils.getMimetypeDescription(mainFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.showdate) {
|
if (options.showdate) {
|
||||||
const timecreated = 'timecreated' in file ? file.timecreated : 0;
|
const timecreated = 'timecreated' in mainFile ? mainFile.timecreated : 0;
|
||||||
|
|
||||||
if (options.filedetails && options.filedetails.modifieddate) {
|
if (options.filedetails && options.filedetails.modifieddate) {
|
||||||
extra.push(Translate.instant(
|
extra.push(Translate.instant(
|
||||||
|
@ -201,12 +205,12 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
'addon.mod_resource.uploadeddate',
|
'addon.mod_resource.uploadeddate',
|
||||||
{ $a: CoreTimeUtils.userDate(options.filedetails.uploadeddate * 1000, 'core.strftimedatetimeshort') },
|
{ $a: CoreTimeUtils.userDate(options.filedetails.uploadeddate * 1000, 'core.strftimedatetimeshort') },
|
||||||
));
|
));
|
||||||
} else if ((file.timemodified || 0) > timecreated + CoreConstants.SECONDS_MINUTE * 5) {
|
} else if ((mainFile.timemodified || 0) > timecreated + CoreConstants.SECONDS_MINUTE * 5) {
|
||||||
/* Modified date may be up to several minutes later than uploaded date just because
|
/* Modified date may be up to several minutes later than uploaded date just because
|
||||||
teacher did not submit the form promptly. Give teacher up to 5 minutes to do it. */
|
teacher did not submit the form promptly. Give teacher up to 5 minutes to do it. */
|
||||||
extra.push(Translate.instant(
|
extra.push(Translate.instant(
|
||||||
'addon.mod_resource.modifieddate',
|
'addon.mod_resource.modifieddate',
|
||||||
{ $a: CoreTimeUtils.userDate((file.timemodified || 0) * 1000, 'core.strftimedatetimeshort') },
|
{ $a: CoreTimeUtils.userDate((mainFile.timemodified || 0) * 1000, 'core.strftimedatetimeshort') },
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
extra.push(Translate.instant(
|
extra.push(Translate.instant(
|
||||||
|
@ -215,9 +219,8 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return extra.join(' ');
|
return extra.join(' · ');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -93,20 +93,20 @@ export class AddonModUrlModuleHandlerService extends CoreModuleHandlerBase imple
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
buttons: [{
|
button: {
|
||||||
hidden: true, // Hide it until we calculate if it should be displayed or not.
|
hidden: true, // Hide it until we calculate if it should be displayed or not.
|
||||||
icon: 'fas-link',
|
icon: 'fas-link',
|
||||||
label: 'core.openmodinbrowser',
|
label: 'core.openmodinbrowser',
|
||||||
action: (event: Event, module: CoreCourseModuleData, courseId: number): void => {
|
action: (event: Event, module: CoreCourseModuleData, courseId: number): void => {
|
||||||
openUrl(module, courseId);
|
openUrl(module, courseId);
|
||||||
},
|
},
|
||||||
}],
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const hideButton = await CoreUtils.ignoreErrors(this.hideLinkButton(module));
|
const hideButton = await CoreUtils.ignoreErrors(this.hideLinkButton(module));
|
||||||
|
|
||||||
if (handlerData.buttons && hideButton !== undefined) {
|
if (handlerData.button && hideButton !== undefined) {
|
||||||
handlerData.buttons[0].hidden = hideButton;
|
handlerData.button.hidden = hideButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-section {
|
.course-section {
|
||||||
--padding-start: 12px;
|
|
||||||
--inner-padding-end: 12px;
|
--inner-padding-end: 12px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,14 +10,14 @@
|
||||||
|
|
||||||
core-mod-icon {
|
core-mod-icon {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
--padding: 12px;
|
--padding: 4px;
|
||||||
|
@include margin-horizontal(null, 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 ion-icon {
|
h1 ion-icon {
|
||||||
color: var(--medium);
|
color: var(--medium);
|
||||||
@include margin-horizontal(8px, null);
|
@include margin-horizontal(8px, null);
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-info-box {
|
.core-module-info-box {
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
<ion-card *ngIf="module.handlerData && module.visibleoncoursepage !== 0" [class.core-course-module-with-view]="moduleHasView"
|
<ion-card *ngIf="module.handlerData && module.visibleoncoursepage !== 0"
|
||||||
(click)="moduleClicked($event)" [button]="module.handlerData.action && module.uservisible"
|
class="activity-card core-course-module-handler {{module.handlerData.class}}" [class.core-course-module-with-view]="moduleHasView"
|
||||||
[attr.aria-label]="module.handlerData.a11yTitle ? module.handlerData.a11yTitle : null">
|
[class.item-dimmed]="module.visible === 0 || module.uservisible === false" (click)="moduleClicked($event)"
|
||||||
|
[button]="module.handlerData.action && module.uservisible"
|
||||||
|
[attr.aria-label]="module.handlerData.a11yTitle ? module.handlerData.a11yTitle : null" id="core-course-module-{{module.id}}">
|
||||||
<ng-container *ngIf="!module.handlerData.loading">
|
<ng-container *ngIf="!module.handlerData.loading">
|
||||||
<ion-item id="core-course-module-{{module.id}}"
|
<ion-item class="ion-text-wrap">
|
||||||
class="ion-text-wrap core-course-module-handler core-module-main-item {{module.handlerData.class}}" [ngClass]="{
|
<ion-label>
|
||||||
'item-dimmed': module.visible === 0 || module.uservisible === false
|
<div class="activity-main">
|
||||||
}">
|
<core-mod-icon *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" [modname]="module.modname"
|
||||||
|
|
||||||
<core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" [modname]="module.modname"
|
|
||||||
[componentId]="module.instance" [fallbackTranslation]="module.modplural">
|
[componentId]="module.instance" [fallbackTranslation]="module.modplural">
|
||||||
</core-mod-icon>
|
</core-mod-icon>
|
||||||
|
<div class="activity-title">
|
||||||
<ion-label class="core-module-title">
|
|
||||||
<p class="item-heading">
|
<p class="item-heading">
|
||||||
<core-format-text [text]="module.handlerData.title" contextLevel="module" [contextInstanceId]="module.id"
|
<core-format-text [text]="module.handlerData.title" contextLevel="module" [contextInstanceId]="module.id"
|
||||||
[courseId]="module.course" [attr.aria-label]="module.handlerData.a11yTitle + ', ' + modNameTranslated">
|
[courseId]="module.course" [attr.aria-label]="module.handlerData.a11yTitle + ', ' + modNameTranslated">
|
||||||
|
@ -22,64 +21,71 @@
|
||||||
[attr.aria-label]="((prefetchStatusText$ | async) || '') | translate"></ion-icon>
|
[attr.aria-label]="((prefetchStatusText$ | async) || '') | translate"></ion-icon>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="core-module-additional-info">
|
<div class="core-module-additional-info" *ngIf="module.visible === 0 || (module.visible !== 0 && module.isStealth)">
|
||||||
<ion-chip *ngIf="module.handlerData.extraBadge" [color]="module.handlerData.extraBadgeColor"
|
|
||||||
class="ion-text-wrap ion-text-start" [outline]="true">
|
|
||||||
<ion-label><span [innerHTML]="module.handlerData.extraBadge"></span></ion-label>
|
|
||||||
</ion-chip>
|
|
||||||
|
|
||||||
<!-- Hidden badges -->
|
<!-- Hidden badges -->
|
||||||
<ion-badge color="warning" *ngIf="module.visible === 0" class="ion-text-wrap">
|
<ion-badge color="secondary" *ngIf="module.visible === 0" class="ion-text-wrap">
|
||||||
|
<ion-icon name="far-eye-slash" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.course.hiddenfromstudents' | translate }}
|
{{ 'core.course.hiddenfromstudents' | translate }}
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
<ion-badge color="warning" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap">
|
<ion-badge color="secondary" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap">
|
||||||
|
<ion-icon name="fas-low-vision" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.course.hiddenoncoursepage' | translate }}
|
{{ 'core.course.hiddenoncoursepage' | translate }}
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
</ion-label>
|
</div>
|
||||||
<!-- Buttons. -->
|
<!-- Buttons. -->
|
||||||
<div slot="end" *ngIf="module.uservisible !== false" class="buttons core-module-buttons"
|
<div *ngIf="module.uservisible !== false" class="core-module-buttons">
|
||||||
[ngClass]="{'core-button-completion': module.completiondata && showLegacyCompletion}">
|
|
||||||
<!-- Module completion (legacy). -->
|
<!-- Module completion (legacy). -->
|
||||||
<core-course-module-completion-legacy *ngIf="module.completiondata && showLegacyCompletion"
|
<core-course-module-completion-legacy *ngIf="module.completiondata && showLegacyCompletion"
|
||||||
[completion]="module.completiondata" [moduleName]="module.name" [moduleId]="module.id"
|
[completion]="module.completiondata" [moduleName]="module.name" [moduleId]="module.id"
|
||||||
(completionChanged)="completionChanged.emit($event)">
|
(completionChanged)="completionChanged.emit($event)">
|
||||||
</core-course-module-completion-legacy>
|
</core-course-module-completion-legacy>
|
||||||
|
|
||||||
<div class="core-module-buttons-more">
|
<!-- Activity completion. For tablets -->
|
||||||
<!-- Buttons defined by the module handler. -->
|
|
||||||
<ion-button fill="clear" *ngFor="let button of module.handlerData.buttons"
|
|
||||||
[hidden]="button.hidden || module.handlerData.spinner" class="core-animate-show-hide"
|
|
||||||
(click)="buttonClicked($event, button)" [attr.aria-label]="button.label | translate:{$a: module.handlerData.title}">
|
|
||||||
<ion-icon [name]="button.icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item *ngIf="hasInfo" id="core-course-module-{{module.id}}-info" detail="false"
|
|
||||||
class="ion-text-wrap core-course-module-handler core-course-module-info {{module.handlerData.class}}" [ngClass]="{
|
|
||||||
'item-dimmed': module.visible === 0 || module.uservisible === false
|
|
||||||
}">
|
|
||||||
<ion-label [collapsible-item]="64">
|
|
||||||
<core-format-text class="core-module-description" *ngIf="module.description" [text]="module.description"
|
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course">
|
|
||||||
</core-format-text>
|
|
||||||
|
|
||||||
<!-- Activity completion. -->
|
|
||||||
<core-course-module-completion *ngIf="hasCompletion && !showLegacyCompletion" [completion]="module.completiondata"
|
<core-course-module-completion *ngIf="hasCompletion && !showLegacyCompletion" [completion]="module.completiondata"
|
||||||
[moduleName]="module.name" [moduleId]="module.id" [showCompletionConditions]="showCompletionConditions"
|
[moduleName]="module.name" [moduleId]="module.id" [showCompletionConditions]="showCompletionConditions"
|
||||||
[showManualCompletion]="showManualCompletion" (completionChanged)="completionChanged.emit($event)">
|
[showManualCompletion]="showManualCompletion" (completionChanged)="completionChanged.emit($event)">
|
||||||
</core-course-module-completion>
|
</core-course-module-completion>
|
||||||
|
|
||||||
<div class="core-module-dates-availabilityinfo"
|
<!-- Button defined by the module handler. -->
|
||||||
*ngIf="(showActivityDates && module.dates && module.dates.length) || module.availabilityinfo">
|
<ion-button fill="clear" class="core-module-button-more core-animate-show-hide" *ngIf="module.handlerData.button"
|
||||||
|
[hidden]="module.handlerData.button.hidden || module.handlerData.spinner" (click)="buttonClicked($event)"
|
||||||
|
[attr.aria-label]="module.handlerData.button.label | translate:{$a: module.handlerData.title}">
|
||||||
|
<ion-icon [name]="module.handlerData.button.icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
|
||||||
|
<!-- @deprecated since 4.3. Buttons defined by the module handler. -->
|
||||||
|
<ion-button fill="clear" class="core-module-button-more core-animate-show-hide"
|
||||||
|
*ngIf="!module.handlerData.button && module.handlerData.buttons && module.handlerData.buttons[0]"
|
||||||
|
[hidden]="module.handlerData.buttons[0].hidden || module.handlerData.spinner" (click)="buttonClicked($event)"
|
||||||
|
[attr.aria-label]="module.handlerData.buttons[0].label | translate:{$a: module.handlerData.title}">
|
||||||
|
<ion-icon [name]="module.handlerData.buttons[0].icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Activity dates. -->
|
<!-- Activity dates. -->
|
||||||
<div *ngIf="showActivityDates && module.dates && module.dates.length" class="core-module-dates">
|
<div *ngIf="showActivityDates && module.dates?.length" class="activity-dates activity-extra">
|
||||||
<core-reminders-date *ngFor="let date of module.dates" [type]="date.id" [label]="date.label" [time]="date.timestamp"
|
<core-reminders-date *ngFor="let date of module.dates" [type]="date.id" [label]="date.label" [time]="date.timestamp"
|
||||||
[relativeTo]="date.relativeto">
|
[relativeTo]="date.relativeto">
|
||||||
</core-reminders-date>
|
</core-reminders-date>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Activity completion. -->
|
||||||
|
<core-course-module-completion class="activity-extra" *ngIf="hasCompletion && !showLegacyCompletion"
|
||||||
|
[completion]="module.completiondata" [moduleName]="module.name" [moduleId]="module.id"
|
||||||
|
[showCompletionConditions]="showCompletionConditions" [showManualCompletion]="showManualCompletion"
|
||||||
|
(completionChanged)="completionChanged.emit($event)">
|
||||||
|
</core-course-module-completion>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Description and restrictions -->
|
||||||
|
<div *ngIf="module.description || module.availabilityinfo" id="activity-{{module.id}}-collapsible"
|
||||||
|
class="ion-text-wrap activity-description-availabilityinfo activity-extra" [collapsible-item]="64">
|
||||||
|
<core-format-text class="core-module-description" *ngIf="module.description" [text]="module.description"
|
||||||
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course">
|
||||||
|
</core-format-text>
|
||||||
|
|
||||||
<!-- Availability info -->
|
<!-- Availability info -->
|
||||||
<div *ngIf="module.availabilityinfo" class="core-module-availabilityinfo">
|
<div *ngIf="module.availabilityinfo" class="core-module-availabilityinfo">
|
||||||
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
|
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
|
||||||
|
@ -89,7 +95,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="module.handlerData.extraBadge" class="ion-text-wrap activity-extrabadges activity-extra"
|
||||||
|
[innerHTML]="module.handlerData.extraBadge"></div>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<div class="core-course-last-module-viewed" *ngIf="isLastViewed">
|
<div class="core-course-last-module-viewed" *ngIf="isLastViewed">
|
||||||
|
@ -99,9 +108,8 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Loading. -->
|
<!-- Loading. -->
|
||||||
<ion-item *ngIf="module.handlerData.loading" role="status" class="ion-text-wrap" id="core-course-module-{{module.id}}"
|
<ion-item *ngIf="module.handlerData.loading" role="status" class="ion-text-wrap core-module-loading"
|
||||||
[attr.aria-label]="module.handlerData.a11yTitle"
|
[attr.aria-label]="module.handlerData.a11yTitle" detail="false">
|
||||||
[ngClass]="['core-course-module-handler', 'core-module-loading', module.handlerData.class]" detail="false">
|
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
<ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
|
@ -1,73 +1,148 @@
|
||||||
@import "~theme/globals";
|
@import "~theme/globals";
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
--horizontal-margin: 10px;
|
--horizontal-margin: 12px;
|
||||||
--vertical-margin: 10px;
|
--vertical-margin: 12px;
|
||||||
|
--card-padding: 16px;
|
||||||
|
|
||||||
ion-card {
|
ion-card {
|
||||||
margin: var(--vertical-margin) var(--horizontal-margin);
|
margin: var(--vertical-margin) var(--horizontal-margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item {
|
ion-item {
|
||||||
--padding-start: 12px;
|
--padding-start: var(--card-padding);
|
||||||
|
--inner-padding-end: var(--card-padding);
|
||||||
|
ion-label {
|
||||||
|
margin-top: var(--card-padding);
|
||||||
|
margin-bottom: var(--card-padding);
|
||||||
|
&>:last-child {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item.core-module-main-item {
|
.activity-main {
|
||||||
--min-height: 52px;
|
--min-height: 52px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
.core-module-title .item-heading ion-icon {
|
core-mod-icon {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
--module-icon-padding: 4px;
|
||||||
|
--module-icon-radius: var(--radius-xs);
|
||||||
|
|
||||||
|
@include margin-horizontal(null, 8px);
|
||||||
|
align-self: self-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-title {
|
||||||
|
flex-grow: 1;
|
||||||
|
align-self: center;
|
||||||
|
@include margin-horizontal(null, var(--card-padding));
|
||||||
|
|
||||||
|
.item-heading ion-icon {
|
||||||
@include margin-horizontal(8px, null);
|
@include margin-horizontal(8px, null);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-buttons,
|
|
||||||
.buttons.core-module-buttons {
|
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-buttons,
|
.core-module-buttons {
|
||||||
.core-module-buttons-more {
|
align-self: self-start;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row;
|
flex-flow: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
align-content: center;
|
align-content: center;
|
||||||
}
|
|
||||||
|
|
||||||
.core-module-buttons core-course-module-completion,
|
ion-button.core-module-button-more {
|
||||||
.core-module-buttons-more button {
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
margin: 0px 8px;
|
||||||
|
--a11y-target-min-size: 32px;
|
||||||
|
width: var(--a11y-target-min-size);
|
||||||
|
height: var(--a11y-target-min-size);
|
||||||
|
min-width: var(--a11y-target-min-size);
|
||||||
|
min-height: var(--a11y-target-min-size);
|
||||||
|
--padding-start: 0px;
|
||||||
|
--padding-end: 0px;
|
||||||
|
ion-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-buttons core-course-module-completion {
|
core-course-module-completion {
|
||||||
text-align: center;
|
--margin: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-additional-info {
|
.core-module-additional-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
|
||||||
|
ion-badge {
|
||||||
|
@include margin-horizontal(null, 4px);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-course-module-info {
|
.core-module-description ::ng-deep img {
|
||||||
.core-module-dates-availabilityinfo {
|
border-radius: var(--radius-lg);
|
||||||
background: var(--light);
|
|
||||||
border-radius: var(--radius-xs);
|
|
||||||
padding: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-dates + .core-module-availabilityinfo {
|
core-course-module-completion {
|
||||||
border-top: 1px solid var(--stroke);
|
--margin: 8px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-dates {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
core-reminders-date {
|
||||||
|
--display-icon: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-description-availabilityinfo,
|
||||||
|
.activity-extrabadges {
|
||||||
|
margin-top: 8px;
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
|
border-top: 1px solid var(--stroke);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.activity-extrabadges {
|
||||||
|
color: var(--gray-700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-description-availabilityinfo {
|
||||||
.core-module-availabilityinfo {
|
.core-module-availabilityinfo {
|
||||||
font-size: 90%;
|
background: var(--gray-300);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 120%;
|
||||||
|
|
||||||
::ng-deep ul {
|
::ng-deep ul {
|
||||||
margin-top: 0.5em;
|
margin-top: 8px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
@include margin-horizontal(null, 8px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,19 +154,6 @@
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.core-module-main-item + .core-course-module-info ion-label {
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.core-module-availabilityinfo ion-icon,
|
|
||||||
.core-module-dates ion-icon {
|
|
||||||
@include margin-horizontal(null, 8px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.core-course-module-info ::ng-deep core-course-module-completion .core-module-automatic-completion-conditions .completioninfo.completion_complete {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.core-course-last-module-viewed {
|
.core-course-last-module-viewed {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
color: var(--subdued-text-color);
|
color: var(--subdued-text-color);
|
||||||
|
@ -102,14 +164,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
.core-module-buttons core-course-module-completion {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
core-course-module-completion.activity-extra {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.indented ion-card {
|
&.indented ion-card {
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 0;
|
--ion-card-radius: 0;
|
||||||
margin-inline-start: calc(var(--horizontal-margin) + 1rem);
|
@include margin-horizontal(calc(var(--horizontal-margin) + 1rem), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.indented + ::ng-deep core-course-module.indented ion-card {
|
&.indented + ::ng-deep core-course-module.indented ion-card {
|
||||||
border-top: 1px solid var(--border-color);
|
border-top: 1px solid var(--border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,8 @@ import {
|
||||||
CoreCourseSection,
|
CoreCourseSection,
|
||||||
CoreCourseHelper,
|
CoreCourseHelper,
|
||||||
} from '@features/course/services/course-helper';
|
} from '@features/course/services/course-helper';
|
||||||
import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseModuleCompletionTracking } from '@features/course/services/course';
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreCourseModuleDelegate, CoreCourseModuleHandlerButton } from '@features/course/services/module-delegate';
|
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
|
||||||
import {
|
import {
|
||||||
CoreCourseModulePrefetchDelegate,
|
CoreCourseModulePrefetchDelegate,
|
||||||
CoreCourseModulePrefetchHandler,
|
CoreCourseModulePrefetchHandler,
|
||||||
|
@ -55,7 +55,6 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
|
||||||
@HostBinding('class.indented') indented = false;
|
@HostBinding('class.indented') indented = false;
|
||||||
|
|
||||||
modNameTranslated = '';
|
modNameTranslated = '';
|
||||||
hasInfo = false;
|
|
||||||
hasCompletion = false; // Whether activity has completion to be shown.
|
hasCompletion = false; // Whether activity has completion to be shown.
|
||||||
showManualCompletion = false; // Whether to show manual completion when completion conditions are disabled.
|
showManualCompletion = false; // Whether to show manual completion when completion conditions are disabled.
|
||||||
prefetchStatusIcon$ = new BehaviorSubject<string>(''); // Module prefetch status icon.
|
prefetchStatusIcon$ = new BehaviorSubject<string>(''); // Module prefetch status icon.
|
||||||
|
@ -87,13 +86,6 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
|
||||||
this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title;
|
this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title;
|
||||||
this.moduleHasView = CoreCourse.moduleHasView(this.module);
|
this.moduleHasView = CoreCourse.moduleHasView(this.module);
|
||||||
|
|
||||||
this.hasInfo = !!(
|
|
||||||
this.module.description ||
|
|
||||||
(this.showActivityDates && this.module.dates && this.module.dates.length) ||
|
|
||||||
(this.hasCompletion && !this.showLegacyCompletion) ||
|
|
||||||
(this.module.availabilityinfo)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.module.handlerData?.showDownloadButton) {
|
if (this.module.handlerData?.showDownloadButton) {
|
||||||
const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(this.module, this.module.course);
|
const status = await CoreCourseModulePrefetchDelegate.getModuleStatus(this.module, this.module.course);
|
||||||
this.updateModuleStatus(status);
|
this.updateModuleStatus(status);
|
||||||
|
@ -177,9 +169,9 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
|
||||||
* Function called when a button is clicked.
|
* Function called when a button is clicked.
|
||||||
*
|
*
|
||||||
* @param event Click event.
|
* @param event Click event.
|
||||||
* @param button The clicked button.
|
|
||||||
*/
|
*/
|
||||||
buttonClicked(event: Event, button: CoreCourseModuleHandlerButton): void {
|
buttonClicked(event: Event): void {
|
||||||
|
const button = this.module.handlerData?.button ?? this.module.handlerData?.buttons?.[0];
|
||||||
if (!button || !button.action) {
|
if (!button || !button.action) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,17 +29,18 @@
|
||||||
<core-course-module-info [module]="module" [courseId]="courseId" [description]="module.description" [component]="module.modname"
|
<core-course-module-info [module]="module" [courseId]="courseId" [description]="module.description" [component]="module.modname"
|
||||||
[componentId]="module.id" [expandDescription]="true" [showAvailabilityInfo]="true" (completionChanged)="onCompletionChange()"
|
[componentId]="module.id" [expandDescription]="true" [showAvailabilityInfo]="true" (completionChanged)="onCompletionChange()"
|
||||||
[showManualCompletion]="showManualCompletion">
|
[showManualCompletion]="showManualCompletion">
|
||||||
<div class="core-module-additional-info" title>
|
|
||||||
<ion-chip *ngIf="module.handlerData?.extraBadge" [color]="module.handlerData?.extraBadgeColor"
|
<div class="core-module-additional-info">
|
||||||
class="ion-text-wrap ion-text-start" [outline]="true">
|
<p *ngIf="module.handlerData?.extraBadge" class="ion-text-wrap" [innerHTML]="module.handlerData?.extraBadge">
|
||||||
<ion-label><span [innerHTML]="module.handlerData?.extraBadge"></span></ion-label>
|
</p>
|
||||||
</ion-chip>
|
|
||||||
|
|
||||||
<!-- Hidden badges -->
|
<!-- Hidden badges -->
|
||||||
<ion-badge color="warning" *ngIf="module.visible === 0" class="ion-text-wrap">
|
<ion-badge color="secondary" *ngIf="module.visible === 0" class="ion-text-wrap">
|
||||||
|
<ion-icon name="far-eye-slash" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.course.hiddenfromstudents' | translate }}
|
{{ 'core.course.hiddenfromstudents' | translate }}
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
<ion-badge color="warning" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap">
|
<ion-badge color="secondary" *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap">
|
||||||
|
<ion-icon name="fas-low-vision" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.course.hiddenoncoursepage' | translate }}
|
{{ 'core.course.hiddenoncoursepage' | translate }}
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -156,6 +156,8 @@ export interface CoreCourseModuleHandlerData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The color of the extra badge. Default: primary.
|
* The color of the extra badge. Default: primary.
|
||||||
|
*
|
||||||
|
* @deprecated since 4.3 Not used anymore.
|
||||||
*/
|
*/
|
||||||
extraBadgeColor?: CoreIonicColorNames;
|
extraBadgeColor?: CoreIonicColorNames;
|
||||||
|
|
||||||
|
@ -168,9 +170,16 @@ export interface CoreCourseModuleHandlerData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The buttons to display in the module item.
|
* The buttons to display in the module item.
|
||||||
|
*
|
||||||
|
* @deprecated since 4.3 Use button instead. It will only display the first.
|
||||||
*/
|
*/
|
||||||
buttons?: CoreCourseModuleHandlerButton[];
|
buttons?: CoreCourseModuleHandlerButton[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The button to display in the module item.
|
||||||
|
*/
|
||||||
|
button?: CoreCourseModuleHandlerButton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to display a spinner where the download button is displayed. The module icon, title, etc. will be displayed.
|
* Whether to display a spinner where the download button is displayed. The module icon, title, etc. will be displayed.
|
||||||
*/
|
*/
|
||||||
|
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
|
@ -3,6 +3,8 @@
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
margin-top: 8px;
|
||||||
|
@include margin-horizontal(null, 8px);
|
||||||
}
|
}
|
||||||
|
|
||||||
div {
|
div {
|
||||||
|
@ -12,10 +14,7 @@ div {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
|
display: var(--display-icon, inline-block);
|
||||||
@include margin-horizontal(0px, 4px);
|
@include margin-horizontal(0px, 4px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
core-reminders-date + :host {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
.item.core-course-module-handler.addon-mod-label-handler {
|
.core-course-module-handler.addon-mod-label-handler {
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
cursor: auto !important;
|
cursor: auto !important;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.activity-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.item-heading {
|
||||||
|
order: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,9 @@ html {
|
||||||
--subdued-text-color: var(--medium);
|
--subdued-text-color: var(--medium);
|
||||||
|
|
||||||
--ion-card-color: var(--text-color);
|
--ion-card-color: var(--text-color);
|
||||||
--ion-card-vertical-margin: 10px;
|
--ion-card-vertical-margin: 12px;
|
||||||
--ion-card-horizontal-margin: 10px;
|
--ion-card-horizontal-margin: 12px;
|
||||||
--ion-card-radius: var(--radius-sm);
|
--ion-card-radius: var(--radius-lg);
|
||||||
--ion-card-border-width: 1px;
|
--ion-card-border-width: 1px;
|
||||||
--ion-card-border-color: var(--stroke);
|
--ion-card-border-color: var(--stroke);
|
||||||
ion-card {
|
ion-card {
|
||||||
|
|
|
@ -7,6 +7,7 @@ information provided here is intended especially for developers.
|
||||||
- Font Awesome icon library has been updated to 6.4.0. But nothing has changed, only version number.
|
- Font Awesome icon library has been updated to 6.4.0. But nothing has changed, only version number.
|
||||||
- The analytics system in the app has been refactored and some functions that could trigger analytics calls no longer do it, now you need to use CoreAnalytics instead. Some functions in CoreCourseLogHelper and CorePushNotificationsProvider have been deprecated.
|
- The analytics system in the app has been refactored and some functions that could trigger analytics calls no longer do it, now you need to use CoreAnalytics instead. Some functions in CoreCourseLogHelper and CorePushNotificationsProvider have been deprecated.
|
||||||
- Due to the analytics refactor, the parameters of most log functions have changed.
|
- Due to the analytics refactor, the parameters of most log functions have changed.
|
||||||
|
- CoreCourseModuleHandlerData.buttons has been deprecated, now only one button in atribute button will be shown.
|
||||||
|
|
||||||
=== 4.2.0 ===
|
=== 4.2.0 ===
|
||||||
|
|
||||||
|
|