MOBILE-3401 courses: Refresh only right data on MY_COURSES_UPDATED

main
Dani Palou 2020-05-25 10:22:09 +02:00
parent 536589c591
commit f284ab7c73
8 changed files with 190 additions and 25 deletions

View File

@ -17,7 +17,7 @@ import { Searchbar } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData } from '@core/courses/providers/courses';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
@ -112,8 +112,12 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
}, this.sitesProvider.getCurrentSiteId());
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.refreshContent();
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
(data: CoreCoursesMyCoursesUpdatedEventData) => {
if (data.action == CoreCoursesProvider.ACTION_ENROL || data.action == CoreCoursesProvider.ACTION_STATE_CHANGED) {
this.refreshCourseList();
}
}, this.sitesProvider.getCurrentSiteId());
this.currentSite = this.sitesProvider.getCurrentSite();
@ -151,12 +155,9 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
promises.push(this.coursesProvider.invalidateUserCourses().finally(() => {
// Invalidate course completion data.
promises.push(this.coursesProvider.invalidateUserCourses().finally(() => {
// Invalidate course completion data.
return this.utils.allPromises(this.courseIds.map((courseId) => {
return this.courseCompletionProvider.invalidateCourseCompletion(courseId);
}));
}));
return this.utils.allPromises(this.courseIds.map((courseId) => {
return this.courseCompletionProvider.invalidateCourseCompletion(courseId);
}));
}));
promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions());
@ -318,6 +319,23 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
});
}
/**
* Refresh the list of courses.
*
* @return Promise resolved when done.
*/
protected async refreshCourseList(): Promise<void> {
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
try {
await this.coursesProvider.invalidateUserCourses();
} catch (error) {
// Ignore errors.
}
await this.loadContent(true);
}
/**
* The selected courses filter have changed.
*/

View File

@ -15,7 +15,7 @@
import { Component, OnInit, OnDestroy, Injector, Input, OnChanges, SimpleChange } from '@angular/core';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData } from '@core/courses/providers/courses';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
@ -72,8 +72,12 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
}, this.sitesProvider.getCurrentSiteId());
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.refreshContent();
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
(data: CoreCoursesMyCoursesUpdatedEventData) => {
if (this.shouldRefreshOnUpdatedEvent(data)) {
this.refreshCourseList();
}
}, this.sitesProvider.getCurrentSiteId());
super.ngOnInit();
@ -130,6 +134,23 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
});
}
/**
* Refresh the list of courses.
*
* @return Promise resolved when done.
*/
protected async refreshCourseList(): Promise<void> {
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
try {
await this.coursesProvider.invalidateUserCourses();
} catch (error) {
// Ignore errors.
}
await this.loadContent(true);
}
/**
* Initialize the prefetch icon for selected courses.
*/
@ -146,6 +167,49 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
});
}
/**
* Whether list should be refreshed based on a EVENT_MY_COURSES_UPDATED event.
*
* @param data Event data.
* @return Whether to refresh.
*/
protected shouldRefreshOnUpdatedEvent(data: CoreCoursesMyCoursesUpdatedEventData): boolean {
if (data.action == CoreCoursesProvider.ACTION_ENROL) {
// Always update if user enrolled in a course.
return true;
}
if (data.action == CoreCoursesProvider.ACTION_VIEW && data.courseId != this.sitesProvider.getCurrentSiteHomeId() &&
this.courses[0] && data.courseId != this.courses[0].id) {
// Update list if user viewed a course that isn't the most recent one and isn't site home.
return true;
}
if (data.action == CoreCoursesProvider.ACTION_STATE_CHANGED && data.state == CoreCoursesProvider.STATE_FAVOURITE &&
this.hasCourse(data.courseId)) {
// Update list if a visible course is now favourite or unfavourite.
return true;
}
return false;
}
/**
* Check if a certain course is in the list of courses.
*
* @param courseId Course ID to search.
* @return Whether it's in the list.
*/
protected hasCourse(courseId: number): boolean {
if (!this.courses) {
return false;
}
return !!this.courses.find((course) => {
return course.id == courseId;
});
}
/**
* Prefetch all the shown courses.
*

View File

@ -15,7 +15,7 @@
import { Component, OnInit, OnDestroy, Injector, Input, OnChanges, SimpleChange } from '@angular/core';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData } from '@core/courses/providers/courses';
import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
@ -72,7 +72,12 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
}, this.sitesProvider.getCurrentSiteId());
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
(data: CoreCoursesMyCoursesUpdatedEventData) => {
if (this.shouldRefreshOnUpdatedEvent(data)) {
this.refreshCourseList();
}
this.refreshContent();
}, this.sitesProvider.getCurrentSiteId());
@ -130,6 +135,44 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
});
}
/**
* Refresh the list of courses.
*
* @return Promise resolved when done.
*/
protected async refreshCourseList(): Promise<void> {
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_REFRESHED);
try {
await this.coursesProvider.invalidateUserCourses();
} catch (error) {
// Ignore errors.
}
await this.loadContent(true);
}
/**
* Whether list should be refreshed based on a EVENT_MY_COURSES_UPDATED event.
*
* @param data Event data.
* @return Whether to refresh.
*/
protected shouldRefreshOnUpdatedEvent(data: CoreCoursesMyCoursesUpdatedEventData): boolean {
if (data.action == CoreCoursesProvider.ACTION_ENROL) {
// Always update if user enrolled in a course.
// New courses shouldn't be favourite by default, but just in case.
return true;
}
if (data.action == CoreCoursesProvider.ACTION_STATE_CHANGED && data.state == CoreCoursesProvider.STATE_FAVOURITE) {
// Update list when making a course favourite or not.
return true;
}
return false;
}
/**
* Initialize the prefetch icon for selected courses.
*/

