MOBILE-2335 book: Implement prefetch handler

main
Dani Palou 2018-02-01 10:14:47 +01:00
parent f8d71dd6ee
commit 7379ca3e71
8 changed files with 134 additions and 21 deletions

View File

@ -16,8 +16,10 @@ import { NgModule } from '@angular/core';
import { AddonModBookProvider } from './providers/book'; import { AddonModBookProvider } from './providers/book';
import { AddonModBookModuleHandler } from './providers/module-handler'; import { AddonModBookModuleHandler } from './providers/module-handler';
import { AddonModBookLinkHandler } from './providers/link-handler'; import { AddonModBookLinkHandler } from './providers/link-handler';
import { AddonModBookPrefetchHandler } from './providers/prefetch-handler';
import { CoreCourseModuleDelegate } from '../../../core/course/providers/module-delegate'; import { CoreCourseModuleDelegate } from '../../../core/course/providers/module-delegate';
import { CoreContentLinksDelegate } from '../../../core/contentlinks/providers/delegate'; import { CoreContentLinksDelegate } from '../../../core/contentlinks/providers/delegate';
import { CoreCourseModulePrefetchDelegate } from '../../../core/course/providers/module-prefetch-delegate';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -27,13 +29,16 @@ import { CoreContentLinksDelegate } from '../../../core/contentlinks/providers/d
providers: [ providers: [
AddonModBookProvider, AddonModBookProvider,
AddonModBookModuleHandler, AddonModBookModuleHandler,
AddonModBookLinkHandler AddonModBookLinkHandler,
AddonModBookPrefetchHandler
] ]
}) })
export class AddonModBookModule { export class AddonModBookModule {
constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModBookModuleHandler, constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModBookModuleHandler,
contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModBookLinkHandler) { contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModBookLinkHandler,
prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModBookPrefetchHandler) {
moduleDelegate.registerHandler(moduleHandler); moduleDelegate.registerHandler(moduleHandler);
contentLinksDelegate.registerHandler(linkHandler); contentLinksDelegate.registerHandler(linkHandler);
prefetchDelegate.registerHandler(prefetchHandler);
} }
} }

View File

