MOBILE-3411 h5pactivity: Add button to download the file
parent
4bbd05bd55
commit
0196a738d7
|
@ -13,5 +13,21 @@
|
|||
|
||||
<core-course-module-description [description]="description" [component]="component" [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description>
|
||||
|
||||
<!-- TODO -->
|
||||
<ion-list *ngIf="deployedFile && !playing">
|
||||
<ion-item text-wrap *ngIf="stateMessage">
|
||||
<p >{{ stateMessage | translate }}</p>
|
||||
</ion-item>
|
||||
|
||||
<!-- Button to download the package. -->
|
||||
<ion-item *ngIf="!downloading && needsDownload" text-wrap>
|
||||
<a ion-button block (click)="downloadAndPlay($event)">{{ 'core.download' | translate }}</a>
|
||||
</ion-item>
|
||||
|
||||
<!-- Download progress. -->
|
||||
<ion-item text-center *ngIf="downloading">
|
||||
<ion-spinner></ion-spinner>
|
||||
<p *ngIf="progressMessage">{{ progressMessage | translate }}</p>
|
||||
<p *ngIf="percentage <= 100">{{ 'core.percentagenumber' | translate:{$a: percentage} }}</p>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
</core-loading>
|
||||
|
|
|
@ -14,8 +14,20 @@
|
|||
|
||||
import { Component, Optional, Injector } from '@angular/core';
|
||||
import { Content } from 'ionic-angular';
|
||||
|
||||
import { CoreApp } from '@providers/app';
|
||||
import { CoreFilepool } from '@providers/filepool';
|
||||
import { CoreWSExternalFile } from '@providers/ws';
|
||||
import { CoreDomUtils } from '@providers/utils/dom';
|
||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
|
||||
import { AddonModH5PActivity, AddonModH5PActivityProvider, AddonModH5PActivityData } from '../../providers/h5pactivity';
|
||||
import { CoreH5P } from '@core/h5p/providers/h5p';
|
||||
import { CoreH5PDisplayOptions } from '@core/h5p/classes/core';
|
||||
import { CoreH5PHelper } from '@core/h5p/classes/helper';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
|
||||
import {
|
||||
AddonModH5PActivity, AddonModH5PActivityProvider, AddonModH5PActivityData, AddonModH5PActivityAccessInfo
|
||||
} from '../../providers/h5pactivity';
|
||||
|
||||
/**
|
||||
* Component that displays an H5P activity entry page.
|
||||
|
@ -29,8 +41,18 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
|||
moduleName = 'h5pactivity';
|
||||
|
||||
h5pActivity: AddonModH5PActivityData; // The H5P activity object.
|
||||
accessInfo: AddonModH5PActivityAccessInfo; // Info about the user capabilities.
|
||||
deployedFile: CoreWSExternalFile; // The H5P deployed file.
|
||||
|
||||
stateMessage: string; // Message about the file state.
|
||||
downloading: boolean; // Whether the H5P file is being downloaded.
|
||||
needsDownload: boolean; // Whether the file needs to be downloaded.
|
||||
percentage: string; // Download/unzip percentage.
|
||||
progressMessage: string; // Message about download/unzip.
|
||||
playing: boolean; // Whether the package is being played.
|
||||
|
||||
protected fetchContentDefaultError = 'addon.mod_h5pactivity.errorgetactivity';
|
||||
protected displayOptions: CoreH5PDisplayOptions;
|
||||
|
||||
constructor(injector: Injector,
|
||||
@Optional() protected content: Content) {
|
||||
|
@ -66,12 +88,61 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
|||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(this.courseId, this.module.id);
|
||||
|
||||
this.description = this.h5pActivity.intro;
|
||||
this.displayOptions = CoreH5PHelper.decodeDisplayOptions(this.h5pActivity.displayoptions);
|
||||
this.dataRetrieved.emit(this.h5pActivity);
|
||||
|
||||
await Promise.all([
|
||||
this.fetchAccessInfo(),
|
||||
this.fetchDeployedFileData(),
|
||||
]);
|
||||
} finally {
|
||||
this.fillContextMenu(refresh);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the access info and store it in the right variables.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchAccessInfo(): Promise<void> {
|
||||
this.accessInfo = await AddonModH5PActivity.instance.getAccessInformation(this.h5pActivity.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the deployed file data if needed and store it in the right variables.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchDeployedFileData(): Promise<void> {
|
||||
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);
|
||||
}
|
||||
|
||||
await this.calculateFileStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the status of the deployed file.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async calculateFileStatus(): Promise<void> {
|
||||
const state = await CoreFilepool.instance.getFileStateByUrl(this.siteId, this.deployedFile.fileurl,
|
||||
this.deployedFile.timemodified);
|
||||
|
||||
this.showFileState(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the invalidate content function.
|
||||
*
|
||||
|
@ -80,4 +151,120 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
|||
protected invalidateContent(): Promise<any> {
|
||||
return AddonModH5PActivity.instance.invalidateActivityData(this.courseId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays some data based on the state of the main file.
|
||||
*
|
||||
* @param state The state of the file.
|
||||
*/
|
||||
protected showFileState(state: string): void {
|
||||
|
||||
if (state == CoreConstants.OUTDATED) {
|
||||
this.stateMessage = 'addon.mod_h5pactivity.filestateoutdated';
|
||||
this.needsDownload = true;
|
||||
} else if (state == CoreConstants.NOT_DOWNLOADED) {
|
||||
this.stateMessage = 'addon.mod_h5pactivity.filestatenotdownloaded';
|
||||
this.needsDownload = true;
|
||||
} else if (state == CoreConstants.DOWNLOADING) {
|
||||
this.stateMessage = '';
|
||||
|
||||
if (!this.downloading) {
|
||||
// It's being downloaded right now but the view isn't tracking it. "Restore" the download.
|
||||
this.downloadDeployedFile().then(() => {
|
||||
this.play();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.stateMessage = '';
|
||||
this.needsDownload = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the file and play it.
|
||||
*
|
||||
* @param e Click event.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
async downloadAndPlay(e: MouseEvent): Promise<void> {
|
||||
e && e.preventDefault();
|
||||
e && e.stopPropagation();
|
||||
|
||||
if (!CoreApp.instance.isOnline()) {
|
||||
CoreDomUtils.instance.showErrorModal('core.networkerrormsg', true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Confirm the download if needed.
|
||||
await CoreDomUtils.instance.confirmDownloadSize({ size: this.deployedFile.filesize, total: true });
|
||||
|
||||
await this.downloadDeployedFile();
|
||||
|
||||
if (!this.isDestroyed) {
|
||||
this.play();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
if (CoreDomUtils.instance.isCanceledError(error) || this.isDestroyed) {
|
||||
// User cancelled or view destroyed, stop.
|
||||
return;
|
||||
}
|
||||
|
||||
CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download athe H5P deployed file or restores an ongoing download.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async downloadDeployedFile(): Promise<void> {
|
||||
this.downloading = true;
|
||||
this.progressMessage = 'core.downloading';
|
||||
|
||||
try {
|
||||
await CoreFilepool.instance.downloadUrl(this.siteId, this.deployedFile.fileurl, false, this.component, this.componentId,
|
||||
this.deployedFile.timemodified, (data) => {
|
||||
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.message) {
|
||||
// Show a message.
|
||||
this.progressMessage = data.message;
|
||||
this.percentage = undefined;
|
||||
} else if (typeof data.loaded != 'undefined') {
|
||||
if (this.progressMessage == 'core.downloading') {
|
||||
// Downloading package.
|
||||
this.percentage = (Number(data.loaded / this.deployedFile.filesize) * 100).toFixed(1);
|
||||
} else if (typeof data.total != 'undefined') {
|
||||
// Unzipping package.
|
||||
this.percentage = (Number(data.loaded / data.total) * 100).toFixed(1);
|
||||
} else {
|
||||
this.percentage = undefined;
|
||||
}
|
||||
} else {
|
||||
this.percentage = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
} finally {
|
||||
this.progressMessage = undefined;
|
||||
this.percentage = undefined;
|
||||
this.downloading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Play the package.
|
||||
*/
|
||||
play(): void {
|
||||
this.playing = true;
|
||||
|
||||
// @TODO
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
{
|
||||
"errorgetactivity": "Error getting H5P activity data.",
|
||||
"modulenameplural": "H5P"
|
||||
"filestatenotdownloaded": "The H5P package is not downloaded. You need to download it to be able to use it.",
|
||||
"filestateoutdated": "The H5P package has been modified since the last download. You need to download it again to be able to use it.",
|
||||
"modulenameplural": "H5P",
|
||||
"storingfiles": "Storing files"
|
||||
}
|
|
@ -17,6 +17,7 @@ import { Injectable } from '@angular/core';
|
|||
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 { makeSingleton, Translate } from '@singletons/core.singletons';
|
||||
|
||||
|
@ -29,6 +30,39 @@ export class AddonModH5PActivityProvider {
|
|||
|
||||
protected ROOT_CACHE_KEY = 'mmaModH5PActivity:';
|
||||
|
||||
/**
|
||||
* Get cache key for access information WS calls.
|
||||
*
|
||||
* @param id H5P activity ID.
|
||||
* @return Cache key.
|
||||
*/
|
||||
protected getAccessInformationCacheKey(id: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'accessInfo:' + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access information for a given H5P activity.
|
||||
*
|
||||
* @param id H5P activity ID.
|
||||
* @param forceCache True to always get the value from cache. false otherwise.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with the data.
|
||||
*/
|
||||
async getAccessInformation(id: number, forceCache?: boolean, siteId?: string): Promise<AddonModH5PActivityAccessInfo> {
|
||||
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
const params = {
|
||||
h5pactivityid: id,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAccessInformationCacheKey(id),
|
||||
omitExpires: forceCache,
|
||||
};
|
||||
|
||||
return site.read('mod_h5pactivity_get_h5pactivity_access_information', params, preSets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for H5P activity data WS calls.
|
||||
*
|
||||
|
@ -54,6 +88,7 @@ export class AddonModH5PActivityProvider {
|
|||
: Promise<AddonModH5PActivityData> {
|
||||
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
const params = {
|
||||
courseids: [courseId],
|
||||
};
|
||||
|
@ -66,7 +101,7 @@ export class AddonModH5PActivityProvider {
|
|||
preSets.omitExpires = true;
|
||||
}
|
||||
|
||||
const response: AddonModH5PActivityGetByCoursesRresult =
|
||||
const response: AddonModH5PActivityGetByCoursesResult =
|
||||
await site.read('mod_h5pactivity_get_h5pactivities_by_courses', params, preSets);
|
||||
|
||||
if (response && response.h5pactivities) {
|
||||
|
@ -108,6 +143,20 @@ export class AddonModH5PActivityProvider {
|
|||
return this.getH5PActivityByField(courseId, 'id', id, forceCache, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates access information.
|
||||
*
|
||||
* @param id H5P activity ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when the data is invalidated.
|
||||
*/
|
||||
async invalidateAccessInformation(id: number, siteId?: string): Promise<void> {
|
||||
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
await site.invalidateWsCacheForKey(this.getAccessInformationCacheKey(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates H5P activity data.
|
||||
*
|
||||
|
@ -115,10 +164,10 @@ export class AddonModH5PActivityProvider {
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when the data is invalidated.
|
||||
*/
|
||||
async invalidateActivityData(courseId: number, siteId?: string): Promise<any> {
|
||||
async invalidateActivityData(courseId: number, siteId?: string): Promise<void> {
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
return site.invalidateWsCacheForKey(this.getH5PActivityDataCacheKey(courseId));
|
||||
await site.invalidateWsCacheForKey(this.getH5PActivityDataCacheKey(courseId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,6 +180,35 @@ export class AddonModH5PActivityProvider {
|
|||
|
||||
return site.wsAvailable('mod_h5pactivity_get_h5pactivities_by_courses');
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an H5P activity as being viewed.
|
||||
*
|
||||
* @param id H5P activity ID.
|
||||
* @param name Name of the activity.
|
||||
* @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> {
|
||||
const params = {
|
||||
h5pactivityid: id,
|
||||
};
|
||||
|
||||
const result: AddonModH5PActivityViewResult = await CoreCourseLogHelper.instance.logSingle(
|
||||
'mod_h5pactivity_view_h5pactivity',
|
||||
params,
|
||||
AddonModH5PActivityProvider.COMPONENT,
|
||||
id,
|
||||
name,
|
||||
'h5pactivity',
|
||||
{},
|
||||
siteId
|
||||
);
|
||||
|
||||
if (!result.status) {
|
||||
throw result.warnings[0] || 'Error marking H5P activity as viewed.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class AddonModH5PActivity extends makeSingleton(AddonModH5PActivityProvider) {}
|
||||
|
@ -167,7 +245,26 @@ export type AddonModH5PActivityData = {
|
|||
/**
|
||||
* Result of WS mod_h5pactivity_get_h5pactivities_by_courses.
|
||||
*/
|
||||
export type AddonModH5PActivityGetByCoursesRresult = {
|
||||
export type AddonModH5PActivityGetByCoursesResult = {
|
||||
h5pactivities: AddonModH5PActivityData[];
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Result of WS mod_h5pactivity_get_h5pactivity_access_information.
|
||||
*/
|
||||
export type AddonModH5PActivityAccessInfo = {
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
canview?: boolean; // Whether the user has the capability mod/h5pactivity:view allowed.
|
||||
canaddinstance?: boolean; // Whether the user has the capability mod/h5pactivity:addinstance allowed.
|
||||
cansubmit?: boolean; // Whether the user has the capability mod/h5pactivity:submit allowed.
|
||||
canreviewattempts?: boolean; // Whether the user has the capability mod/h5pactivity:reviewattempts allowed.
|
||||
};
|
||||
|
||||
/**
|
||||
* Result of WS mod_h5pactivity_view_h5pactivity.
|
||||
*/
|
||||
export type AddonModH5PActivityViewResult = {
|
||||
status: boolean; // Status: true if success.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
|
|
@ -1257,7 +1257,7 @@ export class AddonModScormProvider {
|
|||
/**
|
||||
* Invalidates access information.
|
||||
*
|
||||
* @param forumId SCORM ID.
|
||||
* @param scormId SCORM ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when the data is invalidated.
|
||||
*/
|
||||
|
@ -1544,7 +1544,7 @@ export class AddonModScormProvider {
|
|||
|
||||
return this.logHelper.logSingle('mod_scorm_view_scorm', params, AddonModScormProvider.COMPONENT, id, name, 'scorm', {},
|
||||
siteId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a SCORM tracking record.
|
||||
|
|
|
@ -660,7 +660,10 @@
|
|||
"addon.mod_glossary.searchquery": "Search query",
|
||||
"addon.mod_glossary.tagarea_glossary_entries": "Glossary entries",
|
||||
"addon.mod_h5pactivity.errorgetactivity": "Error getting H5P activity data.",
|
||||
"addon.mod_h5pactivity.filestatenotdownloaded": "The H5P package is not downloaded. You need to download it to be able to use it.",
|
||||
"addon.mod_h5pactivity.filestateoutdated": "The H5P package has been modified since the last download. You need to download it again to be able to use it.",
|
||||
"addon.mod_h5pactivity.modulenameplural": "H5P",
|
||||
"addon.mod_h5pactivity.storingfiles": "Storing files",
|
||||
"addon.mod_imscp.deploymenterror": "Content package error!",
|
||||
"addon.mod_imscp.modulenameplural": "IMS content packages",
|
||||
"addon.mod_imscp.showmoduledescription": "Show description",
|
||||
|
|
|
@ -20,6 +20,8 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||
|
||||
import { makeSingleton } from '@singletons/core.singletons';
|
||||
|
||||
/**
|
||||
* Helper to manage logging to Moodle.
|
||||
*/
|
||||
|
@ -355,3 +357,5 @@ export class CoreCourseLogHelperProvider {
|
|||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export class CoreCourseLogHelper extends makeSingleton(CoreCourseLogHelperProvider) {}
|
||||
|
|
|
@ -16,8 +16,9 @@ import { CoreFile, CoreFileProvider } from '@providers/file';
|
|||
import { CoreSites } from '@providers/sites';
|
||||
import { CoreMimetypeUtils } from '@providers/utils/mimetype';
|
||||
import { CoreTextUtils } from '@providers/utils/text';
|
||||
import { CoreUtils } from '@providers/utils/utils';
|
||||
import { CoreH5P } from '../providers/h5p';
|
||||
import { CoreH5PCore } from './core';
|
||||
import { CoreH5PCore, CoreH5PDisplayOptions } from './core';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
|
||||
/**
|
||||
|
@ -25,6 +26,25 @@ import { FileEntry } from '@ionic-native/file';
|
|||
*/
|
||||
export class CoreH5PHelper {
|
||||
|
||||
/**
|
||||
* Convert the number representation of display options into an object.
|
||||
*
|
||||
* @param displayOptions Number representing display options.
|
||||
* @return Object with display options.
|
||||
*/
|
||||
static decodeDisplayOptions(displayOptions: number): CoreH5PDisplayOptions {
|
||||
const config: any = {};
|
||||
const displayOptionsObject = CoreH5P.instance.h5pCore.getDisplayOptionsAsObject(displayOptions);
|
||||
|
||||
config.export = 0; // Don't allow downloading in the app.
|
||||
config.embed = CoreUtils.instance.notNullOrUndefined(displayOptionsObject[CoreH5PCore.DISPLAY_OPTION_EMBED]) ?
|
||||
displayOptionsObject[CoreH5PCore.DISPLAY_OPTION_EMBED] : 0;
|
||||
config.copyright = CoreUtils.instance.notNullOrUndefined(displayOptionsObject[CoreH5PCore.DISPLAY_OPTION_COPYRIGHT]) ?
|
||||
displayOptionsObject[CoreH5PCore.DISPLAY_OPTION_COPYRIGHT] : 0;
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the core H5P assets, including all core H5P JavaScript and CSS.
|
||||
*
|
||||
|
@ -107,19 +127,25 @@ export class CoreH5PHelper {
|
|||
* @param fileUrl The file URL used to download the file.
|
||||
* @param file The file entry of the downloaded file.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param onProgress Function to call on progress.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
static async saveH5P(fileUrl: string, file: FileEntry, siteId?: string): Promise<void> {
|
||||
static async saveH5P(fileUrl: string, file: FileEntry, siteId?: string, onProgress?: (event: any) => any): Promise<void> {
|
||||
siteId = siteId || CoreSites.instance.getCurrentSiteId();
|
||||
|
||||
// Unzip the file.
|
||||
const folderName = CoreMimetypeUtils.instance.removeExtension(file.name);
|
||||
const destFolder = CoreTextUtils.instance.concatenatePaths(CoreFileProvider.TMPFOLDER, 'h5p/' + folderName);
|
||||
|
||||
// Notify that the unzip is starting.
|
||||
onProgress && onProgress({message: 'core.unzipping'});
|
||||
|
||||
// Unzip the file.
|
||||
await CoreFile.instance.unzipFile(file.toURL(), destFolder);
|
||||
await CoreFile.instance.unzipFile(file.toURL(), destFolder, onProgress);
|
||||
|
||||
try {
|
||||
// Notify that the unzip is starting.
|
||||
onProgress && onProgress({message: 'addon.mod_h5pactivity.storingfiles'});
|
||||
|
||||
// Read the contents of the unzipped dir, process them and store them.
|
||||
const contents = await CoreFile.instance.getDirectoryContents(destFolder);
|
||||
|
||||
|
|
|
@ -219,11 +219,11 @@ export class CoreH5PPlayer {
|
|||
* Get the content index file.
|
||||
*
|
||||
* @param fileUrl URL of the H5P package.
|
||||
* @param urlParams URL params.
|
||||
* @param displayOptions Display options.
|
||||
* @param siteId The site ID. If not defined, current site.
|
||||
* @return Promise resolved with the file URL if exists, rejected otherwise.
|
||||
*/
|
||||
async getContentIndexFileUrl(fileUrl: string, urlParams?: {[name: string]: string}, siteId?: string): Promise<string> {
|
||||
async getContentIndexFileUrl(fileUrl: string, displayOptions?: CoreH5PDisplayOptions, siteId?: string): Promise<string> {
|
||||
siteId = siteId || CoreSites.instance.getCurrentSiteId();
|
||||
|
||||
const path = await this.h5pCore.h5pFS.getContentIndexFileUrl(fileUrl, siteId);
|
||||
|
@ -231,9 +231,9 @@ export class CoreH5PPlayer {
|
|||
// Add display options to the URL.
|
||||
const data = await this.h5pCore.h5pFramework.getContentDataByUrl(fileUrl, siteId);
|
||||
|
||||
const options = this.h5pCore.fixDisplayOptions(this.getDisplayOptionsFromUrlParams(urlParams), data.id);
|
||||
displayOptions = this.h5pCore.fixDisplayOptions(displayOptions, data.id);
|
||||
|
||||
return CoreUrlUtils.instance.addParamsToUrl(path, options, undefined, true);
|
||||
return CoreUrlUtils.instance.addParamsToUrl(path, displayOptions, undefined, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -93,11 +93,12 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.loading = true;
|
||||
|
||||
let localUrl: string;
|
||||
const displayOptions = CoreH5P.instance.h5pPlayer.getDisplayOptionsFromUrlParams(this.urlParams);
|
||||
|
||||
if (this.canDownload && CoreFileHelper.instance.isStateDownloaded(this.state)) {
|
||||
// Package is downloaded, use the local URL.
|
||||
try {
|
||||
localUrl = await CoreH5P.instance.h5pPlayer.getContentIndexFileUrl(this.urlParams.url, this.urlParams, this.siteId);
|
||||
localUrl = await CoreH5P.instance.h5pPlayer.getContentIndexFileUrl(this.urlParams.url, displayOptions, this.siteId);
|
||||
} catch (error) {
|
||||
// Index file doesn't exist, probably deleted because a lib was updated. Try to create it again.
|
||||
try {
|
||||
|
@ -108,7 +109,7 @@ export class CoreH5PPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
|||
await CoreH5PHelper.saveH5P(this.urlParams.url, file, this.siteId);
|
||||
|
||||
// File treated. Try to get the index file URL again.
|
||||
localUrl = await CoreH5P.instance.h5pPlayer.getContentIndexFileUrl(this.urlParams.url, this.urlParams,
|
||||
localUrl = await CoreH5P.instance.h5pPlayer.getContentIndexFileUrl(this.urlParams.url, displayOptions,
|
||||
this.siteId);
|
||||
} catch (error) {
|
||||
// Still failing. Delete the H5P package?
|
||||
|
|
|
@ -18,6 +18,7 @@ import { CoreMimetypeUtils } from '@providers/utils/mimetype';
|
|||
import { CoreUrlUtils } from '@providers/utils/url';
|
||||
import { CoreUtils } from '@providers/utils/utils';
|
||||
import { CoreH5P } from './h5p';
|
||||
import { CoreSites } from '@providers/sites';
|
||||
import { CoreWSExternalFile } from '@providers/ws';
|
||||
import { FileEntry } from '@ionic-native/file';
|
||||
import { Translate } from '@singletons/core.singletons';
|
||||
|
@ -50,7 +51,14 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler {
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved with the file to use. Rejected if cannot download.
|
||||
*/
|
||||
getDownloadableFile(file: CoreWSExternalFile, siteId?: string): Promise<CoreWSExternalFile> {
|
||||
async getDownloadableFile(file: CoreWSExternalFile, siteId?: string): Promise<CoreWSExternalFile> {
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
if (site.containsUrl(file.fileurl) && file.fileurl.match(/pluginfile\.php\/[^\/]+\/core_h5p\/export\//i)) {
|
||||
// It's already a deployed file, use it.
|
||||
return file;
|
||||
}
|
||||
|
||||
return CoreH5P.instance.getTrustedH5PFile(file.fileurl, {}, false, siteId);
|
||||
}
|
||||
|
||||
|
@ -85,7 +93,7 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler {
|
|||
*/
|
||||
async getFileSize(file: CoreWSExternalFile, siteId?: string): Promise<number> {
|
||||
try {
|
||||
const trustedFile = await CoreH5P.instance.getTrustedH5PFile(file.fileurl, {}, false, siteId);
|
||||
const trustedFile = await this.getDownloadableFile(file, siteId);
|
||||
|
||||
return trustedFile.filesize;
|
||||
} catch (error) {
|
||||
|
@ -145,9 +153,10 @@ export class CoreH5PPluginFileHandler implements CorePluginFileHandler {
|
|||
* @param fileUrl The file URL used to download the file.
|
||||
* @param file The file entry of the downloaded file.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param onProgress Function to call on progress.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string): Promise<void> {
|
||||
return CoreH5PHelper.saveH5P(fileUrl, file, siteId);
|
||||
treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string, onProgress?: (event: any) => any): Promise<void> {
|
||||
return CoreH5PHelper.saveH5P(fileUrl, file, siteId, onProgress);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1058,7 +1058,7 @@ export class CoreFilepoolProvider {
|
|||
return this.wsProvider.downloadFile(fileUrl, filePath, addExtension, onProgress).then((entry) => {
|
||||
fileEntry = entry;
|
||||
|
||||
return this.pluginFileDelegate.treatDownloadedFile(fileUrl, fileEntry, siteId);
|
||||
return this.pluginFileDelegate.treatDownloadedFile(fileUrl, fileEntry, siteId, onProgress);
|
||||
}).then(() => {
|
||||
const data: CoreFilepoolFileEntry = poolFileObject || {};
|
||||
|
||||
|
|
|
@ -108,9 +108,10 @@ export interface CorePluginFileHandler extends CoreDelegateHandler {
|
|||
* @param fileUrl The file URL used to download the file.
|
||||
* @param file The file entry of the downloaded file.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param onProgress Function to call on progress.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
treatDownloadedFile?(fileUrl: string, file: FileEntry, siteId?: string): Promise<any>;
|
||||
treatDownloadedFile?(fileUrl: string, file: FileEntry, siteId?: string, onProgress?: (event: any) => any): Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,13 +361,14 @@ export class CorePluginFileDelegate extends CoreDelegate {
|
|||
* @param fileUrl The file URL used to download the file.
|
||||
* @param file The file entry of the downloaded file.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param onProgress Function to call on progress.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string): Promise<any> {
|
||||
treatDownloadedFile(fileUrl: string, file: FileEntry, siteId?: string, onProgress?: (event: any) => any): Promise<any> {
|
||||
const handler = this.getHandlerForFile({fileurl: fileUrl});
|
||||
|
||||
if (handler && handler.treatDownloadedFile) {
|
||||
return handler.treatDownloadedFile(fileUrl, file, siteId);
|
||||
return handler.treatDownloadedFile(fileUrl, file, siteId, onProgress);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
|
|
|
@ -872,6 +872,16 @@ export class CoreUtilsProvider {
|
|||
return this.uniqueArray(array1.concat(array2), key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value isn't null or undefined.
|
||||
*
|
||||
* @param value Value to check.
|
||||
* @return True if not null and not undefined.
|
||||
*/
|
||||
notNullOrUndefined(value: any): boolean {
|
||||
return typeof value != 'undefined' && value !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a file using platform specific method.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue