MOBILE-3411 h5pactivity: Implement prefetch
This commit is contained in:
		
							parent
							
								
									a8e336fd41
								
							
						
					
					
						commit
						e6818524c5
					
				| @ -5,6 +5,8 @@ | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item> | ||||
|     </core-context-menu> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
|  | ||||
| @ -142,18 +142,10 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (this.h5pActivity.deployedfile) { | ||||
|             // File already deployed and still valid, use this one.
 | ||||
|             this.deployedFile = this.h5pActivity.deployedfile; | ||||
|         } else { | ||||
|             if (!this.h5pActivity.package || !this.h5pActivity.package[0]) { | ||||
|                 // Shouldn't happen.
 | ||||
|                 throw 'No H5P package found.'; | ||||
|             } | ||||
| 
 | ||||
|             // Deploy the file in the server.
 | ||||
|             this.deployedFile = await CoreH5P.instance.getTrustedH5PFile(this.h5pActivity.package[0].fileurl, this.displayOptions); | ||||
|         } | ||||
|         this.deployedFile = await AddonModH5PActivity.instance.getDeployedFile(this.h5pActivity, { | ||||
|             displayOptions: this.displayOptions, | ||||
|             siteId: this.siteId, | ||||
|         }); | ||||
| 
 | ||||
|         this.fileUrl = this.deployedFile.fileurl; | ||||
| 
 | ||||
| @ -300,6 +292,9 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv | ||||
|      */ | ||||
|     play(): void { | ||||
|         this.playing = true; | ||||
| 
 | ||||
|         // Mark the activity as viewed.
 | ||||
|         AddonModH5PActivity.instance.logView(this.h5pActivity.id, this.h5pActivity.name, this.siteId); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -16,10 +16,12 @@ import { NgModule } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate'; | ||||
| import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate'; | ||||
| 
 | ||||
| import { AddonModH5PActivityComponentsModule } from './components/components.module'; | ||||
| import { AddonModH5PActivityModuleHandler } from './providers/module-handler'; | ||||
| import { AddonModH5PActivityProvider } from './providers/h5pactivity'; | ||||
| import { AddonModH5PActivityPrefetchHandler } from './providers/prefetch-handler'; | ||||
| import { AddonModH5PActivityIndexLinkHandler } from './providers/index-link-handler'; | ||||
| 
 | ||||
| // List of providers (without handlers).
 | ||||
| @ -36,16 +38,20 @@ export const ADDON_MOD_H5P_ACTIVITY_PROVIDERS: any[] = [ | ||||
|     providers: [ | ||||
|         AddonModH5PActivityProvider, | ||||
|         AddonModH5PActivityModuleHandler, | ||||
|         AddonModH5PActivityPrefetchHandler, | ||||
|         AddonModH5PActivityIndexLinkHandler, | ||||
|     ] | ||||
| }) | ||||
| export class AddonModH5PActivityModule { | ||||
|     constructor(moduleDelegate: CoreCourseModuleDelegate, | ||||
|             moduleHandler: AddonModH5PActivityModuleHandler, | ||||
|             prefetchDelegate: CoreCourseModulePrefetchDelegate, | ||||
|             prefetchHandler: AddonModH5PActivityPrefetchHandler, | ||||
|             linksDelegate: CoreContentLinksDelegate, | ||||
|             indexHandler: AddonModH5PActivityIndexLinkHandler) { | ||||
| 
 | ||||
|         moduleDelegate.registerHandler(moduleHandler); | ||||
|         prefetchDelegate.registerHandler(prefetchHandler); | ||||
|         linksDelegate.registerHandler(indexHandler); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -18,6 +18,8 @@ import { CoreSites } from '@providers/sites'; | ||||
| import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws'; | ||||
| import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; | ||||
| import { CoreCourseLogHelper } from '@core/course/providers/log-helper'; | ||||
| import { CoreH5P } from '@core/h5p/providers/h5p'; | ||||
| import { CoreH5PDisplayOptions } from '@core/h5p/classes/core'; | ||||
| 
 | ||||
| import { makeSingleton, Translate } from '@singletons/core.singletons'; | ||||
| 
 | ||||
| @ -63,6 +65,33 @@ export class AddonModH5PActivityProvider { | ||||
|         return site.read('mod_h5pactivity_get_h5pactivity_access_information', params, preSets); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get deployed file from an H5P activity instance. | ||||
|      * | ||||
|      * @param h5pActivity Activity instance. | ||||
|      * @param options Options | ||||
|      * @return Promise resolved with the file. | ||||
|      */ | ||||
|     async getDeployedFile(h5pActivity: AddonModH5PActivityData, options?: AddonModH5PActivityGetDeployedFileOptions) | ||||
|             : Promise<CoreWSExternalFile> { | ||||
| 
 | ||||
|         if (h5pActivity.deployedfile) { | ||||
|             // File already deployed and still valid, use this one.
 | ||||
|             return h5pActivity.deployedfile; | ||||
|         } else { | ||||
|             if (!h5pActivity.package || !h5pActivity.package[0]) { | ||||
|                 // Shouldn't happen.
 | ||||
|                 throw 'No H5P package found.'; | ||||
|             } | ||||
| 
 | ||||
|             options = options || {}; | ||||
| 
 | ||||
|             // Deploy the file in the server.
 | ||||
|             return CoreH5P.instance.getTrustedH5PFile(h5pActivity.package[0].fileurl, options.displayOptions, | ||||
|                     options.ignoreCache, options.siteId); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get cache key for H5P activity data WS calls. | ||||
|      * | ||||
| @ -189,12 +218,12 @@ export class AddonModH5PActivityProvider { | ||||
|      * @param siteId Site ID. If not defined, current site. | ||||
|      * @return Promise resolved when the WS call is successful. | ||||
|      */ | ||||
|     async logView(id: number, name?: string, siteId?: string): Promise<void> { | ||||
|     logView(id: number, name?: string, siteId?: string): Promise<void> { | ||||
|         const params = { | ||||
|             h5pactivityid: id, | ||||
|         }; | ||||
| 
 | ||||
|         const result: AddonModH5PActivityViewResult = await CoreCourseLogHelper.instance.logSingle( | ||||
|         return CoreCourseLogHelper.instance.logSingle( | ||||
|             'mod_h5pactivity_view_h5pactivity', | ||||
|             params, | ||||
|             AddonModH5PActivityProvider.COMPONENT, | ||||
| @ -204,10 +233,6 @@ export class AddonModH5PActivityProvider { | ||||
|             {}, | ||||
|             siteId | ||||
|         ); | ||||
| 
 | ||||
|         if (!result.status) { | ||||
|             throw result.warnings[0] || 'Error marking H5P activity as viewed.'; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -262,9 +287,10 @@ export type AddonModH5PActivityAccessInfo = { | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Result of WS mod_h5pactivity_view_h5pactivity. | ||||
|  * Options to pass to getDeployedFile function. | ||||
|  */ | ||||
| export type AddonModH5PActivityViewResult = { | ||||
|     status: boolean; // Status: true if success.
 | ||||
|     warnings?: CoreWSExternalWarning[]; | ||||
| export type AddonModH5PActivityGetDeployedFileOptions = { | ||||
|     displayOptions?: CoreH5PDisplayOptions; // Display options
 | ||||
|     ignoreCache?: boolean; // Whether to ignore cache. Will fail if offline or server down.
 | ||||
|     siteId?: string; // Site ID. If not defined, current site.
 | ||||
| }; | ||||
|  | ||||
| @ -65,6 +65,7 @@ export class AddonModH5PActivityModuleHandler implements CoreCourseModuleHandler | ||||
|             icon: CoreCourse.instance.getModuleIconSrc(this.modName, module.modicon), | ||||
|             title: module.name, | ||||
|             class: 'addon-mod_h5pactivity-handler', | ||||
|             showDownloadButton: true, | ||||
|             action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions, params?: any): void { | ||||
|                 const pageParams = {module: module, courseId: courseId}; | ||||
|                 if (params) { | ||||
|  | ||||
							
								
								
									
										166
									
								
								src/addon/mod/h5pactivity/providers/prefetch-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								src/addon/mod/h5pactivity/providers/prefetch-handler.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // 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 { TranslateService } from '@ngx-translate/core'; | ||||
| import { CoreAppProvider } from '@providers/app'; | ||||
| import { CoreFilepoolProvider } from '@providers/filepool'; | ||||
| import { CorePluginFileDelegate } from '@providers/plugin-file-delegate'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreWSExternalFile } from '@providers/ws'; | ||||
| import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreCourseProvider } from '@core/course/providers/course'; | ||||
| import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; | ||||
| import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; | ||||
| import { CoreH5PHelper } from '@core/h5p/classes/helper'; | ||||
| import { CoreH5P } from '@core/h5p/providers/h5p'; | ||||
| import { CoreUserProvider } from '@core/user/providers/user'; | ||||
| import { AddonModH5PActivity, AddonModH5PActivityProvider, AddonModH5PActivityData } from './h5pactivity'; | ||||
| 
 | ||||
| /** | ||||
|  * Handler to prefetch h5p activity. | ||||
|  */ | ||||
| @Injectable() | ||||
| export class AddonModH5PActivityPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase { | ||||
|     name = 'AddonModH5PActivity'; | ||||
|     modName = 'h5pactivity'; | ||||
|     component = AddonModH5PActivityProvider.COMPONENT; | ||||
|     updatesNames = /^configuration$|^.*files$|^tracks$|^usertracks$/; | ||||
| 
 | ||||
|     constructor(translate: TranslateService, | ||||
|             appProvider: CoreAppProvider, | ||||
|             utils: CoreUtilsProvider, | ||||
|             courseProvider: CoreCourseProvider, | ||||
|             filepoolProvider: CoreFilepoolProvider, | ||||
|             sitesProvider: CoreSitesProvider, | ||||
|             domUtils: CoreDomUtilsProvider, | ||||
|             filterHelper: CoreFilterHelperProvider, | ||||
|             pluginFileDelegate: CorePluginFileDelegate, | ||||
|             protected userProvider: CoreUserProvider, | ||||
|             protected injector: Injector) { | ||||
| 
 | ||||
|         super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper, | ||||
|                 pluginFileDelegate); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get list of files. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @param single True if we're downloading a single module, false if we're downloading a whole section. | ||||
|      * @return Promise resolved with the list of files. | ||||
|      */ | ||||
|     async getFiles(module: any, courseId: number, single?: boolean): Promise<CoreWSExternalFile[]> { | ||||
| 
 | ||||
|         const h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(courseId, module.id); | ||||
| 
 | ||||
|         const displayOptions = CoreH5PHelper.decodeDisplayOptions(h5pActivity.displayoptions); | ||||
| 
 | ||||
|         const deployedFile = await AddonModH5PActivity.instance.getDeployedFile(h5pActivity, { | ||||
|             displayOptions: displayOptions, | ||||
|         }); | ||||
| 
 | ||||
|         return [deployedFile].concat(this.getIntroFilesFromInstance(module, h5pActivity)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Invalidate WS calls needed to determine module status (usually, to check if module is downloadable). | ||||
|      * It doesn't need to invalidate check updates. It should NOT invalidate files nor all the prefetched data. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @return Promise resolved when invalidated. | ||||
|      */ | ||||
|     async invalidateModule(module: any, courseId: number): Promise<void> { | ||||
|         // No need to invalidate anything.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if a module can be downloaded. If the function is not defined, we assume that all modules are downloadable. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @return Whether the module can be downloaded. The promise should never be rejected. | ||||
|      */ | ||||
|     isDownloadable(module: any, courseId: number): boolean | Promise<boolean> { | ||||
|         return this.sitesProvider.getCurrentSite().canDownloadFiles() && !CoreH5P.instance.isOfflineDisabledInSite(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Whether or not the handler is enabled on a site level. | ||||
|      * | ||||
|      * @return A boolean, or a promise resolved with a boolean, indicating if the handler is enabled. | ||||
|      */ | ||||
|     isEnabled(): boolean | Promise<boolean> { | ||||
|         return AddonModH5PActivity.instance.isPluginEnabled(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch a module. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @param single True if we're downloading a single module, false if we're downloading a whole section. | ||||
|      * @param dirPath Path of the directory where to store all the content files. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> { | ||||
|         return this.prefetchPackage(module, courseId, single, this.prefetchActivity.bind(this)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch an H5P activity. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param courseId Course ID the module belongs to. | ||||
|      * @param single True if we're downloading a single module, false if we're downloading a whole section. | ||||
|      * @param siteId Site ID. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async prefetchActivity(module: any, courseId: number, single: boolean, siteId: string): Promise<void> { | ||||
| 
 | ||||
|         const h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(courseId, module.id, true, siteId); | ||||
| 
 | ||||
|         const introFiles = this.getIntroFilesFromInstance(module, h5pActivity); | ||||
| 
 | ||||
|         await Promise.all([ | ||||
|             AddonModH5PActivity.instance.getAccessInformation(h5pActivity.id, true, siteId), | ||||
|             this.filepoolProvider.addFilesToQueue(siteId, introFiles, AddonModH5PActivityProvider.COMPONENT, module.id), | ||||
|             this.prefetchMainFile(module, h5pActivity, siteId), | ||||
|         ]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch the deployed file of the activity. | ||||
|      * | ||||
|      * @param module Module. | ||||
|      * @param h5pActivity Activity instance. | ||||
|      * @param siteId Site ID. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async prefetchMainFile(module: any, h5pActivity: AddonModH5PActivityData, siteId: string): Promise<void> { | ||||
| 
 | ||||
|         const displayOptions = CoreH5PHelper.decodeDisplayOptions(h5pActivity.displayoptions); | ||||
| 
 | ||||
|         const deployedFile = await AddonModH5PActivity.instance.getDeployedFile(h5pActivity, { | ||||
|             displayOptions: displayOptions, | ||||
|             ignoreCache: true, | ||||
|             siteId: siteId, | ||||
|         }); | ||||
| 
 | ||||
|         await this.filepoolProvider.addFilesToQueue(siteId, [deployedFile], AddonModH5PActivityProvider.COMPONENT, module.id); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user