View File

@ -862,8 +862,10 @@ export class CoreCourseProvider {
if (!response.status) {
return Promise.reject(null);
} else {
this.eventsProvider.trigger(
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {course: courseId}, site.getId());
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
courseId: courseId,
action: CoreCoursesProvider.ACTION_VIEW,
}, site.getId());
}
});
});

View File

@ -218,8 +218,13 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
// We should use null to unset the preference.
this.userProvider.updateUserPreference('block_myoverview_hidden_course_' + this.course.id, hide ? 1 : null).then(() => {
this.course.hidden = hide;
this.eventsProvider.trigger(
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {course: this.course}, this.sitesProvider.getCurrentSiteId());
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
courseId: this.course.id,
course: this.course,
action: CoreCoursesProvider.ACTION_STATE_CHANGED,
state: CoreCoursesProvider.STATE_HIDDEN,
value: hide,
}, this.sitesProvider.getCurrentSiteId());
}).catch((error) => {
if (!this.isDestroyed) {
this.domUtils.showErrorModalDefault(error, 'Error changing course visibility.');
@ -239,8 +244,13 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
this.coursesProvider.setFavouriteCourse(this.course.id, favourite).then(() => {
this.course.isfavourite = favourite;
this.eventsProvider.trigger(
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {course: this.course}, this.sitesProvider.getCurrentSiteId());
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
courseId: this.course.id,
course: this.course,
action: CoreCoursesProvider.ACTION_STATE_CHANGED,
state: CoreCoursesProvider.STATE_FAVOURITE,
value: favourite,
}, this.sitesProvider.getCurrentSiteId());
}).catch((error) => {
if (!this.isDestroyed) {
this.domUtils.showErrorModalDefault(error, 'Error changing course favourite attribute.');

View File

@ -17,7 +17,7 @@ import { Searchbar } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData } from '../../providers/courses';
import { CoreCoursesHelperProvider } from '../../providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
@ -63,8 +63,13 @@ export class CoreCoursesMyCoursesComponent implements OnInit, OnDestroy {
this.coursesLoaded = true;
});
this.myCoursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.fetchCourses();
// Update list if user enrols in a course.
this.myCoursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
(data: CoreCoursesMyCoursesUpdatedEventData) => {
if (data.action == CoreCoursesProvider.ACTION_ENROL) {
this.fetchCourses();
}
}, this.sitesProvider.getCurrentSiteId());
// Refresh the enabled flags if site is updated.

View File

@ -365,8 +365,11 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
this.waitForEnrolled(true).then(() => {
this.refreshData().finally(() => {
// My courses have been updated, trigger event.
this.eventsProvider.trigger(
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {course: this.course}, this.sitesProvider.getCurrentSiteId());
this.eventsProvider.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
courseId: this.course.id,
course: this.course,
action: CoreCoursesProvider.ACTION_ENROL,
}, this.sitesProvider.getCurrentSiteId());
});
});
}).catch((error) => {

View File

@ -18,6 +18,17 @@ import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
import { CoreSite } from '@classes/site';
/**
* Data sent to the EVENT_MY_COURSES_UPDATED.
*/
export type CoreCoursesMyCoursesUpdatedEventData = {
action: string; // Action performed.
courseId?: number; // Course ID affected (if any).
course?: any; // Course affected (if any).
state?: string; // Only for ACTION_STATE_CHANGED. The state that changed (hidden, favourite).
value?: boolean; // The new value for the state changed.
};
/**
* Service that provides some features regarding lists of courses and categories.
*/
@ -30,6 +41,15 @@ export class CoreCoursesProvider {
static EVENT_MY_COURSES_REFRESHED = 'courses_my_courses_refreshed';
static EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED = 'dashboard_download_enabled_changed';
// Actions for event EVENT_MY_COURSES_UPDATED.
static ACTION_ENROL = 'enrol'; // User enrolled in a course.
static ACTION_STATE_CHANGED = 'state_changed'; // Course state changed (hidden, favourite).
static ACTION_VIEW = 'view'; // Course viewed.
// Possible states changed.
static STATE_HIDDEN = 'hidden';
static STATE_FAVOURITE = 'favourite';
protected ROOT_CACHE_KEY = 'mmCourses:';
protected logger;
protected userCoursesIds: {[id: number]: boolean}; // Use an object to make it faster to search.