diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts index a889ac9ed..0eaab6861 100644 --- a/src/addons/mod/resource/services/handlers/module.ts +++ b/src/addons/mod/resource/services/handlers/module.ts @@ -95,7 +95,7 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase this.getResourceData(module, courseId, handlerData).then((extra) => { handlerData.extraBadge = extra; - handlerData.extraBadgeColor = 'light'; + handlerData.extraBadgeColor = ''; return; }).catch(() => { diff --git a/src/core/features/course/components/course-index/course-index.ts b/src/core/features/course/components/course-index/course-index.ts index 87c653fb2..712e87e37 100644 --- a/src/core/features/course/components/course-index/course-index.ts +++ b/src/core/features/course/components/course-index/course-index.ts @@ -14,7 +14,7 @@ import { Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { CoreCourseModuleData, CoreCourseSectionWithStatus } from '@features/course/services/course-helper'; +import { CoreCourseModuleData, CoreCourseSection } from '@features/course/services/course-helper'; import { CoreCourseModuleCompletionStatus, CoreCourseModuleCompletionTracking, @@ -126,7 +126,7 @@ export class CoreCourseCourseIndexComponent implements OnInit { * @param event Event. * @param section Selected section object. */ - selectSection(event: Event, section: CoreCourseSectionWithStatus): void { + selectSection(event: Event, section: CoreCourseSection): void { if (section.uservisible !== false) { ModalController.dismiss({ event, section }); } @@ -139,7 +139,7 @@ export class CoreCourseCourseIndexComponent implements OnInit { * @param section Selected section object. * @param module Selected module object. */ - selectModule(event: Event,section: CoreCourseSectionWithStatus, module: CoreCourseModuleData): void { + selectModule(event: Event,section: CoreCourseSection, module: CoreCourseModuleData): void { if (module.uservisible !== false) { ModalController.dismiss({ event, section, module }); } @@ -147,7 +147,7 @@ export class CoreCourseCourseIndexComponent implements OnInit { } -type CourseIndexSection = Omit & { +type CourseIndexSection = Omit & { highlighted?: boolean; expanded?: boolean; modules: (CoreCourseModuleData & { diff --git a/src/core/features/course/components/format/core-course-format.html b/src/core/features/course/components/format/core-course-format.html index 1b34598a3..3c8036beb 100644 --- a/src/core/features/course/components/format/core-course-format.html +++ b/src/core/features/course/components/format/core-course-format.html @@ -74,19 +74,23 @@ -

- +

+ + {{ 'core.course.hiddenfromstudents' | translate }} - + + {{ 'core.notavailable' | translate }} - + +

+ {{highlighted}} diff --git a/src/core/features/course/components/format/format.ts b/src/core/features/course/components/format/format.ts index 760637898..25a3cd218 100644 --- a/src/core/features/course/components/format/format.ts +++ b/src/core/features/course/components/format/format.ts @@ -38,7 +38,6 @@ import { CoreCourseModuleData, CoreCourseModuleCompletionData, CoreCourseSection, - CoreCourseSectionWithStatus, } from '@features/course/services/course-helper'; import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; @@ -47,7 +46,6 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreCourseCourseIndexComponent, CoreCourseIndexSectionWithModule } from '../course-index/course-index'; import { CoreBlockHelper } from '@features/block/services/block-helper'; import { CoreNavigator } from '@services/navigator'; -import { database } from 'faker'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; /** @@ -70,7 +68,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { static readonly LOAD_MORE_ACTIVITIES = 20; // How many activities should load each time showMoreActivities is called. @Input() course!: CoreCourseAnyCourseData; // The course to render. - @Input() sections: CoreCourseSectionWithStatus[] = []; // List of course sections. + @Input() sections: CoreCourseSectionToDisplay[] = []; // List of course sections. @Input() initialSectionId?: number; // The section to load first (by ID). @Input() initialSectionNumber?: number; // The section to load first (by number). @Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section. @@ -98,6 +96,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { stealthModulesSectionId: number = CoreCourseProvider.STEALTH_MODULES_SECTION_ID; loaded = false; progress?: number; + highlighted?: string; protected selectTabObserver?: CoreEventObserver; protected completionObserver?: CoreEventObserver; @@ -220,6 +219,10 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { // Format has changed or it's the first time, load all the components. this.lastCourseFormat = this.course.format; + this.highlighted = CoreCourseFormatDelegate.getSectionHightlightedName(this.course); + const currentSection = await CoreCourseFormatDelegate.getCurrentSection(this.course, this.sections); + currentSection.highlighted = true; + await Promise.all([ this.loadCourseFormatComponent(), this.loadCourseSummaryComponent(), @@ -559,3 +562,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { } } + +type CoreCourseSectionToDisplay = CoreCourseSection & { + highlighted?: boolean; +}; diff --git a/src/core/features/course/components/module-completion/core-course-module-completion.html b/src/core/features/course/components/module-completion/core-course-module-completion.html index 571e9f15a..dbdc18616 100644 --- a/src/core/features/course/components/module-completion/core-course-module-completion.html +++ b/src/core/features/course/components/module-completion/core-course-module-completion.html @@ -4,16 +4,19 @@ + {{ 'core.course.completion_automatic:done' | translate }} {{ rule.rulevalue.description }} + {{ 'core.course.completion_automatic:failed' | translate }} {{ rule.rulevalue.description }} - + + {{ 'core.course.completion_automatic:todo' | translate }} {{ rule.rulevalue.description }} 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 88060b6ca..864dd98a5 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 @@ -19,12 +19,21 @@ - - + + -

- {{ date.label }} {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }} -

+ +
+

+ {{ date.label }} {{ date.timestamp * 1000 | + coreFormatDate:'strftimedatetime' }} +

+
+ + +
diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss index 514315b48..f540001d2 100644 --- a/src/core/features/course/components/module-info/course-module-info.scss +++ b/src/core/features/course/components/module-info/course-module-info.scss @@ -16,4 +16,9 @@ core-mod-icon { align-self: flex-start; } + + .core-module-dates ion-icon { + @include margin-horizontal(null, 8px); + } + } diff --git a/src/core/features/course/components/module-manual-completion/core-course-module-manual-completion.html b/src/core/features/course/components/module-manual-completion/core-course-module-manual-completion.html index d205a5a65..8f8e5d6e3 100644 --- a/src/core/features/course/components/module-manual-completion/core-course-module-manual-completion.html +++ b/src/core/features/course/components/module-manual-completion/core-course-module-manual-completion.html @@ -2,22 +2,20 @@ - + {{ 'core.course.completion_manual:done' | translate }} - + {{ 'core.course.completion_manual:markdone' | translate }} - + {{ 'core.course.completion_manual:markdone' | translate }} diff --git a/src/core/features/course/components/module-navigation/core-course-module-navigation.html b/src/core/features/course/components/module-navigation/core-course-module-navigation.html index 7d0fde92d..497b0e42e 100644 --- a/src/core/features/course/components/module-navigation/core-course-module-navigation.html +++ b/src/core/features/course/components/module-navigation/core-course-module-navigation.html @@ -6,12 +6,10 @@ - + + [moduleId]="currentModule.id" [showManualCompletion]="true" (completionChanged)="completionChanged.emit($event)"> 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 1f5af1171..adfa73f2a 100644 --- a/src/core/features/course/components/module/core-course-module.html +++ b/src/core/features/course/components/module/core-course-module.html @@ -18,25 +18,26 @@ [courseId]="module.course" [attr.aria-label]="module.handlerData.a11yTitle + ', ' + modNameTranslated">

- - - - - {{ 'core.course.hiddenfromstudents' | translate }} - - - {{ 'core.course.hiddenoncoursepage' | translate }} - -
- {{ 'core.restricted' | translate }} - - -
- - {{ 'core.course.manualcompletionnotsynced' | translate }} - + + + + {{ 'core.course.todo' | translate }} + + + + + {{'core.course.done' | translate }} + + + + {{'core.course.failed' | translate }} + + + + +
+ + +

- {{ date.label }} {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }} + {{ date.label }} {{ date.timestamp * + 1000 | coreFormatDate:'strftimedatetime' }}

@@ -76,9 +82,31 @@ [showManualCompletion]="showManualCompletion" (completionChanged)="completionChanged.emit($event)"> - - + + + {{ 'core.course.manualcompletionnotsynced' | translate }} + + + + + + {{ 'core.course.hiddenfromstudents' | translate }} + + + + + {{ 'core.course.hiddenoncoursepage' | translate }} + + + + + + + + + +
diff --git a/src/core/features/course/components/module/module.scss b/src/core/features/course/components/module/module.scss index 2253562e5..faf96e525 100644 --- a/src/core/features/course/components/module/module.scss +++ b/src/core/features/course/components/module/module.scss @@ -1,3 +1,5 @@ +@import "~theme/globals"; + :host { .item.core-module-main-item { @@ -59,4 +61,9 @@ --inner-border-width: 0px; } + .core-module-availabilityinfo ion-icon, + .core-module-dates ion-icon { + @include margin-horizontal(null, 8px); + } + } diff --git a/src/core/features/course/components/module/module.ts b/src/core/features/course/components/module/module.ts index 936901f5f..287c2a484 100644 --- a/src/core/features/course/components/module/module.ts +++ b/src/core/features/course/components/module/module.ts @@ -20,7 +20,7 @@ import { CoreCourseModuleCompletionData, CoreCourseSection, } from '@features/course/services/course-helper'; -import { CoreCourse } from '@features/course/services/course'; +import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseModuleCompletionTracking } from '@features/course/services/course'; import { CoreCourseModuleDelegate, CoreCourseModuleHandlerButton } from '@features/course/services/module-delegate'; /** @@ -47,6 +47,7 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { hasInfo = false; showLegacyCompletion = false; // Whether to show module completion in the old format. showManualCompletion = false; // Whether to show manual completion when completion conditions are disabled. + completionStatus?: CoreCourseModuleCompletionStatus; /** * Component being initialized. @@ -61,13 +62,22 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { } this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title; + this.completionStatus = this.module.completiondata === undefined || + this.module.completiondata.tracking == CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE + ? undefined + : this.module.completiondata.state; + this.hasInfo = !!( this.module.description || (this.showActivityDates && this.module.dates && this.module.dates.length) || (this.module.completiondata && ((this.showManualCompletion && !this.module.completiondata.isautomatic) || (this.showCompletionConditions && this.module.completiondata.isautomatic)) - ) + ) || + this.module.completiondata?.offline || + (this.module.visible === 0 && (!this.section || this.section.visible)) || + (this.module.visible !== 0 && this.module.isStealth) || + (this.module.availabilityinfo) ); } diff --git a/src/core/features/course/format/singleactivity/components/singleactivity.ts b/src/core/features/course/format/singleactivity/components/singleactivity.ts index b3d11a9d7..499d7f805 100644 --- a/src/core/features/course/format/singleactivity/components/singleactivity.ts +++ b/src/core/features/course/format/singleactivity/components/singleactivity.ts @@ -19,7 +19,7 @@ import { CoreCourseUnsupportedModuleComponent } from '@features/course/component import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component'; import { CoreCourseAnyCourseData } from '@features/courses/services/courses'; import { IonRefresher } from '@ionic/angular'; -import { CoreCourseModuleCompletionData, CoreCourseSectionWithStatus } from '@features/course/services/course-helper'; +import { CoreCourseModuleCompletionData, CoreCourseSection } from '@features/course/services/course-helper'; import { CoreBlockHelper } from '@features/block/services/block-helper'; import { CoreCourse } from '@features/course/services/course'; @@ -36,7 +36,7 @@ import { CoreCourse } from '@features/course/services/course'; export class CoreCourseFormatSingleActivityComponent implements OnChanges { @Input() course?: CoreCourseAnyCourseData; // The course to render. - @Input() sections?: CoreCourseSectionWithStatus[]; // List of course sections. + @Input() sections?: CoreCourseSection[]; // List of course sections. @Input() initialSectionId?: number; // The section to load first (by ID). @Input() initialSectionNumber?: number; // The section to load first (by number). @Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section. diff --git a/src/core/features/course/pages/module-preview/module-preview.html b/src/core/features/course/pages/module-preview/module-preview.html index 711f8c740..bd5b02506 100644 --- a/src/core/features/course/pages/module-preview/module-preview.html +++ b/src/core/features/course/pages/module-preview/module-preview.html @@ -27,33 +27,35 @@ -
- - - +
+ + +
-
- - {{ 'core.course.hiddenfromstudents' | translate }} - +
+ + + {{ 'core.course.hiddenfromstudents' | translate }} +
-
- - {{ 'core.course.hiddenoncoursepage' | translate }} - +
+ + + {{ 'core.course.hiddenoncoursepage' | translate }} +
-
- {{ 'core.restricted' | translate }} -
+
+ + -
+
-
- - {{ 'core.course.manualcompletionnotsynced' | translate }} - +
+ + {{ 'core.course.manualcompletionnotsynced' | translate }} +
diff --git a/src/core/features/siteplugins/components/course-format/course-format.ts b/src/core/features/siteplugins/components/course-format/course-format.ts index 025c1036e..9fd9e6459 100644 --- a/src/core/features/siteplugins/components/course-format/course-format.ts +++ b/src/core/features/siteplugins/components/course-format/course-format.ts @@ -16,7 +16,7 @@ import { Component, OnChanges, Input, ViewChild, Output, EventEmitter } from '@a import { IonRefresher } from '@ionic/angular'; import { CoreCourseFormatComponent } from '@features/course/components/format/format'; -import { CoreCourseModuleCompletionData, CoreCourseSectionWithStatus } from '@features/course/services/course-helper'; +import { CoreCourseModuleCompletionData, CoreCourseSection } from '@features/course/services/course-helper'; import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate'; import { CoreCourseAnyCourseData } from '@features/courses/services/courses'; import { CoreSitePlugins, CoreSitePluginsContent } from '@features/siteplugins/services/siteplugins'; @@ -33,7 +33,7 @@ import { CoreSitePluginsPluginContentComponent } from '../plugin-content/plugin- export class CoreSitePluginsCourseFormatComponent implements OnChanges { @Input() course?: CoreCourseAnyCourseData; // The course to render. - @Input() sections?: CoreCourseSectionWithStatus[]; // List of course sections. The status will be calculated in this component. + @Input() sections?: CoreCourseSection[]; // List of course sections. The status will be calculated in this component. @Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled. @Input() initialSectionId?: number; // The section to load first (by ID). @Input() initialSectionNumber?: number; // The section to load first (by number). diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index cd61d7f89..74a6f739d 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -844,6 +844,8 @@ ion-select-popover ion-item.core-select-option-title { ion-chip { line-height: 1.1; + border-radius: var(--big-radius); + @include padding-horizontal(16px); } ion-searchbar { @@ -1167,9 +1169,8 @@ ion-item.item-input ion-input.has-focus { } } -// Ionic set this value to 0 without px that provoked miscalculations. ion-item-divider { - --inner-padding-end: 0px; + --inner-padding-end: 8px; } // Change default outline.