MOBILE-3915 course: Update course progress when completion changes
parent
5e29e65325
commit
7971e71e57
|
@ -19,8 +19,6 @@ import {
|
|||
OnChanges,
|
||||
OnDestroy,
|
||||
SimpleChange,
|
||||
Output,
|
||||
EventEmitter,
|
||||
ViewChildren,
|
||||
QueryList,
|
||||
Type,
|
||||
|
@ -31,12 +29,9 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
|
|||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import {
|
||||
CoreCourse,
|
||||
CoreCourseModuleCompletionStatus,
|
||||
CoreCourseProvider,
|
||||
} from '@features/course/services/course';
|
||||
import {
|
||||
CoreCourseModuleData,
|
||||
CoreCourseModuleCompletionData,
|
||||
CoreCourseSection,
|
||||
} from '@features/course/services/course-helper';
|
||||
import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate';
|
||||
|
@ -56,7 +51,7 @@ import { CoreCourseModuleDelegate } from '@features/course/services/module-deleg
|
|||
*
|
||||
* Example usage:
|
||||
*
|
||||
* <core-course-format [course]="course" [sections]="sections" (completionChanged)="onCompletionChange()"></core-course-format>
|
||||
* <core-course-format [course]="course" [sections]="sections"></core-course-format>
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-course-format',
|
||||
|
@ -72,7 +67,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
@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.
|
||||
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when any module completion changes.
|
||||
|
||||
@ViewChildren(CoreDynamicComponent) dynamicComponents?: QueryList<CoreDynamicComponent>;
|
||||
|
||||
|
@ -95,11 +89,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
allSectionsId: number = CoreCourseProvider.ALL_SECTIONS_ID;
|
||||
stealthModulesSectionId: number = CoreCourseProvider.STEALTH_MODULES_SECTION_ID;
|
||||
loaded = false;
|
||||
progress?: number;
|
||||
highlighted?: string;
|
||||
|
||||
protected selectTabObserver?: CoreEventObserver;
|
||||
protected completionObserver?: CoreEventObserver;
|
||||
protected lastCourseFormat?: string;
|
||||
|
||||
constructor(
|
||||
|
@ -141,36 +133,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
// The completion of any of the modules have changed.
|
||||
this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_CHANGED, (data) => {
|
||||
if (data.completion.courseId != this.course.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit a new event for other components.
|
||||
this.completionChanged.emit(data.completion);
|
||||
|
||||
if (data.completion.valueused !== false || !this.course || !('progress' in this.course) ||
|
||||
typeof this.course.progress != 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the completion value is not used, the page won't be reloaded, so update the progress bar.
|
||||
const completionModules = (<CoreCourseModuleData[]> [])
|
||||
.concat(...this.sections.map((section) => section.modules))
|
||||
.map((module) => module.completion && module.completion > 0 ? 1 : module.completion)
|
||||
.reduce((accumulator, currentValue) => (accumulator || 0) + (currentValue || 0), 0);
|
||||
|
||||
const moduleProgressPercent = 100 / (completionModules || 1);
|
||||
// Use min/max here to avoid floating point rounding errors over/under-flowing the progress bar.
|
||||
if (data.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
|
||||
this.course.progress = Math.min(100, this.course.progress + moduleProgressPercent);
|
||||
} else {
|
||||
this.course.progress = Math.max(0, this.course.progress - moduleProgressPercent);
|
||||
}
|
||||
|
||||
this.updateProgress();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,8 +149,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.displayBlocks = CoreCourseFormatDelegate.displayBlocks(this.course);
|
||||
|
||||
this.hasBlocks = await CoreBlockHelper.hasCourseBlocks(this.course.id);
|
||||
|
||||
this.updateProgress();
|
||||
}
|
||||
|
||||
if (changes.sections && this.sections) {
|
||||
|
@ -205,7 +165,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.data.initialSectionId = this.initialSectionId;
|
||||
this.data.initialSectionNumber = this.initialSectionNumber;
|
||||
this.data.moduleId = this.moduleId;
|
||||
this.data.completionChanged = this.completionChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -542,25 +501,6 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
|
|||
section.id != CoreCourseProvider.STEALTH_MODULES_SECTION_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update course progress.
|
||||
*/
|
||||
protected updateProgress(): void {
|
||||
if (
|
||||
!this.course ||
|
||||
!('progress' in this.course) ||
|
||||
typeof this.course.progress !== 'number' ||
|
||||
this.course.progress < 0 ||
|
||||
this.course.completionusertracked === false
|
||||
) {
|
||||
this.progress = undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.progress = this.course.progress;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type CoreCourseSectionToDisplay = CoreCourseSection & {
|
||||
|
|
|
@ -20,7 +20,7 @@ import { CoreCourseFormatDelegate } from '../../services/format-delegate';
|
|||
import { CoreCourseOptionsDelegate } from '../../services/course-options-delegate';
|
||||
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourse, CoreCourseModuleCompletionStatus, CoreCourseWSSection } from '@features/course/services/course';
|
||||
import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
|
@ -52,6 +52,8 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
|||
|
||||
protected currentPagePath = '';
|
||||
protected selectTabObserver: CoreEventObserver;
|
||||
protected completionObserver: CoreEventObserver;
|
||||
protected sections: CoreCourseWSSection[] = []; // List of course sections.
|
||||
protected firstTabName?: string;
|
||||
protected module?: CoreCourseModuleData;
|
||||
protected modParams?: Params;
|
||||
|
@ -83,6 +85,34 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
// The completion of any of the modules have changed.
|
||||
this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_CHANGED, (data) => {
|
||||
if (data.completion.courseId != this.course?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.completion.valueused !== false || !this.course || !('progress' in this.course) ||
|
||||
typeof this.course.progress != 'number') {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the completion value is not used, the page won't be reloaded, so update the progress bar.
|
||||
const completionModules = (<CoreCourseModuleData[]> [])
|
||||
.concat(...this.sections.map((section) => section.modules))
|
||||
.map((module) => module.completion && module.completion > 0 ? 1 : module.completion)
|
||||
.reduce((accumulator, currentValue) => (accumulator || 0) + (currentValue || 0), 0);
|
||||
|
||||
const moduleProgressPercent = 100 / (completionModules || 1);
|
||||
// Use min/max here to avoid floating point rounding errors over/under-flowing the progress bar.
|
||||
if (data.completion.state === CoreCourseModuleCompletionStatus.COMPLETION_COMPLETE) {
|
||||
this.course.progress = Math.min(100, this.course.progress + moduleProgressPercent);
|
||||
} else {
|
||||
this.course.progress = Math.max(0, this.course.progress - moduleProgressPercent);
|
||||
}
|
||||
|
||||
this.updateProgress();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -206,14 +236,14 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
|||
this.updateProgress();
|
||||
|
||||
// Load sections.
|
||||
const sections = await CoreUtils.ignoreErrors(CoreCourse.getSections(this.course.id, false, true));
|
||||
this.sections = await CoreUtils.ignoreErrors(CoreCourse.getSections(this.course.id, false, true), []);
|
||||
|
||||
if (!sections) {
|
||||
if (!this.sections) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the title again now that we have sections.
|
||||
this.title = CoreCourseFormatDelegate.getCourseTitle(this.course, sections);
|
||||
this.title = CoreCourseFormatDelegate.getCourseTitle(this.course, this.sections);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -224,6 +254,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
|
|||
|
||||
CoreNavigator.decreaseRouteDepth(path.replace(/(\/deep)+/, ''));
|
||||
this.selectTabObserver?.off();
|
||||
this.completionObserver?.off();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue