diff --git a/src/addons/mod/assign/components/index/addon-mod-assign-index.html b/src/addons/mod/assign/components/index/addon-mod-assign-index.html index de9b9a462..73d0903e9 100644 --- a/src/addons/mod/assign/components/index/addon-mod-assign-index.html +++ b/src/addons/mod/assign/components/index/addon-mod-assign-index.html @@ -24,6 +24,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/bigbluebuttonbn/components/index/index.html b/src/addons/mod/bigbluebuttonbn/components/index/index.html index 7b5f0aa7b..e10694728 100644 --- a/src/addons/mod/bigbluebuttonbn/components/index/index.html +++ b/src/addons/mod/bigbluebuttonbn/components/index/index.html @@ -17,6 +17,10 @@ [iconAction]="prefetchStatusIcon" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/book/components/index/addon-mod-book-index.html b/src/addons/mod/book/components/index/addon-mod-book-index.html index 0ebdcb21f..4e1084b7a 100644 --- a/src/addons/mod/book/components/index/addon-mod-book-index.html +++ b/src/addons/mod/book/components/index/addon-mod-book-index.html @@ -15,6 +15,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/chat/components/index/addon-mod-chat-index.html b/src/addons/mod/chat/components/index/addon-mod-chat-index.html index d9106e2bf..5851b8e75 100644 --- a/src/addons/mod/chat/components/index/addon-mod-chat-index.html +++ b/src/addons/mod/chat/components/index/addon-mod-chat-index.html @@ -21,6 +21,10 @@ [iconAction]="prefetchStatusIcon" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/choice/components/index/addon-mod-choice-index.html b/src/addons/mod/choice/components/index/addon-mod-choice-index.html index 730623b79..4b32c2dbf 100644 --- a/src/addons/mod/choice/components/index/addon-mod-choice-index.html +++ b/src/addons/mod/choice/components/index/addon-mod-choice-index.html @@ -23,6 +23,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/data/components/index/addon-mod-data-index.html b/src/addons/mod/data/components/index/addon-mod-data-index.html index c33a3a94a..b64adbce8 100644 --- a/src/addons/mod/data/components/index/addon-mod-data-index.html +++ b/src/addons/mod/data/components/index/addon-mod-data-index.html @@ -33,6 +33,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html b/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html index f7bde4f52..bb3b4550e 100644 --- a/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html +++ b/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html @@ -23,6 +23,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/folder/components/index/addon-mod-folder-index.html b/src/addons/mod/folder/components/index/addon-mod-folder-index.html index adceb5976..ea4d48cdf 100644 --- a/src/addons/mod/folder/components/index/addon-mod-folder-index.html +++ b/src/addons/mod/folder/components/index/addon-mod-folder-index.html @@ -20,6 +20,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/forum/components/index/index.html b/src/addons/mod/forum/components/index/index.html index 11a307a79..3bd8b6ada 100644 --- a/src/addons/mod/forum/components/index/index.html +++ b/src/addons/mod/forum/components/index/index.html @@ -28,6 +28,10 @@ (action)="showSortOrderSelector()"> + + + + diff --git a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html index a3437f70d..142f410eb 100644 --- a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html +++ b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html @@ -36,6 +36,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html b/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html index 1338852c1..e7b6e7ea2 100644 --- a/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html +++ b/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html @@ -30,6 +30,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html b/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html index 7a7a036c2..b6856d0db 100644 --- a/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html +++ b/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html @@ -23,6 +23,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html index 1dd4b2270..dd57d8860 100644 --- a/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html +++ b/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html @@ -23,6 +23,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/lti/components/index/addon-mod-lti-index.html b/src/addons/mod/lti/components/index/addon-mod-lti-index.html index 9430ef52b..9dfc934b2 100644 --- a/src/addons/mod/lti/components/index/addon-mod-lti-index.html +++ b/src/addons/mod/lti/components/index/addon-mod-lti-index.html @@ -14,6 +14,10 @@ (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/page/components/index/addon-mod-page-index.html b/src/addons/mod/page/components/index/addon-mod-page-index.html index 1c8cab9ed..bd5f3a6ba 100644 --- a/src/addons/mod/page/components/index/addon-mod-page-index.html +++ b/src/addons/mod/page/components/index/addon-mod-page-index.html @@ -20,6 +20,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html index dffa76b76..8060c0171 100644 --- a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html +++ b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html @@ -23,6 +23,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/resource/components/index/addon-mod-resource-index.html b/src/addons/mod/resource/components/index/addon-mod-resource-index.html index bbad8ec56..78357a63f 100644 --- a/src/addons/mod/resource/components/index/addon-mod-resource-index.html +++ b/src/addons/mod/resource/components/index/addon-mod-resource-index.html @@ -15,6 +15,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html b/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html index aeb744521..e5eea8e77 100644 --- a/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html +++ b/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html @@ -23,6 +23,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/survey/components/index/addon-mod-survey-index.html b/src/addons/mod/survey/components/index/addon-mod-survey-index.html index 99a46962c..8f73a5c47 100644 --- a/src/addons/mod/survey/components/index/addon-mod-survey-index.html +++ b/src/addons/mod/survey/components/index/addon-mod-survey-index.html @@ -24,6 +24,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/url/components/index/addon-mod-url-index.html b/src/addons/mod/url/components/index/addon-mod-url-index.html index 24f4579bd..47d00e1af 100644 --- a/src/addons/mod/url/components/index/addon-mod-url-index.html +++ b/src/addons/mod/url/components/index/addon-mod-url-index.html @@ -10,6 +10,10 @@ + + + + diff --git a/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html b/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html index 7db05d66b..c689ec193 100644 --- a/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html +++ b/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html @@ -42,6 +42,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html index a5a979a6f..ec5719b0d 100644 --- a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html +++ b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html @@ -24,6 +24,10 @@ iconDescription="fas-archive" (action)="removeFiles($event)" iconAction="fas-trash" [closeOnClick]="false"> + + + + diff --git a/src/core/features/block/components/side-blocks/side-blocks.html b/src/core/features/block/components/side-blocks/side-blocks.html index 198cb21d2..91fee4e1e 100644 --- a/src/core/features/block/components/side-blocks/side-blocks.html +++ b/src/core/features/block/components/side-blocks/side-blocks.html @@ -1,8 +1,5 @@ - + - - {{ 'core.block.blocks' | translate }} - @@ -10,7 +7,7 @@ - + diff --git a/src/core/features/course/classes/main-activity-component.ts b/src/core/features/course/classes/main-activity-component.ts index 1c2621036..e89d53476 100644 --- a/src/core/features/course/classes/main-activity-component.ts +++ b/src/core/features/course/classes/main-activity-component.ts @@ -42,7 +42,6 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR // Data for context menu. syncIcon?: string; // Sync icon. - hasOffline?: boolean; // If it has offline data to be synced. isOnline?: boolean; // If the app is online or not. protected syncObserver?: CoreEventObserver; // It will observe the sync auto event. diff --git a/src/core/features/course/classes/main-resource-component.ts b/src/core/features/course/classes/main-resource-component.ts index 1cf1b4a0b..cc1f72c67 100644 --- a/src/core/features/course/classes/main-resource-component.ts +++ b/src/core/features/course/classes/main-resource-component.ts @@ -29,6 +29,7 @@ import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreLogger } from '@singletons/logger'; +import { CoreCourseModuleSummaryComponent, CoreCourseModuleSummaryResult } from '../components/module-summary/module-summary'; import { CoreCourseContentsPage } from '../pages/contents/contents'; import { CoreCourse } from '../services/course'; import { CoreCourseHelper, CoreCourseModuleData } from '../services/course-helper'; @@ -58,6 +59,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, loaded = false; // If the component has been loaded. component?: string; // Component name. componentId?: number; // Component ID. + hasOffline = false; // Resources don't have any data to sync. blog?: boolean; // If blog is available. // Data for context menu. @@ -253,16 +255,11 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, /** * Expand the description. + * + * @deprecated Use openModuleSummary instead. */ expandDescription(): void { - CoreTextUtils.viewText(Translate.instant('core.description'), this.description!, { - component: this.component, - componentId: this.module.id, - filter: true, - contextLevel: 'module', - instanceId: this.module.id, - courseId: this.courseId, - }); + this.openModuleSummary(); } /** @@ -449,6 +446,48 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, this.module = module; } + /** + * Opens a module summary page. + */ + async openModuleSummary(): Promise { + if (!this.module) { + return; + } + + const data = await CoreDomUtils.openSideModal({ + component: CoreCourseModuleSummaryComponent, + componentProps: { + moduleId: this.module.id, + module: this.module, + description: this.description, + component: this.component, + courseId: this.courseId, + hasOffline: this.hasOffline, + }, + }); + + if (data) { + if (data.action == 'refresh') { + const modal = await CoreDomUtils.showModalLoading(); + + try { + await this.doRefresh(); + } finally { + modal.dismiss(); + } + } else if(data.action == 'sync') { + const modal = await CoreDomUtils.showModalLoading(); + + try { + await this.doRefresh( undefined, undefined, true); + } finally { + modal.dismiss(); + } + } + + } + } + /** * Component being destroyed. */ diff --git a/src/core/features/course/components/components.module.ts b/src/core/features/course/components/components.module.ts index 53f7d8563..5eee268bf 100644 --- a/src/core/features/course/components/components.module.ts +++ b/src/core/features/course/components/components.module.ts @@ -27,6 +27,7 @@ import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-l import { CoreCourseModuleInfoComponent } from './module-info/module-info'; import { CoreCourseModuleManualCompletionComponent } from './module-manual-completion/module-manual-completion'; import { CoreCourseModuleNavigationComponent } from './module-navigation/module-navigation'; +import { CoreCourseModuleSummaryComponent } from './module-summary/module-summary'; @NgModule({ declarations: [ @@ -41,6 +42,7 @@ import { CoreCourseModuleNavigationComponent } from './module-navigation/module- CoreCourseTagAreaComponent, CoreCourseUnsupportedModuleComponent, CoreCourseModuleNavigationComponent, + CoreCourseModuleSummaryComponent, ], imports: [ CoreBlockComponentsModule, @@ -58,6 +60,7 @@ import { CoreCourseModuleNavigationComponent } from './module-navigation/module- CoreCourseTagAreaComponent, CoreCourseUnsupportedModuleComponent, CoreCourseModuleNavigationComponent, + CoreCourseModuleSummaryComponent, ], }) export class CoreCourseComponentsModule {} diff --git a/src/core/features/course/components/module-summary/module-summary.html b/src/core/features/course/components/module-summary/module-summary.html new file mode 100644 index 000000000..26d20c8b6 --- /dev/null +++ b/src/core/features/course/components/module-summary/module-summary.html @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ prefetchText }} + {{ downloadTimeReadable }} + + + + + + + + + + + {{ 'addon.storagemanager.totalspaceusage' | translate }} + {{ sizeReadable | coreBytesToSize }} + + 0" (click)="removeFiles()" color="danger" fill="outline" + [attr.aria-label]="'core.clearstoreddata' | translate:{$a: sizeReadable}" slot="end"> + + + + + + + + + {{ 'addon.blog.blog' | translate }} + + + + + + + + + {{ 'core.refresh' | translate }} + + + + + + + {{ 'core.settings.synchronizenow' | translate }} + + + diff --git a/src/core/features/course/components/module-summary/module-summary.scss b/src/core/features/course/components/module-summary/module-summary.scss new file mode 100644 index 000000000..fb9664764 --- /dev/null +++ b/src/core/features/course/components/module-summary/module-summary.scss @@ -0,0 +1,8 @@ + +:host ::ng-deep .collapsible-title ion-label { + margin-top: 12px; +} + +h1 { + font-size: 20px; +} diff --git a/src/core/features/course/components/module-summary/module-summary.ts b/src/core/features/course/components/module-summary/module-summary.ts new file mode 100644 index 000000000..58d159945 --- /dev/null +++ b/src/core/features/course/components/module-summary/module-summary.ts @@ -0,0 +1,311 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreConstants } from '@/core/constants'; +import { AddonBlog } from '@addons/blog/services/blog'; +import { AddonBlogMainMenuHandlerService } from '@addons/blog/services/handlers/mainmenu'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { Params } from '@angular/router'; +import { CoreCourseHelper, CoreCourseModuleData } from '@features/course/services/course-helper'; +import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; +import { CoreApp } from '@services/app'; +import { CoreFilepool } from '@services/filepool'; +import { CoreNavigator } from '@services/navigator'; +import { CoreSites } from '@services/sites'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreTextUtils } from '@services/utils/text'; +import { CoreUtils } from '@services/utils/utils'; +import { ModalController, Network, Translate, NgZone } from '@singletons'; +import { CoreEventObserver, CoreEvents } from '@singletons/events'; +import { Subscription } from 'rxjs'; + +/** + * Component to display a module summary modal. + */ +@Component({ + selector: 'core-course-module-summary', + templateUrl: 'module-summary.html', + styleUrls: ['module-summary.scss'], +}) +export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { + + @Input() module?: CoreCourseModuleData; // The module of the component. + @Input() courseId = 0; // Course ID the component belongs to. + @Input() moduleId = 0; // Module ID the component belongs to. + @Input() component = ''; // Component name. + @Input() description = ''; // Module description. + @Input() hasOffline = false; // If it has offline data to be synced. + + loaded = false; // If the component has been loaded. + componentId?: number; // Component ID. + + // Data for context menu. + externalUrl?: string; // External URL to open in browser. + + removeFilesLoading = false; + prefetchStatusIcon?: string; + prefetchStatus?: string; + prefetchText?: string; + sizeReadable?: string; + downloadTimeReadable?: string; // Last download time in a readable format. + size = 0; + + blog = false; // If blog is available. + + isOnline = false; // If the app is online or not. + + protected onlineSubscription: Subscription; // It will observe the status of the network connection. + + protected packageStatusObserver?: CoreEventObserver; // Observer of package status. + protected fileStatusObserver?: CoreEventObserver; // Observer of file status. + protected siteId: string; + protected isDestroyed = false; + + constructor() { + this.siteId = CoreSites.getCurrentSiteId(); + this.isOnline = CoreApp.isOnline(); + + // Refresh online status when changes. + this.onlineSubscription = Network.onChange().subscribe(() => { + // Execute the callback in the Angular zone, so change detection doesn't stop working. + NgZone.run(() => { + this.isOnline = CoreApp.isOnline(); + }); + }); + } + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + if (!this.module) { + this.closeModal(); + + return; + } + + this.fetchContent(); + + if (this.component) { + this.packageStatusObserver = CoreEvents.on( + CoreEvents.PACKAGE_STATUS_CHANGED, + (data) => { + if (data.componentId == module.id && data.component == this.component) { + this.getPackageStatus(); + } + }, + this.siteId, + ); + + // Debounce the update size function to prevent too many calls when downloading or deleting a whole activity. + const debouncedUpdateSize = CoreUtils.debounce(async () => { + if (!this.module) { + return; + } + + const moduleSize = await CoreCourseModulePrefetchDelegate.getModuleStoredSize(this.module, this.courseId); + + this.sizeReadable = moduleSize > 0 ? CoreTextUtils.bytesToSize(moduleSize, 2) : ''; + }, 1000); + + this.fileStatusObserver = CoreEvents.on( + CoreEvents.COMPONENT_FILE_ACTION, + (data) => { + if (data.component != this.component || data.componentId != module.id) { + // The event doesn't belong to this component, ignore. + return; + } + + if (!CoreFilepool.isFileEventDownloadedOrDeleted(data)) { + return; + } + + // Update the module size. + debouncedUpdateSize(); + }, + this.siteId, + ); + } + + } + + /** + * Fetch content to populate the page. + */ + protected async fetchContent(): Promise { + if (!this.module) { + return; + } + + this.componentId = this.module.id; + this.externalUrl = this.module.url; + this.courseId = this.courseId || this.module.course; + + this.blog = await AddonBlog.isPluginEnabled(); + + await this.getPackageStatus(); + + this.loaded = true; + } + + /** + * Updage package status. + * + * @param refresh If prefetch info has to be refreshed. + */ + async getPackageStatus(refresh = false): Promise { + if (!this.module) { + return; + } + + const moduleInfo = + await CoreCourseHelper.getModulePrefetchInfo(this.module, this.courseId, refresh, this.component); + + this.prefetchStatusIcon = moduleInfo.statusIcon; + this.prefetchStatus = moduleInfo.status; + this.downloadTimeReadable = ''; + + if (moduleInfo.status != CoreConstants.NOT_DOWNLOADABLE) { + // Module is downloadable, get the text to display to prefetch. + if (moduleInfo.downloadTime && moduleInfo.downloadTime > 0) { + this.prefetchText = Translate.instant('core.lastdownloaded'); + this.downloadTimeReadable = CoreTextUtils.ucFirst(moduleInfo.downloadTimeReadable); + } else { + // Module not downloaded, show a default text. + this.prefetchText = Translate.instant('core.download'); + } + } + + this.sizeReadable = moduleInfo.sizeReadable; + this.size = moduleInfo.size; + if (moduleInfo.status == CoreConstants.DOWNLOADING) { + // Set this to empty to prevent "remove file" option showing up while downloading. + this.sizeReadable = ''; + } + } + + /** + * Go to blog posts. + */ + async gotoBlog(): Promise { + const params: Params = { cmId: this.moduleId }; + + await CoreNavigator.navigateToSitePath(AddonBlogMainMenuHandlerService.PAGE_NAME, { params }); + } + + /** + * Prefetch the module. + */ + async prefetch(): Promise { + if (!this.module) { + return; + } + + const initialIcon = this.prefetchStatusIcon; + this.prefetchStatusIcon = CoreConstants.ICON_DOWNLOADING; // Show spinner since this operation might take a while. + + try { + // We need to call getDownloadSize, the package might have been updated. + const size = await CoreCourseModulePrefetchDelegate.getModuleDownloadSize(this.module, this.courseId, true); + + await CoreDomUtils.confirmDownloadSize(size); + + await CoreCourseModulePrefetchDelegate.prefetchModule(this.module, this.courseId, true); + + await this.getPackageStatus(true); + } catch (error) { + this.prefetchStatusIcon = initialIcon; + + if (!this.isDestroyed) { + CoreDomUtils.showErrorModalDefault(error, 'core.errordownloading', true); + } + } + } + + /** + * Confirm and remove downloaded files. + */ + async removeFiles(): Promise { + if (!this.module) { + return; + } + + if (this.prefetchStatus == CoreConstants.DOWNLOADING) { + CoreDomUtils.showAlertTranslated(undefined, 'core.course.cannotdeletewhiledownloading'); + + return; + } + + try { + await CoreDomUtils.showDeleteConfirm('addon.storagemanager.confirmdeletedatafrom', { name: this.module.name }); + + this.removeFilesLoading = true; + + await CoreCourseHelper.removeModuleStoredData(this.module, this.courseId); + + } catch (error) { + if (!this.isDestroyed &&error) { + CoreDomUtils.showErrorModal(error); + } + } finally { + this.removeFilesLoading = false; + } + + await this.getPackageStatus(); + } + + /** + * Refresh the data. + */ + async refresh(): Promise { + if (!this.module) { + return; + } + + ModalController.dismiss({ action: 'refresh' }); + } + + /** + * Sync the data. + */ + async sync(): Promise { + if (!this.module) { + return; + } + + ModalController.dismiss({ action: 'sync' }); + } + + /** + * Close the modal. + */ + closeModal(): void { + ModalController.dismiss(); + } + + /** + * @inheritdoc + */ + ngOnDestroy(): void { + this.isDestroyed = true; + this.packageStatusObserver?.off(); + this.fileStatusObserver?.off(); + this.onlineSubscription.unsubscribe(); + } + +} + +export type CoreCourseModuleSummaryResult = { + action: 'sync'|'refresh'; +}; diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index f11236c58..a2f2df66f 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -297,6 +297,14 @@ button, ion-button { margin: 4px 8px; + + ion-spinner[slot=start] { + @include margin-horizontal(-0.3em, 0.3em); + } + + ion-spinner[slot=end] { + @include margin-horizontal(-0.3em, 0.3em); + } } ion-button.button-outline { @@ -1465,6 +1473,16 @@ ion-grid.core-no-grid > ion-row { } } +ion-header.no-title { + --core-header-toolbar-border-width: 0; + --core-header-toolbar-background: transparent; + + ion-toolbar .button.button-clear, + ion-toolbar .button.button-solid { + --background: var(--ion-background-color); + } +} + ion-header[collapsible] { @include core-transition(all, 500ms);
{{ prefetchText }}
{{ downloadTimeReadable }}
{{ 'addon.storagemanager.totalspaceusage' | translate }}