diff --git a/src/addon/mod/feedback/providers/prefetch-handler.ts b/src/addon/mod/feedback/providers/prefetch-handler.ts index 01c846d74..0c0562638 100644 --- a/src/addon/mod/feedback/providers/prefetch-handler.ts +++ b/src/addon/mod/feedback/providers/prefetch-handler.ts @@ -28,6 +28,7 @@ import { CoreGroupsProvider } from '@providers/groups'; import { AddonModFeedbackSyncProvider } from './sync'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CorePluginFileDelegate } from '@providers/plugin-file-delegate'; +import { CoreWSExternalFile } from '@providers/ws'; /** * Handler to prefetch feedbacks. @@ -68,26 +69,31 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH * @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. */ - getFiles(module: any, courseId: number, single?: boolean): Promise { + async getFiles(module: any, courseId: number, single?: boolean): Promise { let files = []; - return this.feedbackProvider.getFeedback(courseId, module.id).then((feedback) => { + const feedback = await this.feedbackProvider.getFeedback(courseId, module.id); - // Get intro files and page after submit files. - files = feedback.pageaftersubmitfiles || []; - files = files.concat(this.getIntroFilesFromInstance(module, feedback)); + // Get intro files and page after submit files. + files = feedback.pageaftersubmitfiles || []; + files = files.concat(this.getIntroFilesFromInstance(module, feedback)); + + try { + const response = await this.feedbackProvider.getItems(feedback.id); - return this.feedbackProvider.getItems(feedback.id); - }).then((response) => { response.items.forEach((item) => { - files = files.concat(item.itemfiles); + files = files.concat(item.itemfiles.map((file) => { + file.fileurl = file.fileurl || file.url; + + return file; + })); }); - return files; - }).catch(() => { - // Any error, return the list we have. - return files; - }); + } catch (e) { + // Ignore errors. + } + + return files; } /** @@ -97,7 +103,7 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH * @param courseId Course ID. * @return Promise resolved with list of intro files. */ - getIntroFiles(module: any, courseId: number): Promise { + getIntroFiles(module: any, courseId: number): Promise { return this.feedbackProvider.getFeedback(courseId, module.id).catch(() => { // Not found, return undefined so module description is used. }).then((feedback) => { diff --git a/src/addon/mod/lesson/providers/prefetch-handler.ts b/src/addon/mod/lesson/providers/prefetch-handler.ts index 46ef36db2..c8601ae58 100644 --- a/src/addon/mod/lesson/providers/prefetch-handler.ts +++ b/src/addon/mod/lesson/providers/prefetch-handler.ts @@ -111,7 +111,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan let files = lesson.mediafiles || []; files = files.concat(this.getIntroFilesFromInstance(module, lesson)); - return this.pluginFileDelegate.getFilesSize(files); + return this.pluginFileDelegate.getFilesDownloadSize(files); }).then((res) => { result = res; diff --git a/src/addon/mod/wiki/providers/prefetch-handler.ts b/src/addon/mod/wiki/providers/prefetch-handler.ts index 7870b158d..f9677e893 100644 --- a/src/addon/mod/wiki/providers/prefetch-handler.ts +++ b/src/addon/mod/wiki/providers/prefetch-handler.ts @@ -97,7 +97,7 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl siteId = this.sitesProvider.getCurrentSiteId(); promises.push(this.getFiles(module, courseId, single, siteId).then((files) => { - return this.pluginFileDelegate.getFilesSize(files); + return this.pluginFileDelegate.getFilesDownloadSize(files); })); promises.push(this.getAllPages(module, courseId, false, true, siteId).then((pages) => { diff --git a/src/core/course/classes/module-prefetch-handler.ts b/src/core/course/classes/module-prefetch-handler.ts index 815cbf5c4..e51ba6e0a 100644 --- a/src/core/course/classes/module-prefetch-handler.ts +++ b/src/core/course/classes/module-prefetch-handler.ts @@ -19,6 +19,7 @@ import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCourseProvider } from '../providers/course'; +import { CoreWSExternalFile } from '@providers/ws'; import { CoreCourseModulePrefetchHandler } from '../providers/module-prefetch-delegate'; import { CoreFilterHelperProvider } from '@core/filter/providers/helper'; import { CorePluginFileDelegate } from '@providers/plugin-file-delegate'; @@ -114,7 +115,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref * @param module The module object returned by WS. * @return List of files. */ - getContentDownloadableFiles(module: any): any[] { + getContentDownloadableFiles(module: any): CoreWSExternalFile[] { const files = []; if (module.contents && module.contents.length) { @@ -139,7 +140,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref */ getDownloadSize(module: any, courseId: number, single?: boolean): Promise<{ size: number, total: boolean }> { return this.getFiles(module, courseId).then((files) => { - return this.pluginFileDelegate.getFilesSize(files); + return this.pluginFileDelegate.getFilesDownloadSize(files); }).catch(() => { return { size: -1, total: false }; }); @@ -166,7 +167,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref * @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. */ - getFiles(module: any, courseId: number, single?: boolean): Promise { + getFiles(module: any, courseId: number, single?: boolean): Promise { // To be overridden. return Promise.resolve([]); } @@ -179,7 +180,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref * @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down). * @return Promise resolved with list of intro files. */ - getIntroFiles(module: any, courseId: number, ignoreCache?: boolean): Promise { + getIntroFiles(module: any, courseId: number, ignoreCache?: boolean): Promise { return Promise.resolve(this.getIntroFilesFromInstance(module)); } @@ -190,7 +191,7 @@ export class CoreCourseModulePrefetchHandlerBase implements CoreCourseModulePref * @param instance The instance to get the intro files (book, assign, ...). If not defined, module will be used. * @return List of intro files. */ - getIntroFilesFromInstance(module: any, instance?: any): any[] { + getIntroFilesFromInstance(module: any, instance?: any): CoreWSExternalFile[] { if (instance) { if (typeof instance.introfiles != 'undefined') { return instance.introfiles; diff --git a/src/providers/filepool.ts b/src/providers/filepool.ts index e26d4d15b..e254d972d 100644 --- a/src/providers/filepool.ts +++ b/src/providers/filepool.ts @@ -1397,7 +1397,7 @@ export class CoreFilepoolProvider { * @param html HTML code. * @return List of fake file objects with file URLs. */ - extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): any[] { + extractDownloadableFilesFromHtmlAsFakeFileObjects(html: string): CoreWSExternalFile[] { const urls = this.extractDownloadableFilesFromHtml(html); // Convert them to fake file objects. @@ -1768,46 +1768,50 @@ export class CoreFilepoolProvider { * @param revision File revision. If not defined, it will be calculated using the URL. * @return Promise resolved with the file state. */ - getFileStateByUrl(siteId: string, fileUrl: string, timemodified: number = 0, filePath?: string, revision?: number) + async getFileStateByUrl(siteId: string, fileUrl: string, timemodified: number = 0, filePath?: string, revision?: number) : Promise { - let fileId; + let file; - return this.fixPluginfileURL(siteId, fileUrl, timemodified).then((file) => { - - fileUrl = file.fileurl; - timemodified = file.timemodified || timemodified; - revision = revision || this.getRevisionFromUrl(fileUrl); - fileId = this.getFileIdByUrl(fileUrl); - - // Check if the file is in queue (waiting to be downloaded). - return this.hasFileInQueue(siteId, fileId).then(() => { - return CoreConstants.DOWNLOADING; - }).catch(() => { - // Check if the file is being downloaded right now. - const extension = this.mimeUtils.guessExtensionFromUrl(fileUrl), - path = filePath ? filePath : this.getFilePath(siteId, fileId, extension); - - return Promise.resolve(path).then((filePath) => { - const downloadId = this.getFileDownloadId(fileUrl, filePath); - if (this.filePromises[siteId] && this.filePromises[siteId][downloadId]) { - return CoreConstants.DOWNLOADING; - } - - // File is not being downloaded. Check if it's downloaded and if it's outdated. - return this.hasFileInPool(siteId, fileId).then((entry) => { - if (this.isFileOutdated(entry, revision, timemodified)) { - return CoreConstants.OUTDATED; - } else { - return CoreConstants.DOWNLOADED; - } - }).catch(() => { - return CoreConstants.NOT_DOWNLOADED; - }); - }); - }); - }, () => { + try { + file = await this.fixPluginfileURL(siteId, fileUrl, timemodified); + } catch (e) { return CoreConstants.NOT_DOWNLOADABLE; - }); + } + + fileUrl = file.fileurl; + timemodified = file.timemodified || timemodified; + revision = revision || this.getRevisionFromUrl(fileUrl); + const fileId = this.getFileIdByUrl(fileUrl); + + try { + // Check if the file is in queue (waiting to be downloaded). + await this.hasFileInQueue(siteId, fileId); + + return CoreConstants.DOWNLOADING; + } catch (e) { + // Check if the file is being downloaded right now. + const extension = this.mimeUtils.guessExtensionFromUrl(fileUrl); + filePath = filePath || (await this.getFilePath(siteId, fileId, extension)); + + const downloadId = this.getFileDownloadId(fileUrl, filePath); + + if (this.filePromises[siteId] && this.filePromises[siteId][downloadId]) { + return CoreConstants.DOWNLOADING; + } + + try { + // File is not being downloaded. Check if it's downloaded and if it's outdated. + const entry = await this.hasFileInPool(siteId, fileId); + + if (this.isFileOutdated(entry, revision, timemodified)) { + return CoreConstants.OUTDATED; + } + + return CoreConstants.DOWNLOADED; + } catch (e) { + return CoreConstants.NOT_DOWNLOADED; + } + } } /** diff --git a/src/providers/plugin-file-delegate.ts b/src/providers/plugin-file-delegate.ts index b08989dc2..a7ee3d04c 100644 --- a/src/providers/plugin-file-delegate.ts +++ b/src/providers/plugin-file-delegate.ts @@ -18,6 +18,8 @@ import { CoreLoggerProvider } from './logger'; import { CoreSitesProvider } from './sites'; import { CoreWSExternalFile } from '@providers/ws'; import { FileEntry } from '@ionic-native/file'; +import { CoreFilepool } from './filepool'; +import { CoreConstants } from '@core/constants'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { makeSingleton } from '@singletons/core.singletons'; @@ -234,6 +236,27 @@ export class CorePluginFileDelegate extends CoreDelegate { return files; } + /** + * Sum the filesizes from a list if they are not downloaded. + * + * @param files List of files to sum its filesize. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved with file size and a boolean to indicate if it is the total size or only partial. + */ + async getFilesDownloadSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> { + const filteredFiles = []; + + await Promise.all(files.map(async (file) => { + const state = await CoreFilepool.instance.getFileStateByUrl(siteId, file.fileurl, file.timemodified); + + if (state != CoreConstants.DOWNLOADED && state != CoreConstants.NOT_DOWNLOADABLE) { + filteredFiles.push(file); + } + })); + + return this.getFilesSize(filteredFiles, siteId); + } + /** * Sum the filesizes from a list of files checking if the size will be partial or totally calculated. * @@ -241,27 +264,24 @@ export class CorePluginFileDelegate extends CoreDelegate { * @param siteId Site ID. If not defined, current site. * @return Promise resolved with file size and a boolean to indicate if it is the total size or only partial. */ - getFilesSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> { - const promises = [], - result = { - size: 0, - total: true - }; + async getFilesSize(files: CoreWSExternalFile[], siteId?: string): Promise<{ size: number, total: boolean }> { + const result = { + size: 0, + total: true + }; - files.forEach((file) => { - promises.push(this.getFileSize(file, siteId).then((size) => { - if (typeof size == 'undefined') { - // We don't have the file size, cannot calculate its total size. - result.total = false; - } else { - result.size += size; - } - })); - }); + await Promise.all(files.map(async (file) => { + const size = await this.getFileSize(file, siteId); - return Promise.all(promises).then(() => { - return result; - }); + if (typeof size == 'undefined') { + // We don't have the file size, cannot calculate its total size. + result.total = false; + } else { + result.size += size; + } + })); + + return result; } /**