MOBILE-3411 h5pactivity: Add button to download the file

main
Dani Palou 2020-05-26 15:10:58 +02:00
parent 4bbd05bd55
commit 0196a738d7
14 changed files with 385 additions and 27 deletions

View File

@ -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>

View File

@ -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
}
}

View File

@ -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"
}

View File

@ -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[];
};

View File

@ -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.

View File

@ -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",

View File

@ -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) {}

View File

@ -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);

View File

@ -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);
}
/**

View File

@ -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?

View File

@ -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);
}
}

View File

@ -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 || {};

View File

@ -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();

View File

@ -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.
*