diff --git a/src/addon/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html b/src/addon/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html
index bc54e8a4c..28725aa6b 100644
--- a/src/addon/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html
+++ b/src/addon/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html
@@ -5,6 +5,8 @@
+
+
diff --git a/src/addon/mod/h5pactivity/components/index/index.ts b/src/addon/mod/h5pactivity/components/index/index.ts
index 6d28a5fda..83d6469d5 100644
--- a/src/addon/mod/h5pactivity/components/index/index.ts
+++ b/src/addon/mod/h5pactivity/components/index/index.ts
@@ -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);
}
/**
diff --git a/src/addon/mod/h5pactivity/h5pactivity.module.ts b/src/addon/mod/h5pactivity/h5pactivity.module.ts
index ed0fb852e..771ac2ad6 100644
--- a/src/addon/mod/h5pactivity/h5pactivity.module.ts
+++ b/src/addon/mod/h5pactivity/h5pactivity.module.ts
@@ -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);
}
}
diff --git a/src/addon/mod/h5pactivity/providers/h5pactivity.ts b/src/addon/mod/h5pactivity/providers/h5pactivity.ts
index 60a6f8abf..70d42524b 100644
--- a/src/addon/mod/h5pactivity/providers/h5pactivity.ts
+++ b/src/addon/mod/h5pactivity/providers/h5pactivity.ts
@@ -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 {
+
+ 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 {
+ logView(id: number, name?: string, siteId?: string): Promise {
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.
};
diff --git a/src/addon/mod/h5pactivity/providers/module-handler.ts b/src/addon/mod/h5pactivity/providers/module-handler.ts
index e6ad04b83..6f544a16c 100644
--- a/src/addon/mod/h5pactivity/providers/module-handler.ts
+++ b/src/addon/mod/h5pactivity/providers/module-handler.ts
@@ -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) {
diff --git a/src/addon/mod/h5pactivity/providers/prefetch-handler.ts b/src/addon/mod/h5pactivity/providers/prefetch-handler.ts
new file mode 100644
index 000000000..ccb03a168
--- /dev/null
+++ b/src/addon/mod/h5pactivity/providers/prefetch-handler.ts
@@ -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 {
+
+ 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 {
+ // 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 {
+ 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 {
+ 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 {
+ 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 {
+
+ 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 {
+
+ 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);
+ }
+}