commit
cb5508fc72
|
@ -1104,13 +1104,17 @@
|
||||||
"addon.report_insights.notapplicable": "analytics",
|
"addon.report_insights.notapplicable": "analytics",
|
||||||
"addon.report_insights.notuseful": "analytics",
|
"addon.report_insights.notuseful": "analytics",
|
||||||
"addon.report_insights.useful": "analytics",
|
"addon.report_insights.useful": "analytics",
|
||||||
|
"addon.storagemanager.coursedownloads": "local_moodlemobileapp",
|
||||||
|
"addon.storagemanager.courseinfo": "local_moodlemobileapp",
|
||||||
|
"addon.storagemanager.coursesspaceusage": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.deletecourse": "local_moodlemobileapp",
|
"addon.storagemanager.deletecourse": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.deletecourses": "local_moodlemobileapp",
|
"addon.storagemanager.deletecourses": "local_moodlemobileapp",
|
||||||
|
"addon.storagemanager.deletedata": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.deletedatafrom": "local_moodlemobileapp",
|
"addon.storagemanager.deletedatafrom": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.info": "local_moodlemobileapp",
|
"addon.storagemanager.downloadedcourses": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.managecoursestorage": "local_moodlemobileapp",
|
"addon.storagemanager.managedownloads": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.managestorage": "local_moodlemobileapp",
|
"addon.storagemanager.totaldownloads": "local_moodlemobileapp",
|
||||||
"addon.storagemanager.storageused": "local_moodlemobileapp",
|
"addon.storagemanager.totalspaceusage": "local_moodlemobileapp",
|
||||||
"assets.countries.AD": "countries",
|
"assets.countries.AD": "countries",
|
||||||
"assets.countries.AE": "countries",
|
"assets.countries.AE": "countries",
|
||||||
"assets.countries.AF": "countries",
|
"assets.countries.AF": "countries",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div slot="end" class="flex-row">
|
<div slot="end" class="flex-row">
|
||||||
<!-- Download all courses. -->
|
<!-- Download all courses. -->
|
||||||
<div *ngIf="downloadCoursesEnabled && downloadEnabled && filteredCourses.length > 1" class="core-button-spinner">
|
<div *ngIf="downloadCoursesEnabled && filteredCourses.length > 1" class="core-button-spinner">
|
||||||
<ion-button *ngIf="!prefetchCoursesData.loading" fill="clear" color="dark" (click)="prefetchCourses()"
|
<ion-button *ngIf="!prefetchCoursesData.loading" fill="clear" color="dark" (click)="prefetchCourses()"
|
||||||
[attr.aria-label]="prefetchCoursesData.statusTranslatable | translate">
|
[attr.aria-label]="prefetchCoursesData.statusTranslatable | translate">
|
||||||
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true">
|
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true">
|
||||||
|
@ -77,8 +77,8 @@
|
||||||
<ion-row class="ion-no-padding">
|
<ion-row class="ion-no-padding">
|
||||||
<ion-col *ngFor="let course of filteredCourses" class="ion-no-padding" size="12" size-sm="6" size-md="6" size-lg="4"
|
<ion-col *ngFor="let course of filteredCourses" class="ion-no-padding" size="12" size-sm="6" size-md="6" size-lg="4"
|
||||||
size-xl="3">
|
size-xl="3">
|
||||||
<core-courses-course-list-item [course]="course" class="core-courseoverview"
|
<core-courses-course-list-item [course]="course" class="core-courseoverview" [showDownload]="downloadCourseEnabled"
|
||||||
[showDownload]="downloadCourseEnabled && downloadEnabled" [layout]="layouts.selected">
|
[layout]="layouts.selected">
|
||||||
</core-courses-course-list-item>
|
</core-courses-course-list-item>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit, Input, OnDestroy, OnChanges, SimpleChange } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { ModalOptions } from '@ionic/core';
|
import { ModalOptions } from '@ionic/core';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreTimeUtils } from '@services/utils/time';
|
import { CoreTimeUtils } from '@services/utils/time';
|
||||||
|
@ -40,9 +40,7 @@ const FILTER_PRIORITY: AddonBlockMyOverviewTimeFilters[] = ['all', 'inprogress',
|
||||||
selector: 'addon-block-myoverview',
|
selector: 'addon-block-myoverview',
|
||||||
templateUrl: 'addon-block-myoverview.html',
|
templateUrl: 'addon-block-myoverview.html',
|
||||||
})
|
})
|
||||||
export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implements OnInit, OnChanges, OnDestroy {
|
export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input() downloadEnabled = false;
|
|
||||||
|
|
||||||
filteredCourses: CoreEnrolledCourseDataWithOptions[] = [];
|
filteredCourses: CoreEnrolledCourseDataWithOptions[] = [];
|
||||||
|
|
||||||
|
@ -197,16 +195,6 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
ngOnChanges(changes: {[name: string]: SimpleChange}): void {
|
|
||||||
if (changes.downloadEnabled && !changes.downloadEnabled.previousValue && this.downloadEnabled && this.loaded) {
|
|
||||||
// Download all courses is enabled now, initialize it.
|
|
||||||
this.initPrefetchCoursesIcons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
|
@ -431,7 +419,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
async initPrefetchCoursesIcons(): Promise<void> {
|
async initPrefetchCoursesIcons(): Promise<void> {
|
||||||
if (this.prefetchIconsInitialized || !this.downloadEnabled) {
|
if (this.prefetchIconsInitialized) {
|
||||||
// Already initialized.
|
// Already initialized.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
<div (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
|
<div (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
|
||||||
<div class="safe-area-pseudo-padding-start"></div>
|
<div class="safe-area-pseudo-padding-start"></div>
|
||||||
<ng-container *ngFor="let course of courses">
|
<ng-container *ngFor="let course of courses">
|
||||||
<core-courses-course-list-item [course]="course" class="core-recentlyaccessedcourses" layout="summarycard"
|
<core-courses-course-list-item [course]="course" class="core-recentlyaccessedcourses" layout="summarycard">
|
||||||
[showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-list-item>
|
</core-courses-course-list-item>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<div class="safe-area-pseudo-padding-end"></div>
|
<div class="safe-area-pseudo-padding-end"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import {
|
import {
|
||||||
|
@ -41,17 +41,13 @@ import { CoreSite } from '@classes/site';
|
||||||
})
|
})
|
||||||
export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseComponent implements OnInit, OnDestroy {
|
export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input() downloadEnabled = false;
|
|
||||||
|
|
||||||
courses: AddonBlockRecentlyAccessedCourse[] = [];
|
courses: AddonBlockRecentlyAccessedCourse[] = [];
|
||||||
|
|
||||||
downloadCourseEnabled = false;
|
|
||||||
scrollElementId!: string;
|
scrollElementId!: string;
|
||||||
|
|
||||||
protected site!: CoreSite;
|
protected site!: CoreSite;
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
protected coursesObserver?: CoreEventObserver;
|
protected coursesObserver?: CoreEventObserver;
|
||||||
protected updateSiteObserver?: CoreEventObserver;
|
|
||||||
protected fetchContentDefaultError = 'Error getting recent courses data.';
|
protected fetchContentDefaultError = 'Error getting recent courses data.';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -69,15 +65,6 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
|
||||||
|
|
||||||
this.scrollElementId = `addon-block-recentlyaccessedcourses-scroll-${scrollId}`;
|
this.scrollElementId = `addon-block-recentlyaccessedcourses-scroll-${scrollId}`;
|
||||||
|
|
||||||
// Refresh the enabled flags if enabled.
|
|
||||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
|
||||||
|
|
||||||
// Refresh the enabled flags if site is updated.
|
|
||||||
this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
|
||||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
|
||||||
|
|
||||||
}, this.site.getId());
|
|
||||||
|
|
||||||
this.coursesObserver = CoreEvents.on(
|
this.coursesObserver = CoreEvents.on(
|
||||||
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
|
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
|
||||||
(data) => {
|
(data) => {
|
||||||
|
@ -208,7 +195,6 @@ export class AddonBlockRecentlyAccessedCoursesComponent extends CoreBlockBaseCom
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.isDestroyed = true;
|
this.isDestroyed = true;
|
||||||
this.coursesObserver?.off();
|
this.coursesObserver?.off();
|
||||||
this.updateSiteObserver?.off();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreCourse } from '@features/course/services/course';
|
import { CoreCourse } from '@features/course/services/course';
|
||||||
import { CoreCourseHelper, CoreCourseSection } from '@features/course/services/course-helper';
|
import { CoreCourseHelper, CoreCourseSection } from '@features/course/services/course-helper';
|
||||||
|
@ -29,8 +29,6 @@ import { CoreBlockBaseComponent } from '@features/block/classes/base-block-compo
|
||||||
})
|
})
|
||||||
export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent implements OnInit {
|
export class AddonBlockSiteMainMenuComponent extends CoreBlockBaseComponent implements OnInit {
|
||||||
|
|
||||||
@Input() downloadEnabled = false;
|
|
||||||
|
|
||||||
component = 'AddonBlockSiteMainMenu';
|
component = 'AddonBlockSiteMainMenu';
|
||||||
mainMenuBlock?: CoreCourseSection;
|
mainMenuBlock?: CoreCourseSection;
|
||||||
siteHomeId = 1;
|
siteHomeId = 1;
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
<div (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
|
<div (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
|
||||||
<div class="safe-area-pseudo-padding-start"></div>
|
<div class="safe-area-pseudo-padding-start"></div>
|
||||||
<ng-container *ngFor="let course of courses">
|
<ng-container *ngFor="let course of courses">
|
||||||
<core-courses-course-list-item [course]="course" class="core-block_starredcourses" layout="summarycard"
|
<core-courses-course-list-item [course]="course" class="core-block_starredcourses" layout="summarycard">
|
||||||
[showDownload]="downloadCourseEnabled && downloadEnabled"></core-courses-course-list-item>
|
</core-courses-course-list-item>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<div class="safe-area-pseudo-padding-end"></div>
|
<div class="safe-area-pseudo-padding-end"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, OnInit, OnDestroy, Input } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData, CoreCourses } from '@features/courses/services/courses';
|
import { CoreCoursesProvider, CoreCoursesMyCoursesUpdatedEventData, CoreCourses } from '@features/courses/services/courses';
|
||||||
|
@ -36,17 +36,13 @@ import { AddonBlockStarredCourse, AddonBlockStarredCourses } from '../../service
|
||||||
})
|
})
|
||||||
export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent implements OnInit, OnDestroy {
|
export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@Input() downloadEnabled = false;
|
|
||||||
|
|
||||||
courses: AddonBlockStarredCoursesCourse[] = [];
|
courses: AddonBlockStarredCoursesCourse[] = [];
|
||||||
|
|
||||||
downloadCourseEnabled = false;
|
|
||||||
scrollElementId!: string;
|
scrollElementId!: string;
|
||||||
|
|
||||||
protected site: CoreSite;
|
protected site: CoreSite;
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
protected coursesObserver?: CoreEventObserver;
|
protected coursesObserver?: CoreEventObserver;
|
||||||
protected updateSiteObserver?: CoreEventObserver;
|
|
||||||
protected fetchContentDefaultError = 'Error getting starred courses data.';
|
protected fetchContentDefaultError = 'Error getting starred courses data.';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -64,14 +60,6 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
|
||||||
|
|
||||||
this.scrollElementId = `addon-block-starredcourses-scroll-${scrollId}`;
|
this.scrollElementId = `addon-block-starredcourses-scroll-${scrollId}`;
|
||||||
|
|
||||||
// Refresh the enabled flags if enabled.
|
|
||||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
|
||||||
|
|
||||||
// Refresh the enabled flags if site is updated.
|
|
||||||
this.updateSiteObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
|
||||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
|
||||||
}, CoreSites.getCurrentSiteId());
|
|
||||||
|
|
||||||
this.coursesObserver = CoreEvents.on(
|
this.coursesObserver = CoreEvents.on(
|
||||||
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
|
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED,
|
||||||
(data) => {
|
(data) => {
|
||||||
|
@ -194,7 +182,6 @@ export class AddonBlockStarredCoursesComponent extends CoreBlockBaseComponent im
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.isDestroyed = true;
|
this.isDestroyed = true;
|
||||||
this.coursesObserver?.off();
|
this.coursesObserver?.off();
|
||||||
this.updateSiteObserver?.off();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
{
|
{
|
||||||
"deletecourse": "Offload all course data",
|
"deletedata": "Delete offline data",
|
||||||
"deletecourses": "Offload all courses data",
|
"deletecourse": "Delete offline data from this course",
|
||||||
"deletedatafrom": "Offload data from {{name}}",
|
"deletecourses": "Delete offline data from all courses",
|
||||||
"info": "Files stored on your device make the app work faster and enable the app to be used offline. You can safely offload files if you need to free up storage space.",
|
"deletedatafrom": "Delete offline data from {{name}}",
|
||||||
"managestorage": "Manage storage",
|
"courseinfo": "Download course content to work offline. Your activity will sync automatically when your device is back online.",
|
||||||
"managecoursestorage": "Manage course storage",
|
"managedownloads": "Manage downloads",
|
||||||
"storageused": "File storage used:"
|
"coursedownloads": "Course downloads",
|
||||||
|
"totaldownloads": "Total downloads",
|
||||||
|
"totalspaceusage": "Total space usage",
|
||||||
|
"coursesspaceusage": "Courses space usage",
|
||||||
|
"downloadedcourses": "Downloaded courses"
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
|
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>
|
<ion-title>
|
||||||
<h1>{{ 'addon.storagemanager.managecoursestorage' | translate }}</h1>
|
<h1>{{ 'addon.storagemanager.coursedownloads' | translate }}</h1>
|
||||||
</ion-title>
|
</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
@ -12,20 +12,19 @@
|
||||||
<core-loading [hideUntil]="loaded">
|
<core-loading [hideUntil]="loaded">
|
||||||
<ion-card class="wholecourse">
|
<ion-card class="wholecourse">
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
|
<p class="ion-text-wrap ion-no-margin">{{ 'addon.storagemanager.courseinfo' | translate }}</p>
|
||||||
<ion-card-title>{{ title }}</ion-card-title>
|
<ion-card-title>{{ title }}</ion-card-title>
|
||||||
<p class="ion-text-wrap">{{ 'addon.storagemanager.info' | translate }}</p>
|
|
||||||
<ion-item class="size ion-text-wrap ion-no-padding" lines="none">
|
<ion-item class="size ion-text-wrap ion-no-padding" lines="none">
|
||||||
<ion-icon name="fas-archive" slot="start" aria-hidden="true"></ion-icon>
|
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.storageused' | translate }}</p>
|
<p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totaldownloads' | translate }}</p>
|
||||||
<ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge>
|
<ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-button slot="end" (click)="deleteForCourse()" [disabled]="totalSize == 0">
|
<ion-button slot="end" (click)="deleteForCourse()" [disabled]="totalSize == 0" color="danger" fill="outline">
|
||||||
<ion-icon name="fas-trash" slot="icon-only" [attr.aria-label]="'addon.storagemanager.deletecourse' | translate">
|
<ion-icon name="fas-trash" slot="icon-only" [attr.aria-label]="'addon.storagemanager.deletecourse' | translate">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-button *ngIf="downloadCourseEnabled" (click)="prefetchCourse()" expand="block">
|
<ion-button *ngIf="downloadCourseEnabled" (click)="prefetchCourse()" expand="block" fill="outline">
|
||||||
<ion-icon *ngIf="!prefetchCourseData.loading" [name]="prefetchCourseData.icon" slot="start"></ion-icon>
|
<ion-icon *ngIf="!prefetchCourseData.loading" [name]="prefetchCourseData.icon" slot="start"></ion-icon>
|
||||||
<ion-spinner *ngIf="prefetchCourseData.loading" slot="start"></ion-spinner>
|
<ion-spinner *ngIf="prefetchCourseData.loading" slot="start"></ion-spinner>
|
||||||
{{ prefetchCourseData.statusTranslatable | translate }}
|
{{ prefetchCourseData.statusTranslatable | translate }}
|
||||||
|
@ -48,7 +47,7 @@
|
||||||
</p>
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div class="storage-buttons" slot="end" *ngIf="section.totalSize > 0 || downloadEnabled">
|
<div class="storage-buttons" slot="end" *ngIf="section.totalSize > 0 || downloadEnabled">
|
||||||
<ion-button (click)="deleteForSection(section)" *ngIf="section.totalSize > 0">
|
<ion-button (click)="deleteForSection(section)" *ngIf="section.totalSize > 0" color="danger" fill="outline">
|
||||||
<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 }">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
|
@ -87,7 +86,8 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
||||||
<div class="storage-buttons" slot="end">
|
<div class="storage-buttons" slot="end">
|
||||||
<ion-button fill="clear" (click)="deleteForModule(module, section)" *ngIf="module.totalSize > 0">
|
<ion-button fill="clear" (click)="deleteForModule(module, section)" *ngIf="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>
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {
|
||||||
import {
|
import {
|
||||||
CoreCourseModulePrefetchDelegate,
|
CoreCourseModulePrefetchDelegate,
|
||||||
CoreCourseModulePrefetchHandler } from '@features/course/services/module-prefetch-delegate';
|
CoreCourseModulePrefetchHandler } from '@features/course/services/module-prefetch-delegate';
|
||||||
import { CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
import { CoreCourses } from '@features/courses/services/courses';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
|
@ -43,7 +43,6 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
})
|
})
|
||||||
export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
|
export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
course?: CoreEnrolledCourseData;
|
|
||||||
courseId!: number;
|
courseId!: number;
|
||||||
title = '';
|
title = '';
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
@ -70,7 +69,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
|
||||||
constructor() {
|
constructor() {
|
||||||
// Refresh the enabled flags if site is updated.
|
// Refresh the enabled flags if site is updated.
|
||||||
this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
||||||
this.downloadCourseEnabled = !!this.course && !CoreCourses.isDownloadCourseDisabledInSite();
|
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||||
this.downloadEnabled = !CoreSites.getRequiredCurrentSite().isOfflineDisabled();
|
this.downloadEnabled = !CoreSites.getRequiredCurrentSite().isOfflineDisabled();
|
||||||
|
|
||||||
this.initCoursePrefetch();
|
this.initCoursePrefetch();
|
||||||
|
@ -92,15 +91,14 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.course = CoreNavigator.getRouteParam<CoreEnrolledCourseData>('course');
|
this.title = CoreNavigator.getRouteParam<string>('title') || '';
|
||||||
this.title = this.course?.displayname ?? this.course?.fullname ?? '';
|
|
||||||
if (!this.title && this.courseId == CoreSites.getCurrentSiteHomeId()) {
|
if (!this.title && this.courseId == CoreSites.getCurrentSiteHomeId()) {
|
||||||
this.title = Translate.instant('core.sitehome.sitehome');
|
this.title = Translate.instant('core.sitehome.sitehome');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isGuest = !!CoreNavigator.getRouteBooleanParam('isGuest');
|
this.isGuest = !!CoreNavigator.getRouteBooleanParam('isGuest');
|
||||||
|
|
||||||
this.downloadCourseEnabled = !!this.course && !CoreCourses.isDownloadCourseDisabledInSite();
|
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||||
this.downloadEnabled = !CoreSites.getRequiredCurrentSite().isOfflineDisabled();
|
this.downloadEnabled = !CoreSites.getRequiredCurrentSite().isOfflineDisabled();
|
||||||
|
|
||||||
const sections = await CoreCourse.getSections(this.courseId, false, true);
|
const sections = await CoreCourse.getSections(this.courseId, false, true);
|
||||||
|
@ -551,14 +549,12 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy {
|
||||||
* Prefetch the whole course.
|
* Prefetch the whole course.
|
||||||
*/
|
*/
|
||||||
async prefetchCourse(): Promise<void> {
|
async prefetchCourse(): Promise<void> {
|
||||||
if (!this.course) {
|
const course = await CoreCourses.getCourse(this.courseId);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await CoreCourseHelper.confirmAndPrefetchCourse(
|
await CoreCourseHelper.confirmAndPrefetchCourse(
|
||||||
this.prefetchCourseData,
|
this.prefetchCourseData,
|
||||||
this.course,
|
course,
|
||||||
{
|
{
|
||||||
sections: this.sections,
|
sections: this.sections,
|
||||||
isGuest: this.isGuest,
|
isGuest: this.isGuest,
|
||||||
|
|
|
@ -4,43 +4,58 @@
|
||||||
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
|
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>
|
<ion-title>
|
||||||
<h1>{{ 'addon.storagemanager.managestorage' | translate }}</h1>
|
<h1>{{ 'addon.storagemanager.managedownloads' | translate }}</h1>
|
||||||
</ion-title>
|
</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<core-loading [hideUntil]="loaded">
|
<core-loading [hideUntil]="loaded">
|
||||||
|
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-card-header>
|
<ion-item class="ion-text-wrap" *ngIf="spaceUsage">
|
||||||
<ion-card-title class="ion-text-wrap">{{ 'core.courses.courses' | translate }}</ion-card-title>
|
<ion-label>
|
||||||
<p class="ion-text-wrap">{{ 'addon.storagemanager.info' | translate }}</p>
|
<p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totalspaceusage' | translate }}</p>
|
||||||
<ion-item class="size ion-text-wrap ion-no-padding" lines="none">
|
<ion-badge color="light" *ngIf="spaceUsage.spaceUsage">{{ spaceUsage.spaceUsage | coreBytesToSize }}</ion-badge>
|
||||||
<ion-icon name="fas-archive" slot="start" aria-hidden="true"></ion-icon>
|
<p>
|
||||||
<ion-label>
|
{{ 'core.settings.spaceusagehelp' | translate }}
|
||||||
<h2 class="ion-text-wrap">{{ 'addon.storagemanager.storageused' | translate }}</h2>
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<p slot="end" class="ion-text-end">{{ totalSize | coreBytesToSize }}</p>
|
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage()"
|
||||||
<ion-button slot="end" (click)="deleteCompletelyDownloadedCourses()"
|
[hidden]="spaceUsage.spaceUsage! + spaceUsage.cacheEntries! <= 0"
|
||||||
[disabled]="completelyDownloadedCourses.length === 0">
|
[attr.aria-label]="'core.settings.deletesitefilestitle' | translate" fill="outline">
|
||||||
<ion-icon name="fas-trash" slot="icon-only" ariaLabel="{{ 'addon.storagemanager.deletecourses' | translate }}">
|
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
</ion-icon>
|
</ion-button>
|
||||||
</ion-button>
|
</ion-item>
|
||||||
</ion-item>
|
<ion-item class="size ion-text-wrap" lines="none">
|
||||||
</ion-card-header>
|
<ion-label>
|
||||||
|
<h2 class="ion-text-wrap">{{ 'addon.storagemanager.coursesspaceusage' | translate }}</h2>
|
||||||
|
<ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge>
|
||||||
|
</ion-label>
|
||||||
|
<ion-button slot="end" (click)="deleteCompletelyDownloadedCourses()" [disabled]="completelyDownloadedCourses.length === 0"
|
||||||
|
color="danger" fill="outline">
|
||||||
|
<ion-icon name="fas-trash" slot="icon-only" ariaLabel="{{ 'addon.storagemanager.deletecourses' | translate }}">
|
||||||
|
</ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
<ion-card>
|
|
||||||
|
<div class="ion-padding-horizontal ion-text-wrap" *ngIf="downloadedCourses.length">
|
||||||
|
<h2>{{ 'addon.storagemanager.downloadedcourses' | translate }}</h2>
|
||||||
|
</div>
|
||||||
|
<ion-card *ngIf="downloadedCourses.length">
|
||||||
<ion-card-content class="ion-no-padding">
|
<ion-card-content class="ion-no-padding">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item *ngFor="let course of downloadedCourses" class="course">
|
<ion-item *ngFor="let course of downloadedCourses" class="course" (click)="openCourse(course.id, course.title)" button>
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<p class="item-heading" *ngIf="course.displayname">{{ course.displayname }}</p>
|
<p class="item-heading">{{ course.title }}</p>
|
||||||
<p class="item-heading" *ngIf="!course.displayname">{{ course.fullname }}</p>
|
|
||||||
<p class="item-heading item-heading-secondary" *ngIf="course.isDownloading">
|
<p class="item-heading item-heading-secondary" *ngIf="course.isDownloading">
|
||||||
{{ 'core.downloading' | translate }}
|
{{ 'core.downloading' | translate }}
|
||||||
</p>
|
</p>
|
||||||
|
<ion-badge color="light">
|
||||||
|
{{ course.totalSize | coreBytesToSize }}
|
||||||
|
</ion-badge>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<p slot="end" class="ion-text-end">{{ course.totalSize | coreBytesToSize }}</p>
|
<ion-button slot="end" (click)="deleteCourse(course)" [disabled]="course.isDownloading" color="danger" fill="clear">
|
||||||
<ion-button slot="end" (click)="deleteCourse(course)" [disabled]="course.isDownloading">
|
|
||||||
<ion-icon name="fas-trash" slot="icon-only"
|
<ion-icon name="fas-trash" slot="icon-only"
|
||||||
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: course.displayname }">
|
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: course.displayname }">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
|
|
|
@ -18,6 +18,10 @@ import { CoreCourse, CoreCourseProvider } from '@features/course/services/course
|
||||||
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
import { CoreCourseHelper } from '@features/course/services/course-helper';
|
||||||
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
|
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
|
||||||
import { CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
import { CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
|
||||||
|
import { CoreSettingsHelper, CoreSiteSpaceUsage } from '@features/settings/services/settings-helper';
|
||||||
|
import { CoreSiteHome } from '@features/sitehome/services/sitehome';
|
||||||
|
import { CoreNavigator } from '@services/navigator';
|
||||||
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
import { CoreArray } from '@singletons/array';
|
import { CoreArray } from '@singletons/array';
|
||||||
|
@ -38,11 +42,20 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy
|
||||||
completelyDownloadedCourses: DownloadedCourse[] = [];
|
completelyDownloadedCourses: DownloadedCourse[] = [];
|
||||||
totalSize = 0;
|
totalSize = 0;
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
spaceUsage: CoreSiteSpaceUsage = {
|
||||||
|
cacheEntries: 0,
|
||||||
|
spaceUsage: 0,
|
||||||
|
};
|
||||||
|
|
||||||
courseStatusObserver?: CoreEventObserver;
|
courseStatusObserver?: CoreEventObserver;
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.siteId = CoreSites.getCurrentSiteId();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View loaded.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
this.userCourses = await CoreCourses.getUserCourses();
|
this.userCourses = await CoreCourses.getUserCourses();
|
||||||
|
@ -58,6 +71,24 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy
|
||||||
.map((course) => this.getDownloadedCourse(course)),
|
.map((course) => this.getDownloadedCourse(course)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const siteHomeEnabled = await CoreSiteHome.isAvailable(this.siteId);
|
||||||
|
if (siteHomeEnabled) {
|
||||||
|
const siteHomeId = CoreSites.getCurrentSiteHomeId();
|
||||||
|
const size = await this.calculateDownloadedCourseSize(siteHomeId);
|
||||||
|
if (size > 0) {
|
||||||
|
const status = await CoreCourse.getCourseStatus(siteHomeId);
|
||||||
|
|
||||||
|
downloadedCourses.push({
|
||||||
|
id: siteHomeId,
|
||||||
|
title: Translate.instant('core.sitehome.sitehome'),
|
||||||
|
totalSize: size,
|
||||||
|
isDownloading: status === CoreConstants.DOWNLOADING,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.spaceUsage = await CoreSettingsHelper.getSiteSpaceUsage(this.siteId);
|
||||||
|
|
||||||
this.setDownloadedCourses(downloadedCourses);
|
this.setDownloadedCourses(downloadedCourses);
|
||||||
|
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
@ -173,7 +204,8 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy
|
||||||
const status = await CoreCourse.getCourseStatus(course.id);
|
const status = await CoreCourse.getCourseStatus(course.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...course,
|
id: course.id,
|
||||||
|
title: course.displayname || course.fullname,
|
||||||
totalSize,
|
totalSize,
|
||||||
isDownloading: status === CoreConstants.DOWNLOADING,
|
isDownloading: status === CoreConstants.DOWNLOADING,
|
||||||
};
|
};
|
||||||
|
@ -198,12 +230,38 @@ export class AddonStorageManagerCoursesStoragePage implements OnInit, OnDestroy
|
||||||
return moduleSizes.reduce((totalSize, moduleSize) => totalSize + moduleSize, 0);
|
return moduleSizes.reduce((totalSize, moduleSize) => totalSize + moduleSize, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open course storage.
|
||||||
|
*
|
||||||
|
* @param courseId Course Id.
|
||||||
|
*/
|
||||||
|
openCourse(courseId: number, title: string): void {
|
||||||
|
CoreNavigator.navigateToSitePath('/storage/' + courseId, { params: { title } });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes files of a site and the tables that can be cleared.
|
||||||
|
*
|
||||||
|
* @param siteData Site object with space usage.
|
||||||
|
*/
|
||||||
|
async deleteSiteStorage(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const siteName = CoreSites.getRequiredCurrentSite().getSiteName();
|
||||||
|
|
||||||
|
this.spaceUsage = await CoreSettingsHelper.deleteSiteStorage(siteName, this.siteId);
|
||||||
|
} catch {
|
||||||
|
// Ignore cancelled confirmation modal.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Downloaded course data.
|
* Downloaded course data.
|
||||||
*/
|
*/
|
||||||
interface DownloadedCourse extends CoreEnrolledCourseData {
|
interface DownloadedCourse {
|
||||||
|
id: number;
|
||||||
|
title: string;
|
||||||
totalSize: number;
|
totalSize: number;
|
||||||
isDownloading: boolean;
|
isDownloading: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,9 +48,12 @@ export class AddonStorageManagerCourseMenuHandlerService implements CoreCourseOp
|
||||||
course: CoreCourseAnyCourseDataWithOptions,
|
course: CoreCourseAnyCourseDataWithOptions,
|
||||||
): CoreCourseOptionsMenuHandlerData {
|
): CoreCourseOptionsMenuHandlerData {
|
||||||
return {
|
return {
|
||||||
icon: 'fas-archive',
|
icon: 'cloud-download',
|
||||||
title: 'addon.storagemanager.managecoursestorage',
|
title: 'addon.storagemanager.coursedownloads',
|
||||||
page: 'storage/' + course.id,
|
page: 'storage/' + course.id,
|
||||||
|
pageParams: {
|
||||||
|
title: course.displayname ?? course.fullname,
|
||||||
|
},
|
||||||
class: 'addon-storagemanager-coursemenu-handler',
|
class: 'addon-storagemanager-coursemenu-handler',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class AddonStorageManagerSettingsHandlerService implements CoreSettingsHa
|
||||||
getDisplayData(): CoreSettingsHandlerData {
|
getDisplayData(): CoreSettingsHandlerData {
|
||||||
return {
|
return {
|
||||||
icon: 'fas-archive',
|
icon: 'fas-archive',
|
||||||
title: 'addon.storagemanager.managestorage',
|
title: 'addon.storagemanager.managedownloads',
|
||||||
page: AddonStorageManagerSettingsHandlerService.PAGE_NAME,
|
page: AddonStorageManagerSettingsHandlerService.PAGE_NAME,
|
||||||
class: 'addon-storagemanager-settings-handler',
|
class: 'addon-storagemanager-settings-handler',
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
|
*ngIf="prefetch.status == 'downloaded' || prefetch.status == 'outdated'">
|
||||||
<ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'addon.storagemanager.deletecourse' | translate }}</h2>
|
<h2>{{ 'addon.storagemanager.deletedata' | translate }}</h2>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false">
|
<ion-item button class="ion-text-wrap" (click)="action('hide')" *ngIf="!course.hidden" detail="false">
|
||||||
|
|
|
@ -2,13 +2,6 @@
|
||||||
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
||||||
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<core-context-menu>
|
|
||||||
<core-context-menu-item *ngIf="(downloadCourseEnabled || downloadCoursesEnabled)" [priority]="1000"
|
|
||||||
[content]="'core.settings.showdownloadoptions' | translate" (action)="switchDownload()" iconAction="toggle"
|
|
||||||
[(toggle)]="downloadEnabled"></core-context-menu-item>
|
|
||||||
<core-context-menu-item [priority]="500" [content]="'addon.storagemanager.managestorage' | translate"
|
|
||||||
(action)="manageCoursesStorage()" iconAction="fas-archive"></core-context-menu-item>
|
|
||||||
</core-context-menu>
|
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshDashboard($event.target)">
|
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshDashboard($event.target)">
|
||||||
|
@ -18,8 +11,7 @@
|
||||||
<core-loading [hideUntil]="loaded">
|
<core-loading [hideUntil]="loaded">
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ng-container *ngFor="let block of blocks">
|
<ng-container *ngFor="let block of blocks">
|
||||||
<core-block *ngIf="block.visible" [block]="block" contextLevel="user" [instanceId]="userId"
|
<core-block *ngIf="block.visible" [block]="block" contextLevel="user" [instanceId]="userId"></core-block>
|
||||||
[extraData]="{'downloadEnabled': downloadEnabled}"></core-block>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
import { Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
import { Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
|
|
||||||
import { CoreCourses, CoreCoursesProvider } from '../../services/courses';
|
import { CoreCourses } from '../../services/courses';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreCoursesDashboard } from '@features/courses/services/dashboard';
|
import { CoreCoursesDashboard } from '@features/courses/services/dashboard';
|
||||||
|
@ -39,7 +39,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
hasSideBlocks = false;
|
hasSideBlocks = false;
|
||||||
searchEnabled = false;
|
searchEnabled = false;
|
||||||
downloadEnabled = false;
|
|
||||||
downloadCourseEnabled = false;
|
downloadCourseEnabled = false;
|
||||||
downloadCoursesEnabled = false;
|
downloadCoursesEnabled = false;
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
@ -47,7 +46,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
|
|
||||||
protected updateSiteObserver: CoreEventObserver;
|
protected updateSiteObserver: CoreEventObserver;
|
||||||
protected downloadEnabledObserver: CoreEventObserver;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
// Refresh the enabled flags if site is updated.
|
// Refresh the enabled flags if site is updated.
|
||||||
|
@ -56,12 +54,7 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
||||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||||
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
|
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
|
||||||
|
|
||||||
this.downloadEnabled = (this.downloadCourseEnabled || this.downloadCoursesEnabled) && this.downloadEnabled;
|
|
||||||
}, CoreSites.getCurrentSiteId());
|
}, CoreSites.getCurrentSiteId());
|
||||||
|
|
||||||
this.downloadEnabledObserver = CoreEvents.on(CoreCoursesProvider.EVENT_DASHBOARD_DOWNLOAD_ENABLED_CHANGED, (data) => {
|
|
||||||
this.downloadEnabled = (this.downloadCourseEnabled || this.downloadCoursesEnabled) && data.enabled;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,9 +65,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
||||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||||
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
|
this.downloadCoursesEnabled = !CoreCourses.isDownloadCoursesDisabledInSite();
|
||||||
|
|
||||||
this.downloadEnabled =
|
|
||||||
(this.downloadCourseEnabled || this.downloadCoursesEnabled) && CoreCourses.getCourseDownloadOptionsEnabled();
|
|
||||||
|
|
||||||
this.loadContent();
|
this.loadContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,20 +143,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Switch download enabled.
|
|
||||||
*/
|
|
||||||
switchDownload(): void {
|
|
||||||
CoreCourses.setCourseDownloadOptionsEnabled(this.downloadEnabled);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open page to manage courses storage.
|
|
||||||
*/
|
|
||||||
manageCoursesStorage(): void {
|
|
||||||
CoreNavigator.navigateToSitePath('/storage');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go to search courses.
|
* Go to search courses.
|
||||||
*/
|
*/
|
||||||
|
@ -179,7 +155,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.updateSiteObserver.off();
|
this.updateSiteObserver.off();
|
||||||
this.downloadEnabledObserver.off();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,17 +13,6 @@
|
||||||
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
||||||
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<core-context-menu>
|
|
||||||
<core-context-menu-item *ngIf="downloadCoursesEnabled && myOverviewBlock && myOverviewBlock.filteredCourses.length > 1"
|
|
||||||
[priority]="1000" [content]="myOverviewBlock?.prefetchCoursesData.statusTranslatable | translate"
|
|
||||||
(action)="myOverviewBlock?.prefetchCourses()"
|
|
||||||
[iconAction]="myOverviewBlock?.prefetchCoursesData.loading ? 'spinner' : myOverviewBlock?.prefetchCoursesData.icon"
|
|
||||||
[badge]="myOverviewBlock?.prefetchCoursesData.badge"
|
|
||||||
[badgeA11yText]="myOverviewBlock?.prefetchCoursesData.badgeA11yText">
|
|
||||||
</core-context-menu-item>
|
|
||||||
<core-context-menu-item [priority]="500" [content]="'addon.storagemanager.managestorage' | translate"
|
|
||||||
(action)="manageCoursesStorage()" iconAction="fas-archive"></core-context-menu-item>
|
|
||||||
</core-context-menu>
|
|
||||||
<core-user-menu-button></core-user-menu-button>
|
<core-user-menu-button></core-user-menu-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
@ -33,12 +22,33 @@
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="loaded">
|
<core-loading [hideUntil]="loaded">
|
||||||
<div class="ion-padding-horizontal">
|
<ion-item class="ion-text-wrap divider" lines="none">
|
||||||
<h2>{{ 'core.courses.mycourses' | translate }}</h2>
|
<ion-label>
|
||||||
</div>
|
<h2>{{ 'core.courses.mycourses' | translate }}</h2>
|
||||||
|
</ion-label>
|
||||||
|
<div slot="end" class="flex-row">
|
||||||
|
<!-- Download all courses. -->
|
||||||
|
<div *ngIf="downloadCoursesEnabled && myOverviewBlock && myOverviewBlock.filteredCourses.length > 1"
|
||||||
|
class="core-button-spinner">
|
||||||
|
<ion-button *ngIf="!myOverviewBlock.prefetchCoursesData.loading" fill="clear" color="dark"
|
||||||
|
(click)="myOverviewBlock.prefetchCourses()"
|
||||||
|
[attr.aria-label]="myOverviewBlock.prefetchCoursesData.statusTranslatable | translate">
|
||||||
|
<ion-icon [name]="myOverviewBlock.prefetchCoursesData.icon" slot="icon-only" aria-hidden="true">
|
||||||
|
</ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<ion-badge class="core-course-download-courses-progress" *ngIf="myOverviewBlock.prefetchCoursesData.badge"
|
||||||
|
role="progressbar" [attr.aria-valuemax]="myOverviewBlock.prefetchCoursesData.total"
|
||||||
|
[attr.aria-valuenow]="myOverviewBlock.prefetchCoursesData.count"
|
||||||
|
[attr.aria-valuetext]="myOverviewBlock.prefetchCoursesData.badgeA11yText">
|
||||||
|
{{myOverviewBlock.prefetchCoursesData.badge}}
|
||||||
|
</ion-badge>
|
||||||
|
<ion-spinner *ngIf="myOverviewBlock.prefetchCoursesData.loading" [attr.aria-label]="'core.loading' | translate">
|
||||||
|
</ion-spinner>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ion-item>
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<core-block *ngIf="loadedBlock?.visible" [block]="loadedBlock" contextLevel="user" [instanceId]="userId"
|
<core-block *ngIf="loadedBlock?.visible" [block]="loadedBlock" contextLevel="user" [instanceId]="userId"></core-block>
|
||||||
[extraData]="{'downloadEnabled': true}"></core-block>
|
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
<core-empty-box *ngIf="!loadedBlock" icon="fas-cubes" [message]="'core.course.nocontentavailable' | translate">
|
<core-empty-box *ngIf="!loadedBlock" icon="fas-cubes" [message]="'core.course.nocontentavailable' | translate">
|
||||||
|
|
|
@ -122,13 +122,6 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Open page to manage courses storage.
|
|
||||||
*/
|
|
||||||
manageCoursesStorage(): void {
|
|
||||||
CoreNavigator.navigateToSitePath('/storage');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go to search courses.
|
* Go to search courses.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -27,28 +27,15 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
|
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-item class="ion-text-wrap" *ngIf="spaceUsage">
|
|
||||||
<ion-label>
|
|
||||||
<p class="item-heading ion-text-wrap">{{ 'core.settings.spaceusage' | translate }}</p>
|
|
||||||
<p *ngIf="spaceUsage.spaceUsage">{{ spaceUsage.spaceUsage | coreBytesToSize }}</p>
|
|
||||||
</ion-label>
|
|
||||||
<ion-button fill="clear" [attr.aria-label]="'core.info' | translate" (click)="showSpaceInfo()" slot="end">
|
|
||||||
<ion-icon name="fas-info-circle" color="info" slot="icon-only"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage()"
|
|
||||||
[hidden]="spaceUsage.spaceUsage! + spaceUsage.cacheEntries! <= 0"
|
|
||||||
[attr.aria-label]="'core.settings.deletesitefilestitle' | translate">
|
|
||||||
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
</ion-item>
|
|
||||||
<ion-item class="ion-text-wrap">
|
<ion-item class="ion-text-wrap">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<p class="item-heading">{{ 'core.settings.synchronizenow' | translate }}</p>
|
<p class="item-heading">{{ 'core.settings.synchronizenow' | translate }}</p>
|
||||||
|
<p>
|
||||||
|
{{ 'core.settings.synchronizenowhelp' | translate }}
|
||||||
|
</p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-button fill="clear" [attr.aria-label]="'core.info' | translate" (click)="showSyncInfo()" slot="end">
|
|
||||||
<ion-icon name="fas-info-circle" color="info" slot="icon-only"></ion-icon>
|
|
||||||
</ion-button>
|
|
||||||
<core-button-with-spinner [loading]="isSynchronizing()" slot="end">
|
<core-button-with-spinner [loading]="isSynchronizing()" slot="end">
|
||||||
<ion-button fill="clear" (click)="synchronize()" [attr.aria-label]="'core.settings.synchronizenow' | translate">
|
<ion-button fill="clear" (click)="synchronize()" [attr.aria-label]="'core.settings.synchronizenow' | translate">
|
||||||
<ion-icon name="fas-sync-alt" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-sync-alt" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
|
|
|
@ -18,15 +18,13 @@ import { IonRefresher } from '@ionic/angular';
|
||||||
import { CoreSettingsHandlerToDisplay } from '../../services/settings-delegate';
|
import { CoreSettingsHandlerToDisplay } from '../../services/settings-delegate';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
import { CoreSites } from '@services/sites';
|
import { CoreSites } from '@services/sites';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
|
||||||
import { CoreSettingsHelper, CoreSiteSpaceUsage } from '../../services/settings-helper';
|
|
||||||
import { CoreApp } from '@services/app';
|
|
||||||
import { Translate } from '@singletons';
|
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { CoreListItemsManager } from '@classes/items-management/list-items-manager';
|
import { CoreListItemsManager } from '@classes/items-management/list-items-manager';
|
||||||
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
|
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
|
||||||
import { CoreSettingsHandlersSource } from '@features/settings/classes/settings-handlers-source';
|
import { CoreSettingsHandlersSource } from '@features/settings/classes/settings-handlers-source';
|
||||||
|
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
|
||||||
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of site settings pages.
|
* Page that displays the list of site settings pages.
|
||||||
|
@ -41,18 +39,11 @@ export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
handlers: CoreListItemsManager<CoreSettingsHandlerToDisplay>;
|
handlers: CoreListItemsManager<CoreSettingsHandlerToDisplay>;
|
||||||
|
|
||||||
isIOS: boolean;
|
protected siteId: string;
|
||||||
siteId: string;
|
|
||||||
spaceUsage: CoreSiteSpaceUsage = {
|
|
||||||
cacheEntries: 0,
|
|
||||||
spaceUsage: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
protected sitesObserver: CoreEventObserver;
|
protected sitesObserver: CoreEventObserver;
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.isIOS = CoreApp.isIOS();
|
|
||||||
this.siteId = CoreSites.getCurrentSiteId();
|
this.siteId = CoreSites.getCurrentSiteId();
|
||||||
|
|
||||||
const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreSettingsHandlersSource, []);
|
const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreSettingsHandlersSource, []);
|
||||||
|
@ -90,8 +81,6 @@ export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy {
|
||||||
*/
|
*/
|
||||||
protected async fetchData(): Promise<void> {
|
protected async fetchData(): Promise<void> {
|
||||||
await this.handlers.load();
|
await this.handlers.load();
|
||||||
|
|
||||||
this.spaceUsage = await CoreSettingsHelper.getSiteSpaceUsage(this.siteId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,41 +120,6 @@ export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes files of a site and the tables that can be cleared.
|
|
||||||
*
|
|
||||||
* @param siteData Site object with space usage.
|
|
||||||
*/
|
|
||||||
async deleteSiteStorage(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const siteName = CoreSites.getRequiredCurrentSite().getSiteName();
|
|
||||||
|
|
||||||
this.spaceUsage = await CoreSettingsHelper.deleteSiteStorage(siteName, this.siteId);
|
|
||||||
} catch {
|
|
||||||
// Ignore cancelled confirmation modal.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show information about space usage actions.
|
|
||||||
*/
|
|
||||||
showSpaceInfo(): void {
|
|
||||||
CoreDomUtils.showAlert(
|
|
||||||
Translate.instant('core.help'),
|
|
||||||
Translate.instant('core.settings.spaceusagehelp'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show information about sync actions.
|
|
||||||
*/
|
|
||||||
showSyncInfo(): void {
|
|
||||||
CoreDomUtils.showAlert(
|
|
||||||
Translate.instant('core.help'),
|
|
||||||
Translate.instant('core.settings.synchronizenowhelp'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page destroyed.
|
* Page destroyed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2,12 +2,6 @@
|
||||||
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
<ion-button *ngIf="searchEnabled" (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
|
||||||
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<core-context-menu>
|
|
||||||
<core-context-menu-item [priority]="500" [content]="'addon.storagemanager.managestorage' | translate"
|
|
||||||
(action)="manageCoursesStorage()" iconAction="fas-archive"></core-context-menu-item>
|
|
||||||
<core-context-menu-item [priority]="400" [content]="'addon.storagemanager.managecoursestorage' | translate"
|
|
||||||
(action)="manageCourseStorage()" iconAction="fas-archive"></core-context-menu-item>
|
|
||||||
</core-context-menu>
|
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-refresher slot="fixed" [disabled]="!dataLoaded" (ionRefresh)="doRefresh($event.target)">
|
<ion-refresher slot="fixed" [disabled]="!dataLoaded" (ionRefresh)="doRefresh($event.target)">
|
||||||
|
|
|
@ -175,20 +175,6 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Open page to manage courses storage.
|
|
||||||
*/
|
|
||||||
manageCoursesStorage(): void {
|
|
||||||
CoreNavigator.navigateToSitePath('/storage');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open page to manage course storage.
|
|
||||||
*/
|
|
||||||
manageCourseStorage(): void {
|
|
||||||
CoreNavigator.navigateToSitePath('/storage/' + this.siteHomeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go to search courses.
|
* Go to search courses.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -34,7 +34,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges {
|
||||||
|
|
||||||
@Input() course?: CoreCourseAnyCourseData; // The course to render.
|
@Input() course?: CoreCourseAnyCourseData; // The course to render.
|
||||||
@Input() sections?: CoreCourseSection[]; // List of course sections. The status will be calculated in this component.
|
@Input() sections?: CoreCourseSection[]; // 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() initialSectionId?: number; // The section to load first (by ID).
|
||||||
@Input() initialSectionNumber?: number; // The section to load first (by number).
|
@Input() initialSectionNumber?: number; // The section to load first (by number).
|
||||||
@Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section.
|
@Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section.
|
||||||
|
@ -71,7 +70,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges {
|
||||||
this.method = handler.handlerSchema.method;
|
this.method = handler.handlerSchema.method;
|
||||||
this.args = {
|
this.args = {
|
||||||
courseid: this.course.id,
|
courseid: this.course.id,
|
||||||
downloadenabled: this.downloadEnabled,
|
|
||||||
};
|
};
|
||||||
this.initResult = handler.initResult;
|
this.initResult = handler.initResult;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +79,6 @@ export class CoreSitePluginsCourseFormatComponent implements OnChanges {
|
||||||
this.data = {
|
this.data = {
|
||||||
course: this.course,
|
course: this.course,
|
||||||
sections: this.sections,
|
sections: this.sections,
|
||||||
downloadEnabled: this.downloadEnabled,
|
|
||||||
initialSectionId: this.initialSectionId,
|
initialSectionId: this.initialSectionId,
|
||||||
initialSectionNumber: this.initialSectionNumber,
|
initialSectionNumber: this.initialSectionNumber,
|
||||||
moduleId: this.moduleId,
|
moduleId: this.moduleId,
|
||||||
|
|
Loading…
Reference in New Issue