Merge pull request #3090 from crazyserver/MOBILE-3954

Mobile 3954
main
Dani Palou 2022-02-02 16:16:19 +01:00 committed by GitHub
commit cb5508fc72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 187 additions and 260 deletions

View File

@ -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",

View File

@ -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>

View File

@ -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;
} }

View File

@ -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>

View File

@ -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();
} }
} }

View File

@ -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;

View File

@ -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>

View File

@ -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();
} }
} }

View File

@ -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"
} }

View File

@ -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>

View File

@ -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,

View File

@ -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>
<p class="ion-text-wrap">{{ 'addon.storagemanager.info' | translate }}</p>
<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>
<h2 class="ion-text-wrap">{{ 'addon.storagemanager.storageused' | translate }}</h2> <p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totalspaceusage' | translate }}</p>
<ion-badge color="light" *ngIf="spaceUsage.spaceUsage">{{ spaceUsage.spaceUsage | coreBytesToSize }}</ion-badge>
<p>
{{ 'core.settings.spaceusagehelp' | translate }}
</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" aria-hidden="true"></ion-icon>
</ion-button>
</ion-item>
<ion-item class="size ion-text-wrap" lines="none">
<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 name="fas-trash" slot="icon-only" ariaLabel="{{ 'addon.storagemanager.deletecourses' | translate }}">
</ion-icon> </ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
</ion-card-header>
</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>

View File

@ -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;
} }

View File

@ -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',
}; };
} }

View File

@ -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',
}; };

View File

@ -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">

View File

@ -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>

View File

@ -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();
} }
} }

View File

@ -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">
<ion-label>
<h2>{{ 'core.courses.mycourses' | translate }}</h2> <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>
</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">

View File

@ -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.
*/ */

View File

@ -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>

View File

@ -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.
*/ */

View File

@ -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)">

View File

@ -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.
*/ */

View File

@ -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,