diff --git a/scripts/langindex.json b/scripts/langindex.json index 473b3ddbd..aebe2caf0 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1168,6 +1168,7 @@ "addon.storagemanager.deletecourses": "local_moodlemobileapp", "addon.storagemanager.deletedata": "local_moodlemobileapp", "addon.storagemanager.deletedatafrom": "local_moodlemobileapp", + "addon.storagemanager.downloaddatafrom": "local_moodlemobileapp", "addon.storagemanager.downloadedcourses": "local_moodlemobileapp", "addon.storagemanager.downloads": "local_moodlemobileapp", "addon.storagemanager.errordeletedownloadeddata": "local_moodlemobileapp", diff --git a/src/addons/storagemanager/lang.json b/src/addons/storagemanager/lang.json index 9d058c222..5c2fc0eb2 100644 --- a/src/addons/storagemanager/lang.json +++ b/src/addons/storagemanager/lang.json @@ -11,6 +11,7 @@ "deletecourses": "Delete downloaded data from all courses", "deletedata": "Delete downloaded data", "deletedatafrom": "Delete all downloaded data from '{{name}}'", + "downloaddatafrom": "Download {{name}}", "downloadedcourses": "Downloaded courses", "downloads": "Downloads", "errordeletedownloadeddata": "Error deleting downloaded data.", diff --git a/src/addons/storagemanager/pages/course-storage/course-storage.html b/src/addons/storagemanager/pages/course-storage/course-storage.html index dd39926aa..e3d2cf0dc 100644 --- a/src/addons/storagemanager/pages/course-storage/course-storage.html +++ b/src/addons/storagemanager/pages/course-storage/course-storage.html @@ -45,98 +45,102 @@ - - - - - - - - - - - - -

- -

- - {{ module.totalSize | coreBytesToSize }} - - - {{ 'core.calculating' | translate }} - -
+ + {{ 'core.calculating' | translate }} + + +

+ +

+ +
+
+ -
- - - - -

- {{ 'core.notdownloadable' | translate }} -

+ + {{section.count}} / {{section.total}} +
- - - - - - + + + +
+ + + + + + + +

+ +

+ + {{ module.totalSize | + coreBytesToSize }} + + + {{ 'core.calculating' | translate }} + +
+ +
+ + + + +

+ {{ 'core.notdownloadable' | translate }} +

