MOBILE-3833 course: Display data ASAP in course downloads

main
Dani Palou 2022-03-24 17:29:58 +01:00
parent 9c2116c33b
commit 1a07331396
4 changed files with 49 additions and 29 deletions

View File

@ -1453,6 +1453,7 @@
"core.block.tour_navigation_dashboard_content": "tool_usertours",
"core.block.tour_navigation_dashboard_title": "tool_usertours",
"core.browser": "local_moodlemobileapp",
"core.calculating": "local_moodlemobileapp",
"core.cancel": "moodle",
"core.cannotconnect": "local_moodlemobileapp",
"core.cannotconnecttrouble": "local_moodlemobileapp",
@ -1673,6 +1674,7 @@
"core.editor.underline": "atto_underline/pluginname",
"core.editor.unorderedlist": "atto_unorderedlist/pluginname",
"core.emptysplit": "local_moodlemobileapp",
"core.endonesteptour": "tool_usertours",
"core.error": "moodle",
"core.errorchangecompletion": "local_moodlemobileapp",
"core.errordeletefile": "local_moodlemobileapp",
@ -2342,7 +2344,6 @@
"core.usernotfullysetup": "error",
"core.users": "moodle",
"core.usersuspended": "tool_reportbuilder",
"core.endonesteptour": "tool_usertours",
"core.view": "moodle",
"core.viewcode": "local_moodlemobileapp",
"core.vieweditor": "local_moodlemobileapp",

View File

@ -24,15 +24,18 @@
<ion-label>
<p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totaldownloads' | translate }}</p>
</ion-label>
<ion-badge color="light" slot="end">{{ totalSize | coreBytesToSize }}
<ion-badge color="light" slot="end">
<ng-container *ngIf="sizeLoaded">{{ totalSize | coreBytesToSize }}</ng-container>
<ng-container *ngIf="!sizeLoaded">{{ 'core.calculating' | translate }}</ng-container>
</ion-badge>
</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"
[disabled]="prefetchCourseData.loading">
<ion-icon *ngIf="!prefetchCourseData.loading" [name]="prefetchCourseData.icon" slot="start"></ion-icon>
<ion-spinner *ngIf="prefetchCourseData.loading" slot="start"></ion-spinner>
{{ prefetchCourseData.statusTranslatable | translate }}
</ion-button>
<ion-button *ngIf="totalSize > 0" (click)="deleteForCourse()" expand="block" color="danger"
<ion-button *ngIf="sizeLoaded && totalSize > 0" (click)="deleteForCourse()" expand="block" color="danger"
class="ion-no-margin ion-margin-top">
<ion-icon name="fas-trash" slot="start" [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate:
{ name: title }">
@ -52,18 +55,21 @@
</core-format-text>
</p>
<ion-badge [color]="section.downloadStatus == statusDownloaded ? 'success' : 'light'"
*ngIf="section.totalSize > 0">
*ngIf="section.sizeLoaded && section.totalSize > 0">
<ion-icon name="fam-cloud-done" *ngIf="section.downloadStatus == statusDownloaded"
[attr.aria-label]="'core.downloaded' | translate">
</ion-icon>{{ section.totalSize | coreBytesToSize }}
</ion-badge>
<ion-badge color="light" *ngIf="!section.sizeLoaded">
{{ 'core.calculating' | translate }}
</ion-badge>
<!-- Download progress. -->
<p *ngIf="downloadEnabled && section.isDownloading">
<core-progress-bar [progress]="section.total == 0 ? -1 : section.count / section.total">
</core-progress-bar>
</p>
</ion-label>
<div class="storage-buttons" slot="end" *ngIf="section.totalSize > 0 || downloadEnabled">
<div class="storage-buttons" slot="end" *ngIf="(section.sizeLoaded && section.totalSize > 0) || downloadEnabled">
<div *ngIf="downloadEnabled" slot="end" class="core-button-spinner">
<core-download-refresh *ngIf="!section.isDownloading && section.downloadStatus != statusDownloaded"
[status]="section.downloadStatus" [enabled]="true" (action)="prefecthSection(section)"
@ -77,7 +83,8 @@
{{section.count}} / {{section.total}}
</ion-badge>
</div>
<ion-button (click)="deleteForSection(section)" *ngIf="section.totalSize > 0" color="danger" fill="clear">
<ion-button (click)="deleteForSection(section)" *ngIf="section.sizeLoaded && section.totalSize > 0"
color="danger" fill="clear">
<ion-icon name="fas-trash" slot="icon-only"
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: section.name }">
</ion-icon>
@ -87,7 +94,8 @@
</ion-card-header>
<ion-card-content>
<ng-container *ngFor="let module of section.modules">
<ion-item class="ion-no-padding core-course-storage-activity" *ngIf="downloadEnabled || module.totalSize > 0">
<ion-item class="ion-no-padding core-course-storage-activity"
*ngIf="downloadEnabled || (module.sizeLoaded && module.totalSize > 0)">
<core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon"
[modname]="module.modname" [componentId]="module.instance">
</core-mod-icon>
@ -98,11 +106,14 @@
</core-format-text>
</h3>
<ion-badge [color]="module.downloadStatus == statusDownloaded ? 'success' : 'light'"
*ngIf="module.totalSize > 0">
*ngIf="module.sizeLoaded && module.totalSize > 0">
<ion-icon name="fam-cloud-done" *ngIf="module.downloadStatus == statusDownloaded"
[attr.aria-label]="'core.downloaded' | translate">
</ion-icon>{{ module.totalSize | coreBytesToSize }}
</ion-badge>
<ion-badge color="light" *ngIf="!module.sizeLoaded">
{{ 'core.calculating' | translate }}
</ion-badge>
</ion-label>
<div class="storage-buttons" slot="end">
@ -111,8 +122,8 @@
[canTrustDownload]="true" [loading]="module.spinner || module.handlerData.spinner"
(action)="prefetchModule(module, section)">
</core-download-refresh>
<ion-button fill="clear" (click)="deleteForModule(module, section)" *ngIf="module.totalSize > 0"
color="danger">
<ion-button fill="clear" (click)="deleteForModule(module, section)"
*ngIf="module.sizeLoaded && module.totalSize > 0" color="danger">
<ion-icon name="fas-trash" slot="icon-only"
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: module.name }">
</ion-icon>

