MOBILE-3934 grades: Add swipe navigation
parent
275991d9ef
commit
11c2468d58
|
@ -0,0 +1,41 @@
|
||||||
|
// (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 { CoreRoutedItemsManagerSource } from '@classes/items-management/routed-items-manager-source';
|
||||||
|
import { CoreGrades } from '../services/grades';
|
||||||
|
import { CoreGradesGradeOverviewWithCourseData, CoreGradesHelper } from '../services/grades-helper';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a collection of courses.
|
||||||
|
*/
|
||||||
|
export class CoreGradesCoursesSource extends CoreRoutedItemsManagerSource<CoreGradesGradeOverviewWithCourseData> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
protected async loadPageItems(): Promise<{ items: CoreGradesGradeOverviewWithCourseData[] }> {
|
||||||
|
const grades = await CoreGrades.getCoursesGrades();
|
||||||
|
const courses = await CoreGradesHelper.getGradesCourseData(grades);
|
||||||
|
|
||||||
|
return { items: courses };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
getItemPath(course: CoreGradesGradeOverviewWithCourseData): string {
|
||||||
|
return course.courseid.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: CoreGradesCoursePage,
|
component: CoreGradesCoursePage,
|
||||||
|
data: { swipeEnabled: false },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
<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>{{ 'core.grades.grades' | translate }}</h1>
|
<h1>{{ title }}</h1>
|
||||||
</ion-title>
|
</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content [core-swipe-navigation]="courses">
|
||||||
<ion-refresher slot="fixed" [disabled]="!columns || !rows" (ionRefresh)="refreshGrades($event.target)">
|
<ion-refresher slot="fixed" [disabled]="!columns || !rows" (ionRefresh)="refreshGrades($event.target)">
|
||||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { AfterViewInit, Component, ElementRef } from '@angular/core';
|
import { AfterViewInit, Component, ElementRef, OnDestroy } from '@angular/core';
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
|
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
|
@ -28,6 +28,9 @@ import { CoreUtils } from '@services/utils/utils';
|
||||||
import { CoreNavigator } from '@services/navigator';
|
import { CoreNavigator } from '@services/navigator';
|
||||||
import { CoreScreen } from '@services/screen';
|
import { CoreScreen } from '@services/screen';
|
||||||
import { Translate } from '@singletons';
|
import { Translate } from '@singletons';
|
||||||
|
import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager';
|
||||||
|
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
|
||||||
|
import { CoreGradesCoursesSource } from '@features/grades/classes/grades-courses-source';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays a course grades.
|
* Page that displays a course grades.
|
||||||
|
@ -37,12 +40,14 @@ import { Translate } from '@singletons';
|
||||||
templateUrl: 'course.html',
|
templateUrl: 'course.html',
|
||||||
styleUrls: ['course.scss'],
|
styleUrls: ['course.scss'],
|
||||||
})
|
})
|
||||||
export class CoreGradesCoursePage implements AfterViewInit {
|
export class CoreGradesCoursePage implements AfterViewInit, OnDestroy {
|
||||||
|
|
||||||
courseId!: number;
|
courseId!: number;
|
||||||
userId!: number;
|
userId!: number;
|
||||||
expandLabel!: string;
|
expandLabel!: string;
|
||||||
collapseLabel!: string;
|
collapseLabel!: string;
|
||||||
|
title?: string;
|
||||||
|
courses?: CoreSwipeNavigationItemsManager;
|
||||||
columns?: CoreGradesFormattedTableColumn[];
|
columns?: CoreGradesFormattedTableColumn[];
|
||||||
rows?: CoreGradesFormattedTableRow[];
|
rows?: CoreGradesFormattedTableRow[];
|
||||||
totalColumnsSpan?: number;
|
totalColumnsSpan?: number;
|
||||||
|
@ -54,6 +59,12 @@ export class CoreGradesCoursePage implements AfterViewInit {
|
||||||
this.userId = CoreNavigator.getRouteNumberParam('userId', { route }) ?? CoreSites.getCurrentSiteUserId();
|
this.userId = CoreNavigator.getRouteNumberParam('userId', { route }) ?? CoreSites.getCurrentSiteUserId();
|
||||||
this.expandLabel = Translate.instant('core.expand');
|
this.expandLabel = Translate.instant('core.expand');
|
||||||
this.collapseLabel = Translate.instant('core.collapse');
|
this.collapseLabel = Translate.instant('core.collapse');
|
||||||
|
|
||||||
|
if (route.snapshot.data.swipeEnabled ?? true) {
|
||||||
|
const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreGradesCoursesSource, []);
|
||||||
|
|
||||||
|
this.courses = new CoreSwipeNavigationItemsManager(source);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CoreDomUtils.showErrorModal(error);
|
CoreDomUtils.showErrorModal(error);
|
||||||
|
|
||||||
|
@ -73,10 +84,18 @@ export class CoreGradesCoursePage implements AfterViewInit {
|
||||||
async ngAfterViewInit(): Promise<void> {
|
async ngAfterViewInit(): Promise<void> {
|
||||||
this.withinSplitView = !!this.element.nativeElement.parentElement?.closest('core-split-view');
|
this.withinSplitView = !!this.element.nativeElement.parentElement?.closest('core-split-view');
|
||||||
|
|
||||||
|
await this.courses?.start();
|
||||||
await this.fetchInitialGrades();
|
await this.fetchInitialGrades();
|
||||||
await CoreGrades.logCourseGradesView(this.courseId, this.userId);
|
await CoreGrades.logCourseGradesView(this.courseId, this.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.courses?.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get aria label for row.
|
* Get aria label for row.
|
||||||
*
|
*
|
||||||
|
@ -151,6 +170,7 @@ export class CoreGradesCoursePage implements AfterViewInit {
|
||||||
const table = await CoreGrades.getCourseGradesTable(this.courseId, this.userId);
|
const table = await CoreGrades.getCourseGradesTable(this.courseId, this.userId);
|
||||||
const formattedTable = await CoreGradesHelper.formatGradesTable(table);
|
const formattedTable = await CoreGradesHelper.formatGradesTable(table);
|
||||||
|
|
||||||
|
this.title = formattedTable.rows[0]?.gradeitem ?? Translate.instant('core.grades.grades');
|
||||||
this.columns = formattedTable.columns;
|
this.columns = formattedTable.columns;
|
||||||
this.rows = formattedTable.rows;
|
this.rows = formattedTable.rows;
|
||||||
this.totalColumnsSpan = formattedTable.columns.reduce((total, column) => total + column.colspan, 0);
|
this.totalColumnsSpan = formattedTable.columns.reduce((total, column) => total + column.colspan, 0);
|
||||||
|
|
|
@ -13,11 +13,12 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { CorePageItemsListManager } from '@classes/page-items-list-manager';
|
import { CoreListItemsManager } from '@classes/items-management/list-items-manager';
|
||||||
|
import { CoreRoutedItemsManagerSourcesTracker } from '@classes/items-management/routed-items-manager-sources-tracker';
|
||||||
|
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
|
import { CoreGradesCoursesSource } from '@features/grades/classes/grades-courses-source';
|
||||||
import { CoreGrades } from '@features/grades/services/grades';
|
import { CoreGrades } from '@features/grades/services/grades';
|
||||||
import { CoreGradesGradeOverviewWithCourseData, CoreGradesHelper } from '@features/grades/services/grades-helper';
|
|
||||||
import { IonRefresher } from '@ionic/angular';
|
import { IonRefresher } from '@ionic/angular';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
@ -31,10 +32,16 @@ import { CoreUtils } from '@services/utils/utils';
|
||||||
})
|
})
|
||||||
export class CoreGradesCoursesPage implements OnDestroy, AfterViewInit {
|
export class CoreGradesCoursesPage implements OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
courses: CoreGradesCoursesManager = new CoreGradesCoursesManager(CoreGradesCoursesPage);
|
courses: CoreGradesCoursesManager;
|
||||||
|
|
||||||
@ViewChild(CoreSplitViewComponent) splitView!: CoreSplitViewComponent;
|
@ViewChild(CoreSplitViewComponent) splitView!: CoreSplitViewComponent;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
const source = CoreRoutedItemsManagerSourcesTracker.getOrCreateSource(CoreGradesCoursesSource, []);
|
||||||
|
|
||||||
|
this.courses = new CoreGradesCoursesManager(source, CoreGradesCoursesPage);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
|
@ -58,7 +65,7 @@ export class CoreGradesCoursesPage implements OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
async refreshCourses(refresher: IonRefresher): Promise<void> {
|
async refreshCourses(refresher: IonRefresher): Promise<void> {
|
||||||
await CoreUtils.ignoreErrors(CoreGrades.invalidateCoursesGradesData());
|
await CoreUtils.ignoreErrors(CoreGrades.invalidateCoursesGradesData());
|
||||||
await CoreUtils.ignoreErrors(this.fetchCourses());
|
await CoreUtils.ignoreErrors(this.courses.reload());
|
||||||
|
|
||||||
refresher?.complete();
|
refresher?.complete();
|
||||||
}
|
}
|
||||||
|
@ -68,37 +75,18 @@ export class CoreGradesCoursesPage implements OnDestroy, AfterViewInit {
|
||||||
*/
|
*/
|
||||||
private async fetchInitialCourses(): Promise<void> {
|
private async fetchInitialCourses(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.fetchCourses();
|
await this.courses.load();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
CoreDomUtils.showErrorModalDefault(error, 'Error loading courses');
|
CoreDomUtils.showErrorModalDefault(error, 'Error loading courses');
|
||||||
|
|
||||||
this.courses.setItems([]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the list of courses.
|
|
||||||
*/
|
|
||||||
private async fetchCourses(): Promise<void> {
|
|
||||||
const grades = await CoreGrades.getCoursesGrades();
|
|
||||||
const courses = await CoreGradesHelper.getGradesCourseData(grades);
|
|
||||||
|
|
||||||
this.courses.setItems(courses);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class to manage courses.
|
* Helper class to manage courses.
|
||||||
*/
|
*/
|
||||||
class CoreGradesCoursesManager extends CorePageItemsListManager<CoreGradesGradeOverviewWithCourseData> {
|
class CoreGradesCoursesManager extends CoreListItemsManager {
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritdoc
|
|
||||||
*/
|
|
||||||
protected getItemPath(courseGrade: CoreGradesGradeOverviewWithCourseData): string {
|
|
||||||
return courseGrade.courseid.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
|
|
Loading…
Reference in New Issue