diff --git a/src/addons/mod/bigbluebuttonbn/services/handlers/module.ts b/src/addons/mod/bigbluebuttonbn/services/handlers/module.ts index 2f543185a..ee71b6308 100644 --- a/src/addons/mod/bigbluebuttonbn/services/handlers/module.ts +++ b/src/addons/mod/bigbluebuttonbn/services/handlers/module.ts @@ -45,7 +45,7 @@ export class AddonModBBBModuleHandlerService extends CoreModuleHandlerBase imple [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, - [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_OTHER, + [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_COMMUNICATION, }; /** diff --git a/src/addons/mod/h5pactivity/services/handlers/module.ts b/src/addons/mod/h5pactivity/services/handlers/module.ts index c6473702b..0148587d1 100644 --- a/src/addons/mod/h5pactivity/services/handlers/module.ts +++ b/src/addons/mod/h5pactivity/services/handlers/module.ts @@ -42,7 +42,7 @@ export class AddonModH5PActivityModuleHandlerService extends CoreModuleHandlerBa [CoreConstants.FEATURE_GRADE_HAS_GRADE]: true, [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, - [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, + [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT, }; /** diff --git a/src/addons/mod/imscp/services/handlers/module.ts b/src/addons/mod/imscp/services/handlers/module.ts index 369c111cc..0039e6a8f 100644 --- a/src/addons/mod/imscp/services/handlers/module.ts +++ b/src/addons/mod/imscp/services/handlers/module.ts @@ -42,7 +42,7 @@ export class AddonModImscpModuleHandlerService extends CoreModuleHandlerBase imp [CoreConstants.FEATURE_GRADE_OUTCOMES]: false, [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, - [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, + [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT, }; /** diff --git a/src/addons/mod/lesson/services/handlers/module.ts b/src/addons/mod/lesson/services/handlers/module.ts index 897b65381..1bf2ec0f1 100644 --- a/src/addons/mod/lesson/services/handlers/module.ts +++ b/src/addons/mod/lesson/services/handlers/module.ts @@ -42,7 +42,7 @@ export class AddonModLessonModuleHandlerService extends CoreModuleHandlerBase im [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, - [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, + [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT, }; /** diff --git a/src/addons/mod/lti/services/handlers/module.ts b/src/addons/mod/lti/services/handlers/module.ts index 70c8ce34a..f683c8190 100644 --- a/src/addons/mod/lti/services/handlers/module.ts +++ b/src/addons/mod/lti/services/handlers/module.ts @@ -44,7 +44,7 @@ export class AddonModLtiModuleHandlerService extends CoreModuleHandlerBase imple [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, - [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, + [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_OTHER, }; /** diff --git a/src/addons/mod/scorm/services/handlers/module.ts b/src/addons/mod/scorm/services/handlers/module.ts index aacc38544..ab61d2220 100644 --- a/src/addons/mod/scorm/services/handlers/module.ts +++ b/src/addons/mod/scorm/services/handlers/module.ts @@ -41,7 +41,7 @@ export class AddonModScormModuleHandlerService extends CoreModuleHandlerBase imp [CoreConstants.FEATURE_GRADE_OUTCOMES]: true, [CoreConstants.FEATURE_BACKUP_MOODLE2]: true, [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true, - [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, + [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT, }; /** diff --git a/src/core/classes/sites/authenticated-site.ts b/src/core/classes/sites/authenticated-site.ts index d013a5a80..ed6f6b43d 100644 --- a/src/core/classes/sites/authenticated-site.ts +++ b/src/core/classes/sites/authenticated-site.ts @@ -1431,7 +1431,7 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite { } } } - } else if (typeof versions == 'string') { + } else if (typeof versions === 'string') { // Compare with this version. return siteVersion >= this.getVersionNumber(versions); } diff --git a/src/core/components/mod-icon/mod-icon.html b/src/core/components/mod-icon/mod-icon.html index 46777347a..859b0e087 100644 --- a/src/core/components/mod-icon/mod-icon.html +++ b/src/core/components/mod-icon/mod-icon.html @@ -1,5 +1,7 @@ - - + +
diff --git a/src/core/components/mod-icon/mod-icon.scss b/src/core/components/mod-icon/mod-icon.scss index 37913a25e..5bf78a037 100644 --- a/src/core/components/mod-icon/mod-icon.scss +++ b/src/core/components/mod-icon/mod-icon.scss @@ -2,7 +2,7 @@ :host { display: inline-block; - --size: var(--module-icon-size, 24px); + --size: var(--module-icon-size, 32px); --padding: var(--module-icon-padding, 8px); --icon-radius: var(--module-icon-radius, var(--radius-xs)); --margin-end: 0px; @@ -14,16 +14,43 @@ border-radius: var(--icon-radius); padding: var(--padding); - background-color: $gray-100; + background-color: transparent; line-height: var(--size); - @each $type, $value in $activity-icon-colors { - &.#{$type} { - background-color: var(--activity#{$type}); - img { - filter: var(--filter, brightness(0) invert(1)); + &.version_current { + @each $type, $value in $activity-icon-color-filters { + &.#{$type} { + --filter: var(--activity#{$type}); } } + + img { + filter: var(--filter, brightness(0) invert(1)); + } + } + + &.version_40 { + --size: var(--module-icon-size, 24px); + background-color: $gray-100; + + @each $type, $value in $activity-icon-background-colors { + &.#{$type} { + background-color: var(--activity-40-#{$type}); + img { + filter: var(--filter, brightness(0) invert(1)); + } + } + } + } + + &.version_legacy { + --size: var(--module-icon-size, 24px); + --filter: none; + background-color: $gray-100; + } + + &.no-filter { + --filter: none !important; } } @@ -41,11 +68,6 @@ img { white-space: nowrap; overflow: hidden; } - - &.no-filter { - --filter: none; - } - } :host-context(ion-item) { diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index db317f61b..0318d0d79 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -13,7 +13,7 @@ // limitations under the License. import { CoreConstants, ModPurpose } from '@/core/constants'; -import { Component, ElementRef, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; +import { Component, ElementRef, HostBinding, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreSites } from '@services/sites'; @@ -23,6 +23,12 @@ import { CoreUrlUtils } from '@services/utils/url'; const assetsPath = 'assets/img/'; const fallbackModName = 'external-tool'; +const enum IconVersion { + LEGACY_VERSION = 'version_legacy', + VERSION_4_0 = 'version_40', + CURRENT_VERSION = 'version_current', +} + /** * Component to handle a module icon. */ @@ -33,6 +39,8 @@ const fallbackModName = 'external-tool'; }) export class CoreModIconComponent implements OnInit, OnChanges { + @HostBinding('class.no-filter') noFilter = false; + @Input() modname = ''; // The module name. Used also as component if set. @Input() fallbackTranslation = ''; // Fallback translation string if cannot auto translate. @Input() componentId?: number; // Component Id for external icons. @@ -41,12 +49,12 @@ export class CoreModIconComponent implements OnInit, OnChanges { @Input() purpose: ModPurpose = ModPurpose.MOD_PURPOSE_OTHER; // Purpose of the module. icon = ''; - noFilter = false; + modNameTranslated = ''; isLocalUrl = true; linkIconWithComponent = false; - protected legacyIcon = true; // @deprecatedonmoodle since 3.11. + @HostBinding('class') iconVersion = 'legacy'; constructor(protected el: ElementRef) { } @@ -54,22 +62,35 @@ export class CoreModIconComponent implements OnInit, OnChanges { * @inheritdoc */ async ngOnInit(): Promise { + this.iconVersion = this.getIconVersion(); + if (!this.modname && this.modicon) { // Guess module from the icon url. this.modname = this.getComponentNameFromIconUrl(this.modicon); } this.modNameTranslated = CoreCourse.translateModuleName(this.modname, this.fallbackTranslation); - if (CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('4.0')) { - this.legacyIcon = false; + if (this.iconVersion !== IconVersion.LEGACY_VERSION) { - const purposeClass = + let purposeClass = CoreCourseModuleDelegate.supportsFeature( this.modname || '', CoreConstants.FEATURE_MOD_PURPOSE, this.purpose, ); + if (this.iconVersion === IconVersion.VERSION_4_0) { + if (purposeClass === ModPurpose.MOD_PURPOSE_INTERACTIVECONTENT) { + // Interactive content was introduced on 4.4, on previous versions CONTENT is used instead. + purposeClass = ModPurpose.MOD_PURPOSE_CONTENT; + } + + if (this.modname === 'lti') { + // LTI had content purpose with 4.0 icons. + purposeClass = ModPurpose.MOD_PURPOSE_CONTENT; + } + } + if (purposeClass) { const element: HTMLElement = this.el.nativeElement; element.classList.add(purposeClass); @@ -129,13 +150,13 @@ export class CoreModIconComponent implements OnInit, OnChanges { */ protected async getIconNoFilter(): Promise { // Earlier 4.0, icons were never filtered. - if (this.legacyIcon) { + if (this.iconVersion === IconVersion.LEGACY_VERSION) { return true; } // No icon or local icon (not legacy), filter it. if (!this.icon || this.isLocalUrl) { - return false; + return await CoreCourseModuleDelegate.moduleIconIsBranded(this.modname); } this.icon = CoreTextUtils.decodeHTMLEntities(this.icon); @@ -192,4 +213,23 @@ export class CoreModIconComponent implements OnInit, OnChanges { return component; } + /** + * Get the icon version depending on site version. + * + * @returns Icon version. + */ + protected getIconVersion(): IconVersion { + if (!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('4.0')) { + // @deprecatedonmoodle since 3.11. + return IconVersion.LEGACY_VERSION; + } + + if (!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('4.4')) { + // @deprecatedonmoodle since 4.3. + return IconVersion.VERSION_4_0; + } + + return IconVersion.CURRENT_VERSION; + } + } diff --git a/src/core/constants.ts b/src/core/constants.ts index e3a6ce330..25504259b 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -41,7 +41,8 @@ export const enum ModPurpose { MOD_PURPOSE_COLLABORATION = 'collaboration', MOD_PURPOSE_CONTENT = 'content', MOD_PURPOSE_ADMINISTRATION = 'administration', - MOD_PURPOSE_INTERFACE = 'interface', + MOD_PURPOSE_INTERFACE = 'interface', // @deprecatedonmoodle since 4.4. + MOD_PURPOSE_INTERACTIVECONTENT = 'interactivecontent', MOD_PURPOSE_OTHER = 'other', } diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html index 244e2d406..b72768c72 100644 --- a/src/core/features/course/components/module-info/core-course-module-info.html +++ b/src/core/features/course/components/module-info/core-course-module-info.html @@ -1,5 +1,5 @@ - +

+ [fallbackTranslation]="module.modplural" [purpose]="module.purpose" /> {{moduleNameTranslated}}

diff --git a/src/core/features/course/components/module/core-course-module.html b/src/core/features/course/components/module/core-course-module.html index d4f3da3c6..cbcfd1daa 100644 --- a/src/core/features/course/components/module/core-course-module.html +++ b/src/core/features/course/components/module/core-course-module.html @@ -8,7 +8,7 @@
+ [componentId]="module.instance" [fallbackTranslation]="module.modplural" [purpose]="module.purpose" />

; + + /** + * Whether the activity is branded. + * This information is used, for instance, to decide if a filter should be applied to the icon or not. + * + * @returns bool True if the activity is branded, false otherwise. + */ + isBranded?(): Promise; } /** diff --git a/src/theme/globals.variables.scss b/src/theme/globals.variables.scss index ba409da53..ede99747b 100644 --- a/src/theme/globals.variables.scss +++ b/src/theme/globals.variables.scss @@ -115,8 +115,8 @@ $core-user-hide-siteinfo: $core-more-hide-siteinfo !default; $core-user-hide-sitename: $core-more-hide-sitename !default; $core-user-hide-siteurl: $core-more-hide-siteurl !default; -// Activity icon background colors. -$activity-icon-colors: ( +// Activity icon background colors. Only used on 4.0-4.3. @deprecatedonmoodle since 4.4. +$activity-icon-background-colors: ( administration: #5d63f6, assessment: #eb66a2, collaboration: #f7634d, @@ -125,6 +125,25 @@ $activity-icon-colors: ( interface: #a378ff ) !default; +// Moodle 4.4 onwards. +$activity-icon-colors: ( + administration: #da58ef, + assessment: #f90086, + collaboration: #5b40ff, + communication: #eb6200, + content: #0099ad, + interactivecontent: #8d3d1b +) !default; + +$activity-icon-color-filters: ( + administration: invert(45%) sepia(46%) saturate(3819%) hue-rotate(260deg) brightness(101%) contrast(87%), + assessment: invert(36%) sepia(98%) saturate(6969%) hue-rotate(315deg) brightness(90%) contrast(119%), + collaboration: invert(25%) sepia(54%) saturate(6226%) hue-rotate(245deg) brightness(100%) contrast(102%), + communication: invert(48%) sepia(74%) saturate(4887%) hue-rotate(11deg) brightness(102%) contrast(101%), + content: invert(49%) sepia(52%) saturate(4675%) hue-rotate(156deg) brightness(89%) contrast(102%), + interactivecontent: invert(25%) sepia(63%) saturate(1152%) hue-rotate(344deg) brightness(94%) contrast(91%) +) !default; + $calendar-event-category-category: #8e24aa !default; $calendar-event-category-course: $red !default; $calendar-event-category-group: $yellow !default; diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss index 79cb58582..b87a21c3f 100644 --- a/src/theme/theme.light.scss +++ b/src/theme/theme.light.scss @@ -404,10 +404,15 @@ html { } // Make activtity colours available for custom modules. - @each $type, $value in $activity-icon-colors { + @each $type, $value in $activity-icon-color-filters { --activity#{$type}: #{$value}; } + // Make activtity colours available for custom modules. + @each $type, $value in $activity-icon-background-colors { + --activity-40-#{$type}: #{$value}; + } + --core-mainpage-sitename-display: none; --core-mainpage-headerlogo-display: none; --core-mainpage-headerlogo-maxheight: calc(var(--core-header-toolbar-height) - 16px);