View File

@ -48,6 +48,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
loaded = false;
sections: AddonStorageManagerCourseSection[] = [];
totalSize = 0;
sizeLoaded = false;
downloadEnabled = false;
downloadCourseEnabled = false;
@ -107,13 +108,13 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
this.sections = (await CoreCourseHelper.addHandlerDataForModules(sections, this.courseId)).sections
.map((section) => ({ ...section, totalSize: 0 }));
this.loaded = true;
await Promise.all([
this.loadSizes(),
this.initCoursePrefetch(),
this.initModulePrefetch(),
]);
this.loaded = true;
}
/**
@ -241,12 +242,15 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
*/
protected async loadSizes(): Promise<void> {
this.totalSize = 0;
this.sizeLoaded = false;
const promises: Promise<void>[] = [];
this.sections.forEach((section) => {
await Promise.all(this.sections.map(async (section) => {
section.totalSize = 0;
section.modules.forEach((module) => {
section.sizeLoaded = false;
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.
// For other modules it always returns 0, even if they have downloaded some files.
@ -255,21 +259,22 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
// But these aren't necessarily consistent, for example mod_frog vs mmaModFrog.
// There is nothing enforcing correct values.
// Most modules which have large files are downloadable, so I think this is sufficient.
const promise = CoreCourseModulePrefetchDelegate.getModuleStoredSize(module, this.courseId).then((size) => {
// There are some cases where the return from this is not a valid number.
if (!isNaN(size)) {
module.totalSize = Number(size);
section.totalSize += size;
this.totalSize += size;
}
const size = await CoreCourseModulePrefetchDelegate.getModuleStoredSize(module, this.courseId);
return;
});
promises.push(promise);
});
});
// There are some cases where the return from this is not a valid number.
if (!isNaN(size)) {
module.totalSize = Number(size);
section.totalSize += size;
this.totalSize += size;
}
await Promise.all(promises);
module.sizeLoaded = true;
}));
section.sizeLoaded = true;
}));
this.sizeLoaded = true;
// Mark course as not downloaded if course size is 0.
if (this.totalSize == 0) {
@ -608,11 +613,13 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
type AddonStorageManagerCourseSection = Omit<CoreCourseSectionWithStatus, 'modules'> & {
totalSize: number;
sizeLoaded?: boolean;
modules: AddonStorageManagerModule[];
};
type AddonStorageManagerModule = CoreCourseModuleData & {
totalSize?: number;
sizeLoaded?: boolean;
prefetchHandler?: CoreCourseModulePrefetchHandler;
spinner?: boolean;
downloadStatus?: string;

View File

@ -13,6 +13,7 @@
"areyousure": "Are you sure?",
"back": "Back",
"browser": "Browser",
"calculating": "Calculating",
"cancel": "Cancel",
"cannotconnect": "Cannot connect",
"cannotconnecttrouble": "We're having trouble connecting to your site.",