+
+
+
+
+
+ + + + + diff --git a/src/addons/storagemanager/pages/course-storage/course-storage.scss b/src/addons/storagemanager/pages/course-storage/course-storage.scss index 8f8356527..e8690d5ac 100644 --- a/src/addons/storagemanager/pages/course-storage/course-storage.scss +++ b/src/addons/storagemanager/pages/course-storage/course-storage.scss @@ -8,13 +8,20 @@ } ion-card.section { - ion-card-header { + ion-item.card-header { padding: 0; + --border-width: 0px; .item-heading { font: var(--mdl-typography-heading4-font); } } + + .accordion-expanded { + ion-item.card-header { + --border-width: 0 0 1px 0; + } + } ion-card-content { padding: 0; diff --git a/src/addons/storagemanager/pages/course-storage/course-storage.ts b/src/addons/storagemanager/pages/course-storage/course-storage.ts index 7c7ee9f1a..acf17dfb2 100644 --- a/src/addons/storagemanager/pages/course-storage/course-storage.ts +++ b/src/addons/storagemanager/pages/course-storage/course-storage.ts @@ -13,7 +13,7 @@ // limitations under the License. import { CoreConstants, DownloadStatus } from '@/core/constants'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { CoreCourse, CoreCourseProvider } from '@features/course/services/course'; import { CoreCourseHelper, @@ -25,6 +25,7 @@ import { CoreCourseModulePrefetchDelegate, CoreCourseModulePrefetchHandler } from '@features/course/services/module-prefetch-delegate'; import { CoreCourseAnyCourseData, CoreCourses } from '@features/courses/services/courses'; +import { AccordionGroupChangeEventDetail, IonAccordionGroup } from '@ionic/angular'; import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; @@ -40,11 +41,13 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; @Component({ selector: 'page-addon-storagemanager-course-storage', templateUrl: 'course-storage.html', - styleUrls: ['course-storage.scss'], + styleUrl: 'course-storage.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { + @ViewChild('accordionGroup', { static: true }) accordionGroup!: IonAccordionGroup; + courseId!: number; title = ''; loaded = false; @@ -64,7 +67,6 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { statusDownloaded = DownloadStatus.DOWNLOADED; - protected initialSectionId?: number; protected siteUpdatedObserver?: CoreEventObserver; protected courseStatusObserver?: CoreEventObserver; protected sectionStatusObserver?: CoreEventObserver; @@ -106,7 +108,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { this.isGuest = CoreNavigator.getRouteBooleanParam('isGuest') ?? (await CoreCourseHelper.courseUsesGuestAccessInfo(this.courseId)).guestAccess; - this.initialSectionId = CoreNavigator.getRouteNumberParam('sectionId'); + const initialSectionId = CoreNavigator.getRouteNumberParam('sectionId'); this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite(); this.downloadEnabled = !CoreSites.getRequiredCurrentSite().isOfflineDisabled(); @@ -118,7 +120,7 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { ...section, totalSize: 0, calculatingSize: true, - expanded: section.id === this.initialSectionId, + expanded: section.id === initialSectionId, modules: section.modules.map(module => ({ ...module, calculatingSize: true, @@ -127,9 +129,11 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { this.loaded = true; + this.accordionGroup.value = String(initialSectionId); + CoreDom.scrollToElement( this.elementRef.nativeElement, - '.core-course-storage-section-expanded', + '.accordion-expanded', { addYAxis: -10 }, ); @@ -719,12 +723,17 @@ export class AddonStorageManagerCourseStoragePage implements OnInit, OnDestroy { * Toggle expand status. * * @param event Event object. - * @param section Section to expand / collapse. */ - toggleExpand(event: Event, section: AddonStorageManagerCourseSection): void { - section.expanded = !section.expanded; - event.stopPropagation(); - event.preventDefault(); + accordionGroupChange(event: AccordionGroupChangeEventDetail): void { + this.sections.forEach((section) => { + section.expanded = false; + }); + event.value.forEach((sectionId) => { + const section = this.sections.find((section) => section.id === Number(sectionId)); + if (section) { + section.expanded = true; + } + }); } /** diff --git a/src/addons/storagemanager/storagemanager-lazy.module.ts b/src/addons/storagemanager/storagemanager-lazy.module.ts index 0978a1b64..0f4a1fb2d 100644 --- a/src/addons/storagemanager/storagemanager-lazy.module.ts +++ b/src/addons/storagemanager/storagemanager-lazy.module.ts @@ -40,4 +40,4 @@ const routes: Routes = [ AddonStorageManagerCourseStoragePage, ], }) -export class AddonStorageManagerLazyModule {} +export default class AddonStorageManagerLazyModule {} diff --git a/src/addons/storagemanager/storagemanager.module.ts b/src/addons/storagemanager/storagemanager.module.ts index fce59aaec..cd860e5d9 100644 --- a/src/addons/storagemanager/storagemanager.module.ts +++ b/src/addons/storagemanager/storagemanager.module.ts @@ -23,7 +23,7 @@ import { AddonStorageManagerSettingsHandler } from './services/handlers/settings const routes: Routes = [ { path: '', - loadChildren: () => import('@addons/storagemanager/storagemanager-lazy.module').then(m => m.AddonStorageManagerLazyModule), + loadChildren: () => import('@addons/storagemanager/storagemanager-lazy.module'), }, ]; diff --git a/src/core/components/download-refresh/core-download-refresh.html b/src/core/components/download-refresh/core-download-refresh.html index 51f61ce01..9aa45dbb2 100644 --- a/src/core/components/download-refresh/core-download-refresh.html +++ b/src/core/components/download-refresh/core-download-refresh.html @@ -1,23 +1,25 @@ + [ariaLabel]="(statusTranslatable || translates.notdownloaded) | translate: { name : statusSubject }"> + (click)="download($event, true)" @coreShowHideAnimation + [ariaLabel]="(statusTranslatable || translates.outdated) | translate: { name : statusSubject }"> + name="fam-cloud-done" [attr.aria-label]="(statusTranslatable || translates.downloaded) | translate: { name : statusSubject }" + role="status" /> + [attr.aria-label]="(statusTranslatable || translates.downloading) | translate: { name : statusSubject }" /> - + diff --git a/src/core/components/download-refresh/download-refresh.ts b/src/core/components/download-refresh/download-refresh.ts index 13f67a5a8..31ae04256 100644 --- a/src/core/components/download-refresh/download-refresh.ts +++ b/src/core/components/download-refresh/download-refresh.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, Output, EventEmitter } from '@angular/core'; +import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { DownloadStatus } from '@/core/constants'; import { CoreAnimations } from '@components/animations'; @@ -29,24 +29,45 @@ import { CoreAnimations } from '@components/animations'; styleUrls: ['download-refresh.scss'], animations: [CoreAnimations.SHOW_HIDE], }) -export class CoreDownloadRefreshComponent { +export class CoreDownloadRefreshComponent implements OnInit { @Input() status?: DownloadStatus; // Download status. - @Input() statusTranslatable?: string; // Download status translatable string. + @Input() statusesTranslatable?: Partial; // Download statuses translatable strings. + @Input() statusSubject = ''; // Status subject to use on name filed in the translatable string. @Input() enabled = false; // Whether the download is enabled. @Input() loading = true; // Force loading status when is not downloading. @Input() canTrustDownload = false; // If false, refresh will be shown if downloaded. @Output() action: EventEmitter; // Will emit an event when the item clicked. + /** + * @deprecated since 4.5. Use statusesTranslatable instead. + */ + @Input() statusTranslatable?: string; // Download status translatable string. + statusDownloaded = DownloadStatus.DOWNLOADED; statusNotDownloaded = DownloadStatus.DOWNLOADABLE_NOT_DOWNLOADED; statusOutdated = DownloadStatus.OUTDATED; statusDownloading = DownloadStatus.DOWNLOADING; + translates: CoreDownloadStatusTranslatable = { + downloaded: 'core.downloaded', + notdownloaded: 'core.download', + outdated: 'core.refresh', + downloading: 'core.downloading', + loading: 'core.loading', + }; + constructor() { this.action = new EventEmitter(); } + /** + * @inheritdoc + */ + ngOnInit(): void { + this.translates = Object.assign(this.translates, this.statusesTranslatable || {}); + } + /** * Download clicked. * @@ -61,3 +82,11 @@ export class CoreDownloadRefreshComponent { } } + +export type CoreDownloadStatusTranslatable = { + downloaded: string; + notdownloaded: string; + outdated: string; + downloading: string; + loading: string; +}; diff --git a/src/core/features/course/components/module-summary/module-summary.html b/src/core/features/course/components/module-summary/module-summary.html index 202d5ad12..8d4e37bad 100644 --- a/src/core/features/course/components/module-summary/module-summary.html +++ b/src/core/features/course/components/module-summary/module-summary.html @@ -176,7 +176,8 @@ + (click)="prefetch()" [disabled]="prefetchDisabled" + [attr.aria-label]="'addon.storagemanager.downloaddatafrom' | translate:{name: module?.name}">