MOBILE-3659 course: Implement prefetch delegate
This commit is contained in:
		
							parent
							
								
									d14540218a
								
							
						
					
					
						commit
						031f238117
					
				| @ -201,6 +201,7 @@ const appConfig = { | ||||
|         'no-duplicate-imports': 'error', | ||||
|         'no-empty': 'error', | ||||
|         'no-eval': 'error', | ||||
|         'no-fallthrough': 'off', | ||||
|         'no-invalid-this': 'error', | ||||
|         'no-irregular-whitespace': 'error', | ||||
|         'no-multiple-empty-lines': 'error', | ||||
|  | ||||
| @ -17,7 +17,7 @@ import { CoreSites } from '@services/sites'; | ||||
| import { CoreCourse, CoreCourseSection } from '@features/course/services/course'; | ||||
| import { CoreCourseHelper } from '@features/course/services/course-helper'; | ||||
| import { CoreSiteHome, FrontPageItemNames } from '@features/sitehome/services/sitehome'; | ||||
| // @todo import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
 | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { CoreBlockBaseComponent } from '@features/block/classes/base-block-component'; | ||||
| 
 | ||||
| /** | ||||
| @ -63,7 +63,7 @@ export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent impl | ||||
| 
 | ||||
|         if (this.mainMenuBlock && this.mainMenuBlock.modules) { | ||||
|             // Invalidate modules prefetch data.
 | ||||
|             // @todo promises.push(this.prefetchDelegate.invalidateModules(this.mainMenuBlock.modules, this.siteHomeId));
 | ||||
|             promises.push(CoreCourseModulePrefetchDelegate.instance.invalidateModules(this.mainMenuBlock.modules, this.siteHomeId)); | ||||
|         } | ||||
| 
 | ||||
|         await Promise.all(promises); | ||||
|  | ||||
| @ -144,7 +144,7 @@ | ||||
|         <ng-container *ngFor="let module of section.modules"> | ||||
|             <core-course-module *ngIf="module.visibleoncoursepage !== 0" [module]="module" [courseId]="course?.id" | ||||
|                 [downloadEnabled]="downloadEnabled" [section]="section" (completionChanged)="onCompletionChange($event)" | ||||
|                 (statusChanged)="onModuleStatusChange($event)"> | ||||
|                 (statusChanged)="onModuleStatusChange()"> | ||||
|             </core-course-module> | ||||
|         </ng-container> | ||||
|     </section> | ||||
|  | ||||
| @ -37,15 +37,13 @@ import { | ||||
|     CoreCourseModuleData, | ||||
|     CoreCourseProvider, | ||||
| } from '@features/course/services/course'; | ||||
| // import { CoreCourseHelper } from '@features/course/services/course-helper';
 | ||||
| import { CoreCourseHelper, CoreCourseSectionFormatted, CoreCourseSectionWithStatus } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate'; | ||||
| import { CoreEventObserver, CoreEvents, CoreEventSectionStatusChangedData, CoreEventSelectCourseTabData } from '@singletons/events'; | ||||
| import { IonContent, IonRefresher } from '@ionic/angular'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| // import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
 | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { CoreBlockCourseBlocksComponent } from '@features/block/components/course-blocks/course-blocks'; | ||||
| import { CoreCourseSectionFormatted } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseModuleStatusChangedData } from '../module/module'; | ||||
| import { ModalController } from '@singletons'; | ||||
| import { CoreCourseSectionSelectorComponent } from '../section-selector/section-selector'; | ||||
| 
 | ||||
| @ -62,13 +60,14 @@ import { CoreCourseSectionSelectorComponent } from '../section-selector/section- | ||||
| @Component({ | ||||
|     selector: 'core-course-format', | ||||
|     templateUrl: 'core-course-format.html', | ||||
|     styleUrls: ['format.scss'], | ||||
| }) | ||||
| export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
| 
 | ||||
|     static readonly LOAD_MORE_ACTIVITIES = 20; // How many activities should load each time showMoreActivities is called.
 | ||||
| 
 | ||||
|     @Input() course?: CoreCourseAnyCourseData; // The course to render.
 | ||||
|     @Input() sections?: CoreCourseSectionFormatted[]; // List of course sections.
 | ||||
|     @Input() sections?: CoreCourseSectionWithStatus[]; // List of course sections. The status will be calculated in this component.
 | ||||
|     @Input() downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
 | ||||
|     @Input() initialSectionId?: number; // The section to load first (by ID).
 | ||||
|     @Input() initialSectionNumber?: number; // The section to load first (by number).
 | ||||
| @ -125,26 +124,26 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 // @todo Check if the affected section is being downloaded.
 | ||||
|                 // Check if the affected section is being downloaded.
 | ||||
|                 // If so, we don't update section status because it'll already be updated when the download finishes.
 | ||||
|                 // const downloadId = CoreCourseHelper.instance.getSectionDownloadId({ id: data.sectionId });
 | ||||
|                 // if (prefetchDelegate.isBeingDownloaded(downloadId)) {
 | ||||
|                 //     return;
 | ||||
|                 // }
 | ||||
|                 const downloadId = CoreCourseHelper.instance.getSectionDownloadId({ id: data.sectionId }); | ||||
|                 if (CoreCourseModulePrefetchDelegate.instance.isBeingDownloaded(downloadId)) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 // Get the affected section.
 | ||||
|                 // const section = this.sections.find(section => section.id == data.sectionId);
 | ||||
|                 // if (!section) {
 | ||||
|                 //     return;
 | ||||
|                 // }
 | ||||
|                 const section = this.sections.find(section => section.id == data.sectionId); | ||||
|                 if (!section) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 // Recalculate the status.
 | ||||
|                 // await CoreCourseHelper.instance.calculateSectionStatus(section, this.course.id, false);
 | ||||
|                 await CoreCourseHelper.instance.calculateSectionStatus(section, this.course.id, false); | ||||
| 
 | ||||
|                 // if (section.isDownloading && !prefetchDelegate.isBeingDownloaded(downloadId)) {
 | ||||
|                 //     // All the modules are now downloading, set a download all promise.
 | ||||
|                 //     this.prefetch(section);
 | ||||
|                 // }
 | ||||
|                 if (section.isDownloading && !CoreCourseModulePrefetchDelegate.instance.isBeingDownloaded(downloadId)) { | ||||
|                     // All the modules are now downloading, set a download all promise.
 | ||||
|                     this.prefetch(section); | ||||
|                 } | ||||
|             }, | ||||
|             CoreSites.instance.getCurrentSiteId(), | ||||
|         ); | ||||
| @ -392,7 +391,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
|             this.canLoadMore = false; | ||||
|             this.showSectionId = 0; | ||||
|             this.showMoreActivities(); | ||||
|             // @todo CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, false, false);
 | ||||
|             if (this.downloadEnabled) { | ||||
|                 this.calculateSectionsStatus(false); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (this.moduleId && typeof previousValue == 'undefined') { | ||||
| @ -427,11 +428,12 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
|      * | ||||
|      * @param refresh If refresh or not. | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     protected calculateSectionsStatus(refresh?: boolean): void { | ||||
|         // @todo CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, refresh).catch(() => {
 | ||||
|         //     // Ignore errors (shouldn't happen).
 | ||||
|         // });
 | ||||
|         if (!this.sections || !this.course) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         CoreUtils.instance.ignoreErrors(CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, refresh)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -440,38 +442,42 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
|      * @param section Section to download. | ||||
|      * @param refresh Refresh clicked (not used). | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     prefetch(section: CoreCourseSectionFormatted): void { | ||||
|         // section.isCalculating = true;
 | ||||
|         // @todo CoreCourseHelper.instance.confirmDownloadSizeSection(this.course.id, section, this.sections).then(() => {
 | ||||
|         //     this.prefetchSection(section, true);
 | ||||
|         // }, (error) => {
 | ||||
|         //     // User cancelled or there was an error calculating the size.
 | ||||
|         //     if (error) {
 | ||||
|         //         CoreDomUtils.instance.showErrorModal(error);
 | ||||
|         //     }
 | ||||
|         // }).finally(() => {
 | ||||
|         //     section.isCalculating = false;
 | ||||
|         // });
 | ||||
|     async prefetch(section: CoreCourseSectionWithStatus): Promise<void> { | ||||
|         section.isCalculating = true; | ||||
| 
 | ||||
|         try { | ||||
|             await CoreCourseHelper.instance.confirmDownloadSizeSection(this.course!.id, section, this.sections); | ||||
| 
 | ||||
|             await this.prefetchSection(section, true); | ||||
|         } catch (error) { | ||||
|             // User cancelled or there was an error calculating the size.
 | ||||
|             if (error) { | ||||
|                 CoreDomUtils.instance.showErrorModal(error); | ||||
|             } | ||||
|         } finally { | ||||
|             section.isCalculating = false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch a section. @todo | ||||
|      * Prefetch a section. | ||||
|      * | ||||
|      * @param section The section to download. | ||||
|      * @param manual Whether the prefetch was started manually or it was automatically started because all modules | ||||
|      *               are being downloaded. | ||||
|      */ | ||||
|     // protected prefetchSection(section: Section, manual?: boolean): void {
 | ||||
|     //     CoreCourseHelper.instance.prefetchSection(section, this.course.id, this.sections).catch((error) => {
 | ||||
|     //         // Don't show error message if it's an automatic download.
 | ||||
|     //         if (!manual) {
 | ||||
|     //             return;
 | ||||
|     //         }
 | ||||
|     protected async prefetchSection(section: CoreCourseSectionWithStatus, manual?: boolean): Promise<void> { | ||||
|         try { | ||||
|             await CoreCourseHelper.instance.prefetchSection(section, this.course!.id, this.sections); | ||||
|         } catch (error) { | ||||
|             // Don't show error message if it's an automatic download.
 | ||||
|             if (!manual) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|     //         CoreDomUtils.instance.showErrorModalDefault(error, 'core.course.errordownloadingsection', true);
 | ||||
|     //     });
 | ||||
|     // }
 | ||||
|             CoreDomUtils.instance.showErrorModalDefault(error, 'core.course.errordownloadingsection', true); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Refresh the data. | ||||
| @ -550,14 +556,16 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
|             component.callComponentFunction('ionViewDidEnter'); | ||||
|         }); | ||||
| 
 | ||||
|         // @todo if (this.downloadEnabled) {
 | ||||
|         //     // The download status of a section might have been changed from within a module page.
 | ||||
|         //     if (this.selectedSection && this.selectedSection.id !== CoreCourseProvider.ALL_SECTIONS_ID) {
 | ||||
|         //         CoreCourseHelper.instance.calculateSectionStatus(this.selectedSection, this.course.id, false, false);
 | ||||
|         //     } else {
 | ||||
|         //         CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, false, false);
 | ||||
|         //     }
 | ||||
|         // }
 | ||||
|         if (!this.downloadEnabled || !this.course || !this.sections) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // The download status of a section might have been changed from within a module page.
 | ||||
|         if (this.selectedSection && this.selectedSection.id !== CoreCourseProvider.ALL_SECTIONS_ID) { | ||||
|             CoreCourseHelper.instance.calculateSectionStatus(this.selectedSection, this.course.id, false, false); | ||||
|         } else { | ||||
|             CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, false, false); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -609,12 +617,13 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { | ||||
| 
 | ||||
|     /** | ||||
|      * Recalculate the download status of each section, in response to a module being downloaded. | ||||
|      * | ||||
|      * @param eventData | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     onModuleStatusChange(eventData: CoreCourseModuleStatusChangedData): void { | ||||
|         // @todo CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, false, false);
 | ||||
|     onModuleStatusChange(): void { | ||||
|         if (!this.downloadEnabled || !this.sections || !this.course) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         CoreCourseHelper.instance.calculateSectionsStatus(this.sections, this.course.id, false, false); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -14,13 +14,20 @@ | ||||
| 
 | ||||
| import { Component, Input, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core'; | ||||
| 
 | ||||
| // import { CoreSites } from '@services/sites';
 | ||||
| // import { CoreDomUtils } from '@services/utils/dom';
 | ||||
| // import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | ||||
| import { CoreCourseModuleDataFormatted, CoreCourseSectionFormatted } from '@features/course/services/course-helper'; | ||||
| import { CoreSites } from '@services/sites'; | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreEventObserver, CoreEventPackageStatusChanged, CoreEvents } from '@singletons/events'; | ||||
| import { | ||||
|     CoreCourseHelper, | ||||
|     CoreCourseModuleDataFormatted, | ||||
|     CoreCourseSectionFormatted, | ||||
| } from '@features/course/services/course-helper'; | ||||
| import { CoreCourse, CoreCourseModuleCompletionData } from '@features/course/services/course'; | ||||
| import { CoreCourseModuleHandlerButton } from '@features/course/services/module-delegate'; | ||||
| // import { CoreCourseModulePrefetchDelegate, CoreCourseModulePrefetchHandler } from '../../providers/module-prefetch-delegate';
 | ||||
| import { | ||||
|     CoreCourseModulePrefetchDelegate, | ||||
|     CoreCourseModulePrefetchHandler, | ||||
| } from '@features/course/services/module-prefetch-delegate'; | ||||
| 
 | ||||
| /** | ||||
|  * Component to display a module entry in a list of modules. | ||||
| @ -32,6 +39,7 @@ import { CoreCourseModuleHandlerButton } from '@features/course/services/module- | ||||
| @Component({ | ||||
|     selector: 'core-course-module', | ||||
|     templateUrl: 'core-course-module.html', | ||||
|     styleUrls: ['module.scss'], | ||||
| }) | ||||
| export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
| 
 | ||||
| @ -51,7 +59,7 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
|         this.spinner = true; // Show spinner while calculating the status.
 | ||||
| 
 | ||||
|         // Get current status to decide which icon should be shown.
 | ||||
|         // @todo this.prefetchDelegate.getModuleStatus(this.module, this.courseId).then(this.showStatus.bind(this));
 | ||||
|         this.calculateAndShowStatus(); | ||||
|     }; | ||||
| 
 | ||||
|     @Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when module completion changes.
 | ||||
| @ -63,8 +71,8 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
|     downloadEnabled?: boolean; // Whether the download of sections and modules is enabled.
 | ||||
|     modNameTranslated = ''; | ||||
| 
 | ||||
|     // protected prefetchHandler: CoreCourseModulePrefetchHandler;
 | ||||
|     // protected statusObserver?: CoreEventObserver;
 | ||||
|     protected prefetchHandler?: CoreCourseModulePrefetchHandler; | ||||
|     protected statusObserver?: CoreEventObserver; | ||||
|     protected statusCalculated = false; | ||||
|     protected isDestroyed = false; | ||||
| 
 | ||||
| @ -86,26 +94,27 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
|         this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title; | ||||
| 
 | ||||
|         if (this.module.handlerData.showDownloadButton) { | ||||
|             // @todo Listen for changes on this module status, even if download isn't enabled.
 | ||||
|             // this.prefetchHandler = this.prefetchDelegate.getPrefetchHandlerFor(this.module);
 | ||||
|             // this.canCheckUpdates = this.prefetchDelegate.canCheckUpdates();
 | ||||
|             // Listen for changes on this module status, even if download isn't enabled.
 | ||||
|             this.prefetchHandler = CoreCourseModulePrefetchDelegate.instance.getPrefetchHandlerFor(this.module); | ||||
|             this.canCheckUpdates = CoreCourseModulePrefetchDelegate.instance.canCheckUpdates(); | ||||
| 
 | ||||
|             // this.statusObserver = this.eventsProvider.on(CoreEvents.PACKAGE_STATUS_CHANGED, (data) => {
 | ||||
|             //     if (data.componentId === this.module.id && this.prefetchHandler &&
 | ||||
|             //             data.component === this.prefetchHandler.component) {
 | ||||
|             this.statusObserver = CoreEvents.on<CoreEventPackageStatusChanged>(CoreEvents.PACKAGE_STATUS_CHANGED, (data) => { | ||||
|                 if (!this.module || data.componentId != this.module.id || !this.prefetchHandler || | ||||
|                         data.component != this.prefetchHandler.component) { | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|             //         // Call determineModuleStatus to get the right status to display.
 | ||||
|             //         const status = this.prefetchDelegate.determineModuleStatus(this.module, data.status);
 | ||||
|                 // Call determineModuleStatus to get the right status to display.
 | ||||
|                 const status = CoreCourseModulePrefetchDelegate.instance.determineModuleStatus(this.module, data.status); | ||||
| 
 | ||||
|             //         if (this.downloadEnabled) {
 | ||||
|             //             // Download is enabled, show the status.
 | ||||
|             //             this.showStatus(status);
 | ||||
|             //         } else if (this.module.handlerData.updateStatus) {
 | ||||
|             //             // Download isn't enabled but the handler defines a updateStatus function, call it anyway.
 | ||||
|             //             this.module.handlerData.updateStatus(status);
 | ||||
|             //         }
 | ||||
|             //     }
 | ||||
|             // }, this.sitesProvider.getCurrentSiteId());
 | ||||
|                 if (this.downloadEnabled) { | ||||
|                     // Download is enabled, show the status.
 | ||||
|                     this.showStatus(status); | ||||
|                 } else if (this.module.handlerData?.updateStatus) { | ||||
|                     // Download isn't enabled but the handler defines a updateStatus function, call it anyway.
 | ||||
|                     this.module.handlerData.updateStatus(status); | ||||
|                 } | ||||
|             }, CoreSites.instance.getCurrentSiteId()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -138,36 +147,39 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @todo Download the module. | ||||
|      * Download the module. | ||||
|      * | ||||
|      * @param refresh Whether it's refreshing. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     // download(refresh: boolean): void {
 | ||||
|     //     if (!this.prefetchHandler) {
 | ||||
|     //         return;
 | ||||
|     //     }
 | ||||
|     async download(refresh: boolean): Promise<void> { | ||||
|         if (!this.prefetchHandler || !this.module) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|     //     // Show spinner since this operation might take a while.
 | ||||
|     //     this.spinner = true;
 | ||||
|         // Show spinner since this operation might take a while.
 | ||||
|         this.spinner = true; | ||||
| 
 | ||||
|     //     // Get download size to ask for confirm if it's high.
 | ||||
|     //     this.prefetchHandler.getDownloadSize(this.module, this.courseId, true).then((size) => {
 | ||||
|     //         return this.courseHelper.prefetchModule(this.prefetchHandler, this.module, size, this.courseId, refresh);
 | ||||
|     //     }).then(() => {
 | ||||
|     //         const eventData = {
 | ||||
|     //             sectionId: this.section.id,
 | ||||
|     //             moduleId: this.module.id,
 | ||||
|     //             courseId: this.courseId
 | ||||
|     //         };
 | ||||
|     //         this.statusChanged.emit(eventData);
 | ||||
|     //     }).catch((error) => {
 | ||||
|     //         // Error, hide spinner.
 | ||||
|     //         this.spinner = false;
 | ||||
|     //         if (!this.isDestroyed) {
 | ||||
|     //             this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
 | ||||
|     //         }
 | ||||
|     //     });
 | ||||
|     // }
 | ||||
|         try { | ||||
|             // Get download size to ask for confirm if it's high.
 | ||||
|             const size = await this.prefetchHandler.getDownloadSize(this.module, this.courseId!, true); | ||||
| 
 | ||||
|             await CoreCourseHelper.instance.prefetchModule(this.prefetchHandler, this.module, size, this.courseId!, refresh); | ||||
| 
 | ||||
|             const eventData = { | ||||
|                 sectionId: this.section?.id, | ||||
|                 moduleId: this.module.id, | ||||
|                 courseId: this.courseId!, | ||||
|             }; | ||||
|             this.statusChanged.emit(eventData); | ||||
|         } catch (error) { | ||||
|             // Error, hide spinner.
 | ||||
|             this.spinner = false; | ||||
|             if (!this.isDestroyed) { | ||||
|                 CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show download buttons according to module status. | ||||
| @ -185,6 +197,21 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { | ||||
|         this.module?.handlerData?.updateStatus?.(status); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Calculate and show module status. | ||||
|      * | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     protected async calculateAndShowStatus(): Promise<void> { | ||||
|         if (!this.module || !this.courseId) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const status = await CoreCourseModulePrefetchDelegate.instance.getModuleStatus(this.module, this.courseId); | ||||
| 
 | ||||
|         this.showStatus(status); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component destroyed. | ||||
|      */ | ||||
|  | ||||
| @ -12,16 +12,19 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { NgModule } from '@angular/core'; | ||||
| import { APP_INITIALIZER, NgModule } from '@angular/core'; | ||||
| import { Routes } from '@angular/router'; | ||||
| 
 | ||||
| import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module'; | ||||
| import { CORE_SITE_SCHEMAS } from '@services/sites'; | ||||
| import { CoreCourseComponentsModule } from './components/components.module'; | ||||
| import { CoreCourseDirectivesModule } from './directives/directives.module'; | ||||
| import { CoreCourseFormatModule } from './format/formats.module'; | ||||
| import { SITE_SCHEMA, OFFLINE_SITE_SCHEMA } from './services/database/course'; | ||||
| import { SITE_SCHEMA as LOG_SITE_SCHEMA } from './services/database/log'; | ||||
| import { SITE_SCHEMA as PREFETCH_SITE_SCHEMA } from './services/database/module-prefetch'; | ||||
| import { CoreCourseIndexRoutingModule } from './pages/index/index-routing.module'; | ||||
| import { CoreCourseModulePrefetchDelegate } from './services/module-prefetch-delegate'; | ||||
| 
 | ||||
| const routes: Routes = [ | ||||
|     { | ||||
| @ -43,14 +46,23 @@ const courseIndexRoutes: Routes = [ | ||||
|         CoreMainMenuTabRoutingModule.forChild(routes), | ||||
|         CoreCourseFormatModule, | ||||
|         CoreCourseComponentsModule, | ||||
|         CoreCourseDirectivesModule, | ||||
|     ], | ||||
|     exports: [CoreCourseIndexRoutingModule], | ||||
|     providers: [ | ||||
|         { | ||||
|             provide: CORE_SITE_SCHEMAS, | ||||
|             useValue: [SITE_SCHEMA, OFFLINE_SITE_SCHEMA, LOG_SITE_SCHEMA], | ||||
|             useValue: [SITE_SCHEMA, OFFLINE_SITE_SCHEMA, LOG_SITE_SCHEMA, PREFETCH_SITE_SCHEMA], | ||||
|             multi: true, | ||||
|         }, | ||||
|         { | ||||
|             provide: APP_INITIALIZER, | ||||
|             multi: true, | ||||
|             deps: [], | ||||
|             useFactory: () => () => { | ||||
|                 CoreCourseModulePrefetchDelegate.instance.initialize(); | ||||
|             }, | ||||
|         }, | ||||
|     ], | ||||
| }) | ||||
| export class CoreCourseModule {} | ||||
|  | ||||
							
								
								
									
										28
									
								
								src/core/features/course/directives/directives.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/core/features/course/directives/directives.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| // (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 { NgModule } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreCourseDownloadModuleMainFileDirective } from './download-module-main-file'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
|         CoreCourseDownloadModuleMainFileDirective, | ||||
|     ], | ||||
|     imports: [], | ||||
|     exports: [ | ||||
|         CoreCourseDownloadModuleMainFileDirective, | ||||
|     ], | ||||
| }) | ||||
| export class CoreCourseDirectivesModule {} | ||||
| @ -0,0 +1,85 @@ | ||||
| // (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 { Directive, Input, OnInit, ElementRef } from '@angular/core'; | ||||
| 
 | ||||