@ -0,0 +1,103 @@
// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable, Injector } from '@angular/core';
import { CoreCourseModulePrefetchHandlerBase } from '../../../../core/course/classes/module-prefetch-handler';
import { AddonModBookProvider } from './book';
/**
* Handler to prefetch books.
*/
@Injectable()
export class AddonModBookPrefetchHandler extends CoreCourseModulePrefetchHandlerBase {
name = 'book';
component = AddonModBookProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^entries$/;
isResource = true;
constructor(injector: Injector, protected bookProvider: AddonModBookProvider) {
super(injector);
}
/**
* Download or prefetch the content.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @param {boolean} [prefetch] True to prefetch, false to download right away.
* @param {string} [dirPath] Path of the directory where to store all the content files. This is to keep the files
* relative paths and make the package work in an iframe. Undefined to download the files
* in the filepool root folder.
* @return {Promise<any>} Promise resolved when all content is downloaded. Data returned is not reliable.
*/
downloadOrPrefetch(module: any, courseId: number, prefetch?: boolean, dirPath?: string): Promise<any> {
const promises = [];
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
promises.push(this.bookProvider.getBook(courseId, module.id));
return Promise.all(promises);
}
/**
* Returns module intro files.
*
* @param {any} module The module object returned by WS.
* @param {number} courseId Course ID.
* @return {Promise<any[]>} Promise resolved with list of intro files.
*/
getIntroFiles(module: any, courseId: number): Promise<any[]> {
return this.bookProvider.getBook(courseId, module.id).catch(() => {
// Not found, return undefined so module description is used.
}).then((book) => {
return this.getIntroFilesFromInstance(module, book);
});
}
/**
* Invalidate the prefetched content.
*
* @param {number} moduleId The module ID.
* @param {number} courseId Course ID the module belongs to.
* @return {Promise<any>} Promise resolved when the data is invalidated.
*/
invalidateContent(moduleId: number, courseId: number): Promise<any> {
return this.bookProvider.invalidateContent(moduleId, courseId);
}
/**
* Invalidate WS calls needed to determine module status.
*
* @param {any} module Module.
* @param {number} courseId Course ID the module belongs to.
* @return {Promise<any>} Promise resolved when invalidated.
*/
invalidateModule(module: any, courseId: number): Promise<any> {
const promises = [];
promises.push(this.bookProvider.invalidateBookData(courseId));
promises.push(this.courseProvider.invalidateModule(module.id));
return Promise.all(promises);
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return {boolean|Promise<boolean>} A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
*/
isEnabled(): boolean | Promise<boolean> {
return this.bookProvider.isPluginEnabled();
}
}

View File

@ -143,9 +143,9 @@ export class CoreDelegate {
* *
* @param {string} handlerName The handler name. * @param {string} handlerName The handler name.
* @param {boolean} [enabled] Only enabled, or any. * @param {boolean} [enabled] Only enabled, or any.
* @return {any} Handler. * @return {CoreDelegateHandler} Handler.
*/ */
protected getHandler(handlerName: string, enabled: boolean = false): any { protected getHandler(handlerName: string, enabled: boolean = false): CoreDelegateHandler {
return enabled ? this.enabledHandlers[handlerName] : this.handlers[handlerName]; return enabled ? this.enabledHandlers[handlerName] : this.handlers[handlerName];
} }

View File

@ -53,17 +53,11 @@ export type prefetchFunction = (module: any, courseId: number, single: boolean,
* recommended to call the prefetchPackage function since it'll handle changing the status of the module. * recommended to call the prefetchPackage function since it'll handle changing the status of the module.
*/ */
export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePrefetchHandler { export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePrefetchHandler {
/**
* A name to identify the addon.
* @type {string}
*/
name = 'CoreCourseModulePrefetchHandlerBase';
/** /**
* Name of the module. It should match the "modname" of the module returned in core_course_get_contents. * Name of the module. It should match the "modname" of the module returned in core_course_get_contents.
* @type {string} * @type {string}
*/ */
modname = ''; name = '';
/** /**
* The handler's component. * The handler's component.
@ -235,7 +229,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* @param {number} courseId Course ID the module belongs to. * @param {number} courseId Course ID the module belongs to.
* @return {number|Promise<number>} Size, or promise resolved with the size. * @return {number|Promise<number>} Size, or promise resolved with the size.
*/ */
getDownloadedSize?(module: any, courseId: number): number | Promise<number> { getDownloadedSize(module: any, courseId: number): number | Promise<number> {
const siteId = this.sitesProvider.getCurrentSiteId(); const siteId = this.sitesProvider.getCurrentSiteId();
return this.filepoolProvider.getFilesSizeByComponent(siteId, this.component, module.id); return this.filepoolProvider.getFilesSizeByComponent(siteId, this.component, module.id);
@ -324,9 +318,10 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref
* Invalidate the prefetched content. * Invalidate the prefetched content.
* *
* @param {number} moduleId The module ID. * @param {number} moduleId The module ID.
* @param {number} courseId The course ID the module belongs to.
* @return {Promise<any>} Promise resolved when the data is invalidated. * @return {Promise<any>} Promise resolved when the data is invalidated.
*/ */
invalidateContent(moduleId: number): Promise<any> { invalidateContent(moduleId: number, courseId: number): Promise<any> {
const promises = [], const promises = [],
siteId = this.sitesProvider.getCurrentSiteId(); siteId = this.sitesProvider.getCurrentSiteId();

View File

@ -151,6 +151,18 @@ export class CoreCourseSectionPage implements OnDestroy {
promises.push(promise.then((completionStatus) => { promises.push(promise.then((completionStatus) => {
// Get all the sections. // Get all the sections.
promises.push(this.courseProvider.getSections(this.course.id, false, true).then((sections) => { promises.push(this.courseProvider.getSections(this.course.id, false, true).then((sections) => {
if (refresh) {
// Invalidate the recently downloaded module list. To ensure info can be prefetched.
const modules = this.courseProvider.getSectionsModules(sections);
return this.prefetchDelegate.invalidateModules(modules, this.course.id).then(() => {
return sections;
});
} else {
return sections;
}
}).then((sections) => {
this.courseHelper.addHandlerDataForModules(sections, this.course.id, completionStatus); this.courseHelper.addHandlerDataForModules(sections, this.course.id, completionStatus);
// Format the name of each section and check if it has content. // Format the name of each section and check if it has content.

View File

@ -202,9 +202,6 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
}; };
protected ROOT_CACHE_KEY = 'mmCourse:'; protected ROOT_CACHE_KEY = 'mmCourse:';
protected handlers: { [s: string]: CoreCourseModulePrefetchHandler } = {}; // All registered handlers.
protected enabledHandlers: { [s: string]: CoreCourseModulePrefetchHandler } = {}; // Handlers enabled for the current site.
protected statusCache = new CoreCache(); protected statusCache = new CoreCache();
// Promises for check updates, to prevent performing the same request twice at the same time. // Promises for check updates, to prevent performing the same request twice at the same time.
@ -225,7 +222,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
private courseProvider: CoreCourseProvider, private filepoolProvider: CoreFilepoolProvider, private courseProvider: CoreCourseProvider, private filepoolProvider: CoreFilepoolProvider,
private timeUtils: CoreTimeUtilsProvider, private fileProvider: CoreFileProvider, private timeUtils: CoreTimeUtilsProvider, private fileProvider: CoreFileProvider,
protected eventsProvider: CoreEventsProvider) { protected eventsProvider: CoreEventsProvider) {
super('CoreCourseModulePrefetchDelegate', loggerProvider, sitesProvider); super('CoreCourseModulePrefetchDelegate', loggerProvider, sitesProvider, eventsProvider);
this.sitesProvider.createTableFromSchema(this.checkUpdatesTableSchema); this.sitesProvider.createTableFromSchema(this.checkUpdatesTableSchema);
} }
@ -859,7 +856,7 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
* @return {CoreCourseModulePrefetchHandler} Prefetch handler. * @return {CoreCourseModulePrefetchHandler} Prefetch handler.
*/ */
getPrefetchHandlerFor(module: any): CoreCourseModulePrefetchHandler { getPrefetchHandlerFor(module: any): CoreCourseModulePrefetchHandler {
return this.enabledHandlers[module.modname]; return <CoreCourseModulePrefetchHandler> this.getHandler(module.modname, true);
} }
/** /**

View File

@ -99,7 +99,8 @@ export class CoreUserProfileFieldDelegate extends CoreDelegate {
*/ */
getDataForField(field: any, signup: boolean, registerAuth: string, formValues: any): Promise<any> { getDataForField(field: any, signup: boolean, registerAuth: string, formValues: any): Promise<any> {
const type = field.type || field.datatype, const type = field.type || field.datatype,
handler = this.getHandler(type, !signup); handler = <CoreUserProfileFieldHandler> this.getHandler(type, !signup);
if (handler) { if (handler) {
const name = 'profile_field_' + field.shortname; const name = 'profile_field_' + field.shortname;
if (handler.getData) { if (handler.getData) {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Directive, Input, OnInit, ElementRef } from '@angular/core'; import { Directive, Input, OnInit, ElementRef, Optional } from '@angular/core';
import { NavController, Content } from 'ionic-angular'; import { NavController, Content } from 'ionic-angular';
import { CoreSitesProvider } from '../providers/sites'; import { CoreSitesProvider } from '../providers/sites';
import { CoreDomUtilsProvider } from '../providers/utils/dom'; import { CoreDomUtilsProvider } from '../providers/utils/dom';
@ -40,7 +40,7 @@ export class CoreLinkDirective implements OnInit {
constructor(element: ElementRef, private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider, constructor(element: ElementRef, private domUtils: CoreDomUtilsProvider, private utils: CoreUtilsProvider,
private sitesProvider: CoreSitesProvider, private urlUtils: CoreUrlUtilsProvider, private sitesProvider: CoreSitesProvider, private urlUtils: CoreUrlUtilsProvider,
private contentLinksHelper: CoreContentLinksHelperProvider, private navCtrl: NavController, private contentLinksHelper: CoreContentLinksHelperProvider, private navCtrl: NavController,
private content: Content) { @Optional() private content: Content) {
// This directive can be added dynamically. In that case, the first param is the anchor HTMLElement. // This directive can be added dynamically. In that case, the first param is the anchor HTMLElement.
this.element = element.nativeElement || element; this.element = element.nativeElement || element;
} }