forked from EVOgeek/Vmeda.Online
		
	MOBILE-3833 course: Improve performance after download or delete
This commit is contained in:
		
							parent
							
								
									1a07331396
								
							
						
					
					
						commit
						37af8e3c69
					
				| @ -25,8 +25,8 @@ | |||||||
|                         <p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totaldownloads' | translate }}</p> |                         <p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totaldownloads' | translate }}</p> | ||||||
|                     </ion-label> |                     </ion-label> | ||||||
|                     <ion-badge color="light" slot="end"> |                     <ion-badge color="light" slot="end"> | ||||||
|                         <ng-container *ngIf="sizeLoaded">{{ totalSize | coreBytesToSize }}</ng-container> |                         <ng-container *ngIf="!calculatingSize">{{ totalSize | coreBytesToSize }}</ng-container> | ||||||
|                         <ng-container *ngIf="!sizeLoaded">{{ 'core.calculating' | translate }}</ng-container> |                         <ng-container *ngIf="calculatingSize">{{ 'core.calculating' | translate }}</ng-container> | ||||||
|                     </ion-badge> |                     </ion-badge> | ||||||
|                 </ion-item> |                 </ion-item> | ||||||
|                 <ion-button *ngIf="downloadCourseEnabled" (click)="prefetchCourse()" expand="block" fill="outline" class="ion-no-margin" |                 <ion-button *ngIf="downloadCourseEnabled" (click)="prefetchCourse()" expand="block" fill="outline" class="ion-no-margin" | ||||||
| @ -35,7 +35,7 @@ | |||||||
|                     <ion-spinner *ngIf="prefetchCourseData.loading" slot="start"></ion-spinner> |                     <ion-spinner *ngIf="prefetchCourseData.loading" slot="start"></ion-spinner> | ||||||
|                     {{ prefetchCourseData.statusTranslatable | translate }} |                     {{ prefetchCourseData.statusTranslatable | translate }} | ||||||
|                 </ion-button> |                 </ion-button> | ||||||
|                 <ion-button *ngIf="sizeLoaded && totalSize > 0" (click)="deleteForCourse()" expand="block" color="danger" |                 <ion-button [disabled]="calculatingSize || totalSize <= 0" (click)="deleteForCourse()" expand="block" color="danger" | ||||||
|                     class="ion-no-margin ion-margin-top"> |                     class="ion-no-margin ion-margin-top"> | ||||||
|                     <ion-icon name="fas-trash" slot="start" [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: |                     <ion-icon name="fas-trash" slot="start" [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: | ||||||
|                         { name: title }"> |                         { name: title }"> | ||||||
| @ -55,12 +55,12 @@ | |||||||
|                                 </core-format-text> |                                 </core-format-text> | ||||||
|                             </p> |                             </p> | ||||||
|                             <ion-badge [color]="section.downloadStatus == statusDownloaded ? 'success' : 'light'" |                             <ion-badge [color]="section.downloadStatus == statusDownloaded ? 'success' : 'light'" | ||||||
|                                 *ngIf="section.sizeLoaded && section.totalSize > 0"> |                                 *ngIf="!section.calculatingSize && section.totalSize > 0"> | ||||||
|                                 <ion-icon name="fam-cloud-done" *ngIf="section.downloadStatus == statusDownloaded" |                                 <ion-icon name="fam-cloud-done" *ngIf="section.downloadStatus == statusDownloaded" | ||||||
|                                     [attr.aria-label]="'core.downloaded' | translate"> |                                     [attr.aria-label]="'core.downloaded' | translate"> | ||||||
|                                 </ion-icon>{{ section.totalSize | coreBytesToSize }} |                                 </ion-icon>{{ section.totalSize | coreBytesToSize }} | ||||||
|                             </ion-badge> |                             </ion-badge> | ||||||
|                             <ion-badge color="light" *ngIf="!section.sizeLoaded"> |                             <ion-badge color="light" *ngIf="section.calculatingSize"> | ||||||
|                                 {{ 'core.calculating' | translate }} |                                 {{ 'core.calculating' | translate }} | ||||||
|                             </ion-badge> |                             </ion-badge> | ||||||
|                             <!-- Download progress. --> |                             <!-- Download progress. --> | ||||||
| @ -69,7 +69,8 @@ | |||||||
|                                 </core-progress-bar> |                                 </core-progress-bar> | ||||||
|                             </p> |                             </p> | ||||||
|                         </ion-label> |                         </ion-label> | ||||||
|                         <div class="storage-buttons" slot="end" *ngIf="(section.sizeLoaded && section.totalSize > 0) || downloadEnabled"> |                         <div class="storage-buttons" slot="end" | ||||||
|  |                             *ngIf="(!section.calculatingSize && section.totalSize > 0) || downloadEnabled"> | ||||||
|                             <div *ngIf="downloadEnabled" slot="end" class="core-button-spinner"> |                             <div *ngIf="downloadEnabled" slot="end" class="core-button-spinner"> | ||||||
|                                 <core-download-refresh *ngIf="!section.isDownloading && section.downloadStatus != statusDownloaded" |                                 <core-download-refresh *ngIf="!section.isDownloading && section.downloadStatus != statusDownloaded" | ||||||
|                                     [status]="section.downloadStatus" [enabled]="true" (action)="prefecthSection(section)" |                                     [status]="section.downloadStatus" [enabled]="true" (action)="prefecthSection(section)" | ||||||
| @ -83,7 +84,7 @@ | |||||||
|                                     {{section.count}} / {{section.total}} |                                     {{section.count}} / {{section.total}} | ||||||
|                                 </ion-badge> |                                 </ion-badge> | ||||||
|                             </div> |                             </div> | ||||||
|                             <ion-button (click)="deleteForSection(section)" *ngIf="section.sizeLoaded && section.totalSize > 0" |                             <ion-button (click)="deleteForSection(section)" *ngIf="!section.calculatingSize && section.totalSize > 0" | ||||||
|                                 color="danger" fill="clear"> |                                 color="danger" fill="clear"> | ||||||
|                                 <ion-icon name="fas-trash" slot="icon-only" |                                 <ion-icon name="fas-trash" slot="icon-only" | ||||||
|                                     [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: section.name }"> |                                     [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: section.name }"> | ||||||
| @ -95,7 +96,7 @@ | |||||||
|                 <ion-card-content> |                 <ion-card-content> | ||||||
|                     <ng-container *ngFor="let module of section.modules"> |                     <ng-container *ngFor="let module of section.modules"> | ||||||
|                         <ion-item class="ion-no-padding core-course-storage-activity" |                         <ion-item class="ion-no-padding core-course-storage-activity" | ||||||
|                             *ngIf="downloadEnabled || (module.sizeLoaded && module.totalSize > 0)"> |                             *ngIf="downloadEnabled || (!module.calculatingSize && module.totalSize > 0)"> | ||||||
|                             <core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" |                             <core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" | ||||||
|                                 [modname]="module.modname" [componentId]="module.instance"> |                                 [modname]="module.modname" [componentId]="module.instance"> | ||||||
|                             </core-mod-icon> |                             </core-mod-icon> | ||||||
| @ -106,12 +107,12 @@ | |||||||
|                                     </core-format-text> |                                     </core-format-text> | ||||||
|                                 </h3> |                                 </h3> | ||||||
|                                 <ion-badge [color]="module.downloadStatus == statusDownloaded ? 'success' : 'light'" |                                 <ion-badge [color]="module.downloadStatus == statusDownloaded ? 'success' : 'light'" | ||||||
|                                     *ngIf="module.sizeLoaded && module.totalSize > 0"> |                                     *ngIf="!module.calculatingSize && module.totalSize > 0"> | ||||||
|                                     <ion-icon name="fam-cloud-done" *ngIf="module.downloadStatus == statusDownloaded" |                                     <ion-icon name="fam-cloud-done" *ngIf="module.downloadStatus == statusDownloaded" | ||||||
|                                         [attr.aria-label]="'core.downloaded' | translate"> |                                         [attr.aria-label]="'core.downloaded' | translate"> | ||||||
|                                     </ion-icon>{{ module.totalSize | coreBytesToSize }} |                                     </ion-icon>{{ module.totalSize | coreBytesToSize }} | ||||||
|                                 </ion-badge> |                                 </ion-badge> | ||||||
|                                 <ion-badge color="light" *ngIf="!module.sizeLoaded"> |                                 <ion-badge color="light" *ngIf="module.calculatingSize"> | ||||||
|                                     {{ 'core.calculating' | translate }} |                                     {{ 'core.calculating' | translate }} | ||||||
|                                 </ion-badge> |                                 </ion-badge> | ||||||
|                             </ion-label> |                             </ion-label> | ||||||
| @ -123,7 +124,7 @@ | |||||||
|                                     (action)="prefetchModule(module, section)"> |                                     (action)="prefetchModule(module, section)"> | ||||||
|                                 </core-download-refresh> |                                 </core-download-refresh> | ||||||
|                                 <ion-button fill="clear" (click)="deleteForModule(module, section)" |                                 <ion-button fill="clear" (click)="deleteForModule(module, section)" | ||||||
|                                     *ngIf="module.sizeLoaded && module.totalSize > 0" color="danger"> |                                     *ngIf="!module.calculatingSize && module.totalSize > 0" color="danger"> | ||||||
|                                     <ion-icon name="fas-trash" slot="icon-only" |                                     <ion-icon name="fas-trash" slot="icon-only" | ||||||
|                                         [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: module.name }"> |                                         [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: module.name }"> | ||||||
|                                     </ion-icon> |                                     </ion-icon> | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|     loaded = false; |     loaded = false; | ||||||
|     sections: AddonStorageManagerCourseSection[] = []; |     sections: AddonStorageManagerCourseSection[] = []; | ||||||
|     totalSize = 0; |     totalSize = 0; | ||||||
|     sizeLoaded = false; |     calculatingSize = true; | ||||||
| 
 | 
 | ||||||
|     downloadEnabled = false; |     downloadEnabled = false; | ||||||
|     downloadCourseEnabled = false; |     downloadCourseEnabled = false; | ||||||
| @ -106,12 +106,20 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
|         const sections = await CoreCourse.getSections(this.courseId, false, true); |         const sections = await CoreCourse.getSections(this.courseId, false, true); | ||||||
|         this.sections = (await CoreCourseHelper.addHandlerDataForModules(sections, this.courseId)).sections |         this.sections = (await CoreCourseHelper.addHandlerDataForModules(sections, this.courseId)).sections | ||||||
|             .map((section) => ({ ...section, totalSize: 0 })); |             .map(section => ({ | ||||||
|  |                 ...section, | ||||||
|  |                 totalSize: 0, | ||||||
|  |                 calculatingSize: true, | ||||||
|  |                 modules: section.modules.map(module => ({ | ||||||
|  |                     ...module, | ||||||
|  |                     calculatingSize: true, | ||||||
|  |                 })), | ||||||
|  |             })); | ||||||
| 
 | 
 | ||||||
|         this.loaded = true; |         this.loaded = true; | ||||||
| 
 | 
 | ||||||
|         await Promise.all([ |         await Promise.all([ | ||||||
|             this.loadSizes(), |             this.initSizes(), | ||||||
|             this.initCoursePrefetch(), |             this.initCoursePrefetch(), | ||||||
|             this.initModulePrefetch(), |             this.initModulePrefetch(), | ||||||
|         ]); |         ]); | ||||||
| @ -240,18 +248,9 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|     /** |     /** | ||||||
|      * Init section, course and modules sizes. |      * Init section, course and modules sizes. | ||||||
|      */ |      */ | ||||||
|     protected async loadSizes(): Promise<void> { |     protected async initSizes(): Promise<void> { | ||||||
|         this.totalSize = 0; |  | ||||||
|         this.sizeLoaded = false; |  | ||||||
| 
 |  | ||||||
|         await Promise.all(this.sections.map(async (section) => { |         await Promise.all(this.sections.map(async (section) => { | ||||||
|             section.totalSize = 0; |  | ||||||
|             section.sizeLoaded = false; |  | ||||||
| 
 |  | ||||||
|             await Promise.all(section.modules.map(async (module) => { |             await Promise.all(section.modules.map(async (module) => { | ||||||
|                 module.totalSize = 0; |  | ||||||
|                 module.sizeLoaded = false; |  | ||||||
| 
 |  | ||||||
|                 // Note: This function only gets the size for modules which are downloadable.
 |                 // Note: This function only gets the size for modules which are downloadable.
 | ||||||
|                 // For other modules it always returns 0, even if they have downloaded some files.
 |                 // For other modules it always returns 0, even if they have downloaded some files.
 | ||||||
|                 // However there is no 100% reliable way to actually track the files in this case.
 |                 // However there is no 100% reliable way to actually track the files in this case.
 | ||||||
| @ -268,13 +267,13 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|                     this.totalSize += size; |                     this.totalSize += size; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 module.sizeLoaded = true; |                 module.calculatingSize = false; | ||||||
|             })); |             })); | ||||||
| 
 | 
 | ||||||
|             section.sizeLoaded = true; |             section.calculatingSize = false; | ||||||
|         })); |         })); | ||||||
| 
 | 
 | ||||||
|         this.sizeLoaded = true; |         this.calculatingSize = false; | ||||||
| 
 | 
 | ||||||
|         // Mark course as not downloaded if course size is 0.
 |         // Mark course as not downloaded if course size is 0.
 | ||||||
|         if (this.totalSize == 0) { |         if (this.totalSize == 0) { | ||||||
| @ -282,6 +281,56 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Update the sizes of some modules. | ||||||
|  |      * | ||||||
|  |      * @param modules Modules. | ||||||
|  |      * @param section Section the modules belong to. | ||||||
|  |      * @return Promise resolved when done. | ||||||
|  |      */ | ||||||
|  |     protected async updateModulesSizes( | ||||||
|  |         modules: AddonStorageManagerModule[], | ||||||
|  |         section?: AddonStorageManagerCourseSection, | ||||||
|  |     ): Promise<void> { | ||||||
|  |         this.calculatingSize = true; | ||||||
|  | 
 | ||||||
|  |         await Promise.all(modules.map(async (module) => { | ||||||
|  |             if (module.calculatingSize) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             module.calculatingSize = true; | ||||||
|  | 
 | ||||||
|  |             if (!section) { | ||||||
|  |                 section = this.sections.find((section) => section.modules.some((mod) => mod.id === module.id)); | ||||||
|  |                 if (section) { | ||||||
|  |                     section.calculatingSize = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             try { | ||||||
|  |                 const size = await CoreCourseModulePrefetchDelegate.getModuleStoredSize(module, this.courseId); | ||||||
|  | 
 | ||||||
|  |                 const diff = (isNaN(size) ? 0 : size) - (module.totalSize ?? 0); | ||||||
|  | 
 | ||||||
|  |                 module.totalSize = Number(size); | ||||||
|  |                 this.totalSize += diff; | ||||||
|  |                 if (section) { | ||||||
|  |                     section.totalSize += diff; | ||||||
|  |                 } | ||||||
|  |             } catch { | ||||||
|  |                 // Ignore errors, it shouldn't happen.
 | ||||||
|  |             } finally { | ||||||
|  |                 module.calculatingSize = false; | ||||||
|  |             } | ||||||
|  |         })); | ||||||
|  | 
 | ||||||
|  |         this.calculatingSize = false; | ||||||
|  |         if (section) { | ||||||
|  |             section.calculatingSize = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * The user has requested a delete for the whole course data. |      * The user has requested a delete for the whole course data. | ||||||
|      * |      * | ||||||
| @ -406,7 +455,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|         } finally { |         } finally { | ||||||
|             modal.dismiss(); |             modal.dismiss(); | ||||||
| 
 | 
 | ||||||
|             await this.loadSizes(); |             await this.updateModulesSizes(modules, section); | ||||||
|             CoreCourseHelper.calculateSectionsStatus(this.sections, this.courseId, false, false); |             CoreCourseHelper.calculateSectionsStatus(this.sections, this.courseId, false, false); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -455,7 +504,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|                     CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingsection', true); |                     CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingsection', true); | ||||||
|                 } |                 } | ||||||
|             } finally { |             } finally { | ||||||
|                 await this.loadSizes(); |                 await this.updateModulesSizes(section.modules, section); | ||||||
|             } |             } | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             // User cancelled or there was an error calculating the size.
 |             // User cancelled or there was an error calculating the size.
 | ||||||
| @ -501,7 +550,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
|         } finally { |         } finally { | ||||||
|             module.spinner = false; |             module.spinner = false; | ||||||
| 
 | 
 | ||||||
|             await this.loadSizes(); |             await this.updateModulesSizes([module]); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -613,13 +662,13 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { | |||||||
| 
 | 
 | ||||||
| type AddonStorageManagerCourseSection = Omit<CoreCourseSectionWithStatus, 'modules'> & { | type AddonStorageManagerCourseSection = Omit<CoreCourseSectionWithStatus, 'modules'> & { | ||||||
|     totalSize: number; |     totalSize: number; | ||||||
|     sizeLoaded?: boolean; |     calculatingSize: boolean; | ||||||
|     modules: AddonStorageManagerModule[]; |     modules: AddonStorageManagerModule[]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| type AddonStorageManagerModule = CoreCourseModuleData & { | type AddonStorageManagerModule = CoreCourseModuleData & { | ||||||
|     totalSize?: number; |     totalSize?: number; | ||||||
|     sizeLoaded?: boolean; |     calculatingSize: boolean; | ||||||
|     prefetchHandler?: CoreCourseModulePrefetchHandler; |     prefetchHandler?: CoreCourseModulePrefetchHandler; | ||||||
|     spinner?: boolean; |     spinner?: boolean; | ||||||
|     downloadStatus?: string; |     downloadStatus?: string; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user