| import { CoreDomUtils } from '@services/utils/dom'; | ||||
| import { CoreCourse, CoreCourseModuleContentFile, CoreCourseWSModule } from '@features/course/services/course'; | ||||
| import { CoreCourseHelper } from '@features/course/services/course-helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Directive to allow downloading and open the main file of a module. | ||||
|  * When the item with this directive is clicked, the module will be downloaded (if needed) and opened. | ||||
|  * This is meant for modules like mod_resource. | ||||
|  * | ||||
|  * This directive must receive either a module or a moduleId. If no files are provided, it will use module.contents. | ||||
|  */ | ||||
| @Directive({ | ||||
|     selector: '[core-course-download-module-main-file]', | ||||
| }) | ||||
| export class CoreCourseDownloadModuleMainFileDirective implements OnInit { | ||||
| 
 | ||||
|     @Input() module?: CoreCourseWSModule; // The module.
 | ||||
|     @Input() moduleId?: string | number; // The module ID. Required if module is not supplied.
 | ||||
|     @Input() courseId?: string | number; // The course ID.
 | ||||
|     @Input() component?: string; // Component to link the file to.
 | ||||
|     @Input() componentId?: string | number; // Component ID to use in conjunction with the component. If not defined, use moduleId.
 | ||||
|     @Input() files?: CoreCourseModuleContentFile[]; // List of files of the module. If not provided, use module.contents.
 | ||||
| 
 | ||||
|     protected element: HTMLElement; | ||||
| 
 | ||||
|     constructor(element: ElementRef) { | ||||
|         this.element = element.nativeElement; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.element.addEventListener('click', async (ev: Event) => { | ||||
|             if (!this.module && !this.moduleId) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             ev.preventDefault(); | ||||
|             ev.stopPropagation(); | ||||
| 
 | ||||
|             const modal = await CoreDomUtils.instance.showModalLoading(); | ||||
|             const courseId = typeof this.courseId == 'string' ? parseInt(this.courseId, 10) : this.courseId; | ||||
| 
 | ||||
|             try { | ||||
|                 if (!this.module) { | ||||
|                     // Try to get the module from cache.
 | ||||
|                     this.moduleId = typeof this.moduleId == 'string' ? parseInt(this.moduleId, 10) : this.moduleId; | ||||
|                     this.module = await CoreCourse.instance.getModule(this.moduleId!, courseId); | ||||
|                 } | ||||
| 
 | ||||
|                 const componentId = this.componentId || module.id; | ||||
| 
 | ||||
|                 await CoreCourseHelper.instance.downloadModuleAndOpenFile( | ||||
|                     this.module, | ||||
|                     courseId ?? this.module.course!, | ||||
|                     this.component, | ||||
|                     componentId, | ||||
|                     this.files, | ||||
|                 ); | ||||
|             } catch (error) { | ||||
|                 CoreDomUtils.instance.showErrorModalDefault(error, 'core.errordownloading', true); | ||||
|             } finally { | ||||
|                 modal.dismiss(); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -28,20 +28,19 @@ import { | ||||
| } from '@features/course/services/course'; | ||||
| import { CoreCourseHelper, CoreCourseSectionFormatted, CorePrefetchStatusInfo } from '@features/course/services/course-helper'; | ||||
| import { CoreCourseFormatDelegate } from '@features/course/services/format-delegate'; | ||||
| // import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
 | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| import { | ||||
|     CoreCourseOptionsDelegate, | ||||
|     CoreCourseOptionsMenuHandlerToDisplay, | ||||
| } from '@features/course/services/course-options-delegate'; | ||||
| // import { CoreCourseSyncProvider } from '../../providers/sync';
 | ||||
| // import { CoreCourseFormatComponent } from '../../components/format/format';
 | ||||
| import { CoreCourseFormatComponent } from '../../components/format/format'; | ||||
| import { | ||||
|     CoreEvents, | ||||
|     CoreEventObserver, | ||||
|     CoreEventCourseStatusChanged, | ||||
|     CoreEventCompletionModuleViewedData, | ||||
| } from '@singletons/events'; | ||||
| import { Translate } from '@singletons'; | ||||
| import { CoreNavHelper } from '@services/nav-helper'; | ||||
| 
 | ||||
| /** | ||||
| @ -54,7 +53,7 @@ import { CoreNavHelper } from '@services/nav-helper'; | ||||
| export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|     @ViewChild(IonContent) content?: IonContent; | ||||
|     // @ViewChild(CoreCourseFormatComponent) formatComponent: CoreCourseFormatComponent;
 | ||||
|     @ViewChild(CoreCourseFormatComponent) formatComponent?: CoreCourseFormatComponent; | ||||
| 
 | ||||
|     course!: CoreCourseAnyCourseData; | ||||
|     sections?: CoreCourseSectionFormatted[]; | ||||
| @ -244,9 +243,9 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|         if (refresh) { | ||||
|             // Invalidate the recently downloaded module list. To ensure info can be prefetched.
 | ||||
|             // const modules = CoreCourse.instance.getSectionsModules(sections);
 | ||||
|             const modules = CoreCourse.instance.getSectionsModules(sections); | ||||
| 
 | ||||
|             // @todo await this.prefetchDelegate.invalidateModules(modules, this.course.id);
 | ||||
|             await CoreCourseModulePrefetchDelegate.instance.invalidateModules(modules, this.course.id); | ||||
|         } | ||||
| 
 | ||||
|         let completionStatus: Record<string, CoreCourseCompletionActivityStatus> = {}; | ||||
| @ -279,14 +278,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|         if (CoreCourseFormatDelegate.instance.canViewAllSections(this.course)) { | ||||
|             // Add a fake first section (all sections).
 | ||||
|             this.sections.unshift({ | ||||
|                 id: CoreCourseProvider.ALL_SECTIONS_ID, | ||||
|                 name: Translate.instance.instant('core.course.allsections'), | ||||
|                 hasContent: true, | ||||
|                 summary: '', | ||||
|                 summaryformat: 1, | ||||
|                 modules: [], | ||||
|             }); | ||||
|             this.sections.unshift(CoreCourseHelper.instance.createAllSectionsSection()); | ||||
|         } | ||||
| 
 | ||||
|         // Get whether to show the refresher now that we have sections.
 | ||||
| @ -345,8 +337,8 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|         } finally { | ||||
|             // Do not call doRefresh on the format component if the refresher is defined in the format component
 | ||||
|             // to prevent an inifinite loop.
 | ||||
|             if (this.displayRefresher) { | ||||
|                 // @todo await CoreUtils.instance.ignoreErrors(this.formatComponent.doRefresh(refresher));
 | ||||
|             if (this.displayRefresher && this.formatComponent) { | ||||
|                 await CoreUtils.instance.ignoreErrors(this.formatComponent.doRefresh(refresher)); | ||||
|             } | ||||
| 
 | ||||
|             refresher?.detail.complete(); | ||||
| @ -384,7 +376,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|         promises.push(CoreCourseFormatDelegate.instance.invalidateData(this.course, this.sections || [])); | ||||
| 
 | ||||
|         if (this.sections) { | ||||
|             // @todo promises.push(this.prefetchDelegate.invalidateCourseUpdates(this.course.id));
 | ||||
|             promises.push(CoreCourseModulePrefetchDelegate.instance.invalidateCourseUpdates(this.course.id)); | ||||
|         } | ||||
| 
 | ||||
|         await Promise.all(promises); | ||||
| @ -408,7 +400,7 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|         try { | ||||
|             await this.loadData(true, sync); | ||||
| 
 | ||||
|             // @todo await this.formatComponent.doRefresh(undefined, undefined, true);
 | ||||
|             await this.formatComponent?.doRefresh(undefined, undefined, true); | ||||
|         } finally { | ||||
|             this.dataLoaded = true; | ||||
| 
 | ||||
| @ -431,15 +423,15 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|     /** | ||||
|      * Prefetch the whole course. | ||||
|      */ | ||||
|     prefetchCourse(): void { | ||||
|     async prefetchCourse(): Promise<void> { | ||||
|         try { | ||||
|             // @todo await CoreCourseHelper.instance.confirmAndPrefetchCourse(
 | ||||
|             //     this.prefetchCourseData,
 | ||||
|             //     this.course,
 | ||||
|             //     this.sections,
 | ||||
|             //     this.courseHandlers,
 | ||||
|             //     this.courseMenuHandlers,
 | ||||
|             // );
 | ||||
|             await CoreCourseHelper.instance.confirmAndPrefetchCourse( | ||||
|                 this.prefetchCourseData, | ||||
|                 this.course, | ||||
|                 this.sections, | ||||
|                 undefined, | ||||
|                 this.courseMenuHandlers, | ||||
|             ); | ||||
|         } catch (error) { | ||||
|             if (this.isDestroyed) { | ||||
|                 return; | ||||
| @ -497,14 +489,14 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy { | ||||
|      * User entered the page. | ||||
|      */ | ||||
|     ionViewDidEnter(): void { | ||||
|         // @todo this.formatComponent?.ionViewDidEnter();
 | ||||
|         this.formatComponent?.ionViewDidEnter(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * User left the page. | ||||
|      */ | ||||
|     ionViewDidLeave(): void { | ||||
|         // @todo this.formatComponent?.ionViewDidLeave();
 | ||||
|         this.formatComponent?.ionViewDidLeave(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -11,7 +11,6 @@ | ||||
| // 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.
 | ||||
| // @todo test delegate
 | ||||
| 
 | ||||
| import { Injectable } from '@angular/core'; | ||||
| import { CoreDelegate, CoreDelegateHandler, CoreDelegateToDisplay } from '@classes/delegate'; | ||||
| @ -178,7 +177,7 @@ export interface CoreCourseOptionsHandlerToDisplay extends CoreDelegateToDisplay | ||||
|      * @param course The course. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     prefetch?(course: CoreEnrolledCourseDataWithExtraInfoAndOptions): Promise<void>; | ||||
|     prefetch?(course: CoreCourseAnyCourseData): Promise<void>; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
| @ -206,7 +205,7 @@ export interface CoreCourseOptionsMenuHandlerToDisplay { | ||||
|      * @param course The course. | ||||
|      * @return Promise resolved when done. | ||||
|      */ | ||||
|     prefetch?(course: CoreEnrolledCourseDataWithExtraInfoAndOptions): Promise<void>; | ||||
|     prefetch?(course: CoreCourseAnyCourseData): Promise<void>; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | ||||
| @ -109,7 +109,6 @@ export class CoreCourseProvider { | ||||
|      * | ||||
|      * @param courseId Course ID. | ||||
|      * @param completion Completion status of the module. | ||||
|      * @todo Add completion type. | ||||
|      */ | ||||
|     checkModuleCompletion(courseId: number, completion: CoreCourseModuleCompletionDataFormatted): void { | ||||
|         if (completion && completion.tracking === 2 && completion.state === 0) { | ||||
| @ -830,7 +829,7 @@ export class CoreCourseProvider { | ||||
|      * @return Promise resolved when loaded. | ||||
|      */ | ||||
|     async loadModuleContents( | ||||
|         module: CoreCourseModuleData & CoreCourseModuleBasicInfo, | ||||
|         module: CoreCourseModuleData, | ||||
|         courseId?: number, | ||||
|         sectionId?: number, | ||||
|         preferCache?: boolean, | ||||
| @ -1412,14 +1411,13 @@ export type CoreCourseModuleContentFile = { | ||||
|     filename: string; // Filename.
 | ||||
|     filepath: string; // Filepath.
 | ||||
|     filesize: number; // Filesize.
 | ||||
|     fileurl?: string; // Downloadable file url.
 | ||||
|     url?: string; // @deprecated. Use fileurl instead.
 | ||||
|     fileurl: string; // Downloadable file url.
 | ||||
|     content?: string; // Raw content, will be used when type is content.
 | ||||
|     timecreated: number; // Time created.
 | ||||
|     timemodified: number; // Time modified.
 | ||||
|     sortorder: number; // Content sort order.
 | ||||
|     mimetype?: string; // File mime type.
 | ||||
|     isexternalfile?: boolean; // Whether is an external file.
 | ||||
|     isexternalfile?: number; // Whether is an external file.
 | ||||
|     repositorytype?: string; // The repository type for external files.
 | ||||
|     userid: number; // User who added this content to moodle.
 | ||||
|     author: string; // Content owner.
 | ||||
|  | ||||
| @ -0,0 +1,46 @@ | ||||
| // (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 { CoreSiteSchema } from '@services/sites'; | ||||
| 
 | ||||
| /** | ||||
|  * Database variables for CoreCourseModulePrefetchDelegate service. | ||||
|  */ | ||||
| export const CHECK_UPDATES_TIMES_TABLE = 'check_updates_times'; | ||||
| export const SITE_SCHEMA: CoreSiteSchema = { | ||||
|     name: 'CoreCourseModulePrefetchDelegate', | ||||
|     version: 1, | ||||
|     tables: [ | ||||
|         { | ||||
|             name: CHECK_UPDATES_TIMES_TABLE, | ||||
|             columns: [ | ||||
|                 { | ||||
|                     name: 'courseId', | ||||
|                     type: 'INTEGER', | ||||
|                     primaryKey: true, | ||||
|                 }, | ||||
|                 { | ||||
|                     name: 'time', | ||||
|                     type: 'INTEGER', | ||||
|                     notNull: true, | ||||
|                 }, | ||||
|             ], | ||||
|         }, | ||||
|     ], | ||||
| }; | ||||
| 
 | ||||
| export type CoreCourseCheckUpdatesDBRecord = { | ||||
|     courseId: number; | ||||
|     time: number; | ||||
| }; | ||||
							
								
								
									
										1594
									
								
								src/core/features/course/services/module-prefetch-delegate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1594
									
								
								src/core/features/course/services/module-prefetch-delegate.ts
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -26,6 +26,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; | ||||
| import { CoreCourseHelper } from '@features/course/services/course-helper'; | ||||
| import { CoreBlockCourseBlocksComponent } from '@features/block/components/course-blocks/course-blocks'; | ||||
| import { CoreCourseModuleDelegate, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays site home index. | ||||
| @ -59,7 +60,6 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { | ||||
|     constructor( | ||||
|         protected route: ActivatedRoute, | ||||
|         protected navCtrl: NavController, | ||||
|         // @todo private prefetchDelegate: CoreCourseModulePrefetchDelegate,
 | ||||
|     ) {} | ||||
| 
 | ||||
|     /** | ||||
| @ -86,8 +86,8 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|         const module = navParams['module']; | ||||
|         if (module) { | ||||
|             // @todo const modParams = navParams.get('modParams');
 | ||||
|             // CoreCourseHelper.instance.openModule(module, this.siteHomeId, undefined, modParams);
 | ||||
|             const modParams = navParams['modParams']; | ||||
|             CoreCourseHelper.instance.openModule(module, this.siteHomeId, undefined, modParams); | ||||
|         } | ||||
| 
 | ||||
|         this.loadContent().finally(() => { | ||||
| @ -174,7 +174,7 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { | ||||
| 
 | ||||
|         if (this.section && this.section.modules) { | ||||
|             // Invalidate modules prefetch data.
 | ||||
|             //  @todo promises.push(this.prefetchDelegate.invalidateModules(this.section.modules, this.siteHomeId));
 | ||||
|             promises.push(CoreCourseModulePrefetchDelegate.instance.invalidateModules(this.section.modules, this.siteHomeId)); | ||||
|         } | ||||
| 
 | ||||
|         if (this.courseBlocksComponent) { | ||||
|  | ||||
| @ -160,9 +160,18 @@ export class CoreFileHelperProvider { | ||||
|                 onProgress({ calculating: true }); | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 await CoreFilepool.instance.shouldDownloadBeforeOpen(fixedUrl, file.filesize || 0); | ||||
|             } catch (error) { | ||||
|             const shouldDownloadFirst = await CoreFilepool.instance.shouldDownloadFileBeforeOpen(fixedUrl, file.filesize || 0); | ||||
|             if (shouldDownloadFirst) { | ||||
|                 // Download the file first.
 | ||||
|                 if (state == CoreConstants.DOWNLOADING) { | ||||
|                     // It's already downloading, stop.
 | ||||
|                     return fixedUrl; | ||||
|                 } | ||||
| 
 | ||||
|                 // Download and then return the local URL.
 | ||||
|                 return this.downloadFile(fileUrl, component, componentId, timemodified, onProgress, file, siteId); | ||||
|             } | ||||
| 
 | ||||
|             // Start the download if in wifi, but return the URL right away so the file is opened.
 | ||||
|             if (isWifi) { | ||||
|                 this.downloadFile(fileUrl, component, componentId, timemodified, onProgress, file, siteId); | ||||
| @ -185,16 +194,6 @@ export class CoreFileHelperProvider { | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|             // Download the file first.
 | ||||
|             if (state == CoreConstants.DOWNLOADING) { | ||||
|                 // It's already downloading, stop.
 | ||||
|                 return fixedUrl; | ||||
|             } | ||||
| 
 | ||||
|             // Download and then return the local URL.
 | ||||
|             return this.downloadFile(fileUrl, component, componentId, timemodified, onProgress, file, siteId); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -2763,13 +2763,7 @@ export class CoreFilepoolProvider { | ||||
|      * @param url File online URL. | ||||
|      * @param size File size. | ||||
|      * @return Promise resolved if should download before open, rejected otherwise. | ||||
|      * @description | ||||
|      * Convenience function to check if a file should be downloaded before opening it. | ||||
|      * | ||||
|      * The default behaviour in the app is to download first and then open the local file in the following cases: | ||||
|      *     - The file is small (less than DOWNLOAD_THRESHOLD). | ||||
|      *     - The file cannot be streamed. | ||||
|      * If the file is big and can be streamed, the promise returned by this function will be rejected. | ||||
|      * @ddeprecated since 3.9.5. Please use shouldDownloadFileBeforeOpen instead. | ||||
|      */ | ||||
|     async shouldDownloadBeforeOpen(url: string, size: number): Promise<void> { | ||||
|         if (size >= 0 && size <= CoreFilepoolProvider.DOWNLOAD_THRESHOLD) { | ||||
| @ -2784,6 +2778,32 @@ export class CoreFilepoolProvider { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Convenience function to check if a file should be downloaded before opening it. | ||||
|      * | ||||
|      * @param url File online URL. | ||||
|      * @param size File size. | ||||
|      * @return Promise resolved with boolean: whether file should be downloaded before opening it. | ||||
|      * @description | ||||
|      * Convenience function to check if a file should be downloaded before opening it. | ||||
|      * | ||||
|      * The default behaviour in the app is to download first and then open the local file in the following cases: | ||||
|      *     - The file is small (less than DOWNLOAD_THRESHOLD). | ||||
|      *     - The file cannot be streamed. | ||||
|      * If the file is big and can be streamed, the promise returned by this function will be rejected. | ||||
|      */ | ||||
|     async shouldDownloadFileBeforeOpen(url: string, size: number): Promise<boolean> { | ||||
|         if (size >= 0 && size <= CoreFilepoolProvider.DOWNLOAD_THRESHOLD) { | ||||
|             // The file is small, download it.
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         const mimetype = await CoreUtils.instance.getMimeTypeFromUrl(url); | ||||
| 
 | ||||
|         // If the file is streaming (audio or video), return false.
 | ||||
|         return mimetype.indexOf('video') == -1 && mimetype.indexOf('audio') == -1; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Store package status. | ||||
|      * | ||||
|  | ||||
| @ -114,7 +114,7 @@ export class CoreUtilsProvider { | ||||
|      * @param result Object where to put the properties. If not defined, a new object will be created. | ||||
|      * @return The object. | ||||
|      */ | ||||
|     arrayToObject<T extends Record<string, unknown> | string>( | ||||
|     arrayToObject<T>( | ||||
|         array: T[], | ||||
|         propertyName?: string, | ||||
|         result: Record<string, T> = {}, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user