MOBILE-2975 blocks: Allow disabling blocks and always show courses

main
Dani Palou 2019-04-26 15:10:38 +02:00
parent c6e01bfa66
commit 8723e5b684
9 changed files with 356 additions and 246 deletions

View File

@ -15,6 +15,7 @@
import { CoreLoggerProvider } from '@providers/logger';
import { CoreSitesProvider } from '@providers/sites';
import { CoreEventsProvider } from '@providers/events';
import { CoreSite } from '@classes/site';
export interface CoreDelegateHandler {
/**
@ -272,10 +273,10 @@ export class CoreDelegate {
* Check if feature is enabled or disabled in the site, depending on the feature prefix and the handler name.
*
* @param {CoreDelegateHandler} handler Handler to check.
* @param {any} site Site to check.
* @return {boolean} Whether is enabled or disabled in site.
* @param {CoreSite} site Site to check.
* @return {boolean} Whether is enabled or disabled in site.
*/
protected isFeatureDisabled(handler: CoreDelegateHandler, site: any): boolean {
protected isFeatureDisabled(handler: CoreDelegateHandler, site: CoreSite): boolean {
return typeof this.featurePrefix != 'undefined' && site.isFeatureDisabled(this.featurePrefix + handler.name);
}

View File

@ -18,6 +18,7 @@ import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
import { CoreBlockDefaultHandler } from './default-block-handler';
import { CoreSite } from '@classes/site';
/**
* Interface that all blocks must implement.
@ -87,6 +88,30 @@ export class CoreBlockDelegate extends CoreDelegate {
super('CoreBlockDelegate', logger, sitesProvider, eventsProvider);
}
/**
* Check if blocks are disabled in a certain site.
*
* @param {CoreSite} [site] Site. If not defined, use current site.
* @return {boolean} Whether it's disabled.
*/
areBlocksDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('NoDelegate_SiteBlocks');
}
/**
* Check if blocks are disabled in a certain site.
*
* @param {string} [siteId] Site Id. If not defined, use current site.
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
*/
areBlocksDisabled(siteId?: string): Promise<boolean> {
return this.sitesProvider.getSite(siteId).then((site) => {
return this.areBlocksDisabledInSite(site);
});
}
/**
* Get the display data for a certain block.
*
@ -121,4 +146,15 @@ export class CoreBlockDelegate extends CoreDelegate {
isBlockSupported(name: string): boolean {
return this.hasHandler(name, true);
}
/**
* Check if feature is enabled or disabled in the site, depending on the feature prefix and the handler name.
*
* @param {CoreDelegateHandler} handler Handler to check.
* @param {CoreSite} site Site to check.
* @return {boolean} Whether is enabled or disabled in site.
*/
protected isFeatureDisabled(handler: CoreDelegateHandler, site: CoreSite): boolean {
return this.areBlocksDisabledInSite(site) || super.isFeatureDisabled(handler, site);
}
}

View File

@ -19,15 +19,17 @@ import { TranslateModule } from '@ngx-translate/core';
import { CoreComponentsModule } from '@components/components.module';
import { CoreDirectivesModule } from '@directives/directives.module';
import { CorePipesModule } from '@pipes/pipes.module';
import { CoreCoursesCourseProgressComponent } from '../components/course-progress/course-progress';
import { CoreCoursesCourseListItemComponent } from '../components/course-list-item/course-list-item';
import { CoreCoursesCourseOptionsMenuComponent } from '../components/course-options-menu/course-options-menu';
import { CoreCoursesCourseProgressComponent } from './course-progress/course-progress';
import { CoreCoursesCourseListItemComponent } from './course-list-item/course-list-item';
import { CoreCoursesCourseOptionsMenuComponent } from './course-options-menu/course-options-menu';
import { CoreCoursesMyCoursesComponent } from './my-courses/my-courses';
@NgModule({
declarations: [
CoreCoursesCourseProgressComponent,
CoreCoursesCourseListItemComponent,
CoreCoursesCourseOptionsMenuComponent
CoreCoursesCourseOptionsMenuComponent,
CoreCoursesMyCoursesComponent
],
imports: [
CommonModule,
@ -42,7 +44,8 @@ import { CoreCoursesCourseOptionsMenuComponent } from '../components/course-opti
exports: [
CoreCoursesCourseProgressComponent,
CoreCoursesCourseListItemComponent,
CoreCoursesCourseOptionsMenuComponent
CoreCoursesCourseOptionsMenuComponent,
CoreCoursesMyCoursesComponent
],
entryComponents: [
CoreCoursesCourseOptionsMenuComponent

View File

@ -0,0 +1,14 @@
<core-loading [hideUntil]="coursesLoaded">
<ion-searchbar #searchbar *ngIf="showFilter" [(ngModel)]="filter" (ionInput)="filterChanged($event)" (ionCancel)="filterChanged()" [placeholder]="'core.courses.filtermycourses' | translate">
</ion-searchbar>
<ion-grid no-padding>
<ion-row no-padding>
<ion-col *ngFor="let course of filteredCourses" no-padding col-12 col-sm-6 col-md-6 col-lg-4 col-xl-4 align-self-stretch>
<core-courses-course-progress [course]="course" class="core-courseoverview" showAll="true"></core-courses-course-progress>
</ion-col>
</ion-row>
</ion-grid>
<core-empty-box *ngIf="!courses || !courses.length" icon="ionic" [message]="'core.courses.nocourses' | translate">
<p *ngIf="searchEnabled">{{ 'core.courses.searchcoursesadvice' | translate }}</p>
</core-empty-box>
</core-loading>

View File

@ -0,0 +1,242 @@
// (C) Copyright 2015 Martin Dougiamas
//
// 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 { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Searchbar } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCoursesHelperProvider } from '../../providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
/**
* Component that displays the list of courses the user is enrolled in.
*/
@Component({
selector: 'core-courses-my-courses',
templateUrl: 'my-courses.html',
})
export class CoreCoursesMyCoursesComponent implements OnInit, OnDestroy {
@ViewChild('searchbar') searchbar: Searchbar;
courses: any[];
filteredCourses: any[];
searchEnabled: boolean;
filter = '';
showFilter = false;
coursesLoaded = false;
prefetchCoursesData: any = {};
downloadAllCoursesEnabled: boolean;
protected prefetchIconInitialized = false;
protected myCoursesObserver;
protected siteUpdatedObserver;
protected isDestroyed = false;
protected courseIds = '';
constructor(private coursesProvider: CoreCoursesProvider,
private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider,
private sitesProvider: CoreSitesProvider, private courseHelper: CoreCourseHelperProvider,
private courseOptionsDelegate: CoreCourseOptionsDelegate, private coursesHelper: CoreCoursesHelperProvider) { }
/**
* Component being initialized.
*/
ngOnInit(): void {
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
this.fetchCourses().finally(() => {
this.coursesLoaded = true;
});
this.myCoursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.fetchCourses();
}, this.sitesProvider.getCurrentSiteId());
// Refresh the enabled flags if site is updated.
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
const wasEnabled = this.downloadAllCoursesEnabled;
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
if (!wasEnabled && this.downloadAllCoursesEnabled && this.coursesLoaded) {
// Download all courses is enabled now, initialize it.
this.initPrefetchCoursesIcon();
}
}, this.sitesProvider.getCurrentSiteId());
}
/**
* Fetch the user courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchCourses(): Promise<any> {
return this.coursesProvider.getUserCourses().then((courses) => {
const promises = [],
courseIds = courses.map((course) => {
return course.id;
});
this.courseIds = courseIds.join(',');
promises.push(this.coursesHelper.loadCoursesExtraInfo(courses));
if (this.coursesProvider.canGetAdminAndNavOptions()) {
promises.push(this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => {
courses.forEach((course) => {
course.navOptions = options.navOptions[course.id];
course.admOptions = options.admOptions[course.id];
});
}));
}
return Promise.all(promises).then(() => {
this.courses = courses;
this.filteredCourses = this.courses;
this.filter = '';
this.initPrefetchCoursesIcon();
});
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
});
}
/**
* Refresh the courses.
*
* @param {any} refresher Refresher.
*/
refreshCourses(refresher: any): void {
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions());
if (this.courseIds) {
promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds));
}
Promise.all(promises).finally(() => {
this.prefetchIconInitialized = false;
this.fetchCourses().finally(() => {
refresher.complete();
});
});
}
/**
* Show or hide the filter.
*/
switchFilter(): void {
this.filter = '';
this.showFilter = !this.showFilter;
this.filteredCourses = this.courses;
if (this.showFilter) {
setTimeout(() => {
this.searchbar.setFocus();
}, 500);
}
}
/**
* The filter has changed.
*
* @param {any} Received Event.
*/
filterChanged(event: any): void {
const newValue = event.target.value && event.target.value.trim().toLowerCase();
if (!newValue || !this.courses) {
this.filteredCourses = this.courses;
} else {
// Use displayname if avalaible, or fullname if not.
if (this.courses.length > 0 && typeof this.courses[0].displayname != 'undefined') {
this.filteredCourses = this.courses.filter((course) => {
return course.displayname.toLowerCase().indexOf(newValue) > -1;
});
} else {
this.filteredCourses = this.courses.filter((course) => {
return course.fullname.toLowerCase().indexOf(newValue) > -1;
});
}
}
}
/**
* Prefetch all the courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
prefetchCourses(): Promise<any> {
const initialIcon = this.prefetchCoursesData.icon;
this.prefetchCoursesData.icon = 'spinner';
this.prefetchCoursesData.badge = '';
return this.courseHelper.confirmAndPrefetchCourses(this.courses, (progress) => {
this.prefetchCoursesData.badge = progress.count + ' / ' + progress.total;
}).then(() => {
this.prefetchCoursesData.icon = 'ion-android-refresh';
}).catch((error) => {
if (!this.isDestroyed) {
this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
this.prefetchCoursesData.icon = initialIcon;
}
}).finally(() => {
this.prefetchCoursesData.badge = '';
});
}
/**
* Initialize the prefetch icon for the list of courses.
*/
protected initPrefetchCoursesIcon(): void {
if (this.prefetchIconInitialized || !this.downloadAllCoursesEnabled) {
// Already initialized.
return;
}
this.prefetchIconInitialized = true;
if (!this.courses || this.courses.length < 2) {
// Not enough courses.
this.prefetchCoursesData.icon = '';
return;
}
this.courseHelper.determineCoursesStatus(this.courses).then((status) => {
let icon = this.courseHelper.getCourseStatusIconAndTitleFromStatus(status).icon;
if (icon == 'spinner') {
// It seems all courses are being downloaded, show a download button instead.
icon = 'cloud-download';
}
this.prefetchCoursesData.icon = icon;
});
}
/**
* Page destroyed.
*/
ngOnDestroy(): void {
this.isDestroyed = true;
this.myCoursesObserver && this.myCoursesObserver.off();
this.siteUpdatedObserver && this.siteUpdatedObserver.off();
}
}

View File

@ -7,7 +7,12 @@
<ion-icon name="search"></ion-icon>
</button>
<core-context-menu>
<core-context-menu-item *ngIf="downloadCourseEnabled || downloadCoursesEnabled" [priority]="1000" [content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item>
<!-- Action for dashboard and site home. -->
<core-context-menu-item *ngIf="(siteHomeEnabled || dashboardEnabled) && (downloadCourseEnabled || downloadCoursesEnabled)" [priority]="1000" [content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item>
<!-- Actions when both site home and dashboard are disabled. -->
<core-context-menu-item *ngIf="!siteHomeEnabled && !dashboardEnabled && mcComponent && mcComponent.downloadAllCoursesEnabled && mcComponent.courses && mcComponent.courses.length >= 2" [priority]="800" [content]="'core.courses.downloadcourses' | translate" (action)="mcComponent.prefetchCourses()" [iconAction]="mcComponent.prefetchCoursesData.icon" [closeOnClick]="false" [badge]="mcComponent.prefetchCoursesData.badge"></core-context-menu-item>
<core-context-menu-item *ngIf="!siteHomeEnabled && !dashboardEnabled && mcComponent && mcComponent.courses && mcComponent.courses.length > 5" [priority]="700" [content]="'core.courses.filtermycourses' | translate" (action)="mcComponent.switchFilter()" [iconAction]="'funnel'"></core-context-menu-item>
</core-context-menu>
</ion-buttons>
</ion-navbar>
@ -46,5 +51,17 @@
</ion-content>
</ng-template>
</core-tab>
<!-- Tab to display if both site home and dashboard are disabled. -->
<core-tab [show]="!siteHomeEnabled && !dashboardEnabled" [title]="'core.courses.mymoodle' | translate">
<ng-template>
<ion-content>
<ion-refresher [enabled]="mcComponent && mcComponent.coursesLoaded" (ionRefresh)="refreshMyCourses($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-courses-my-courses></core-courses-my-courses>
</ion-content>
</ng-template>
</core-tab>
</core-tabs>
</ion-content>

View File

@ -24,6 +24,7 @@ import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome';
import { CoreSiteHomeIndexComponent } from '@core/sitehome/components/index/index';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCoursesDashboardProvider } from '../../providers/dashboard';
import { CoreCoursesMyCoursesComponent } from '../../components/my-courses/my-courses';
/**
* Page that displays the dashboard.
@ -37,6 +38,7 @@ export class CoreCoursesDashboardPage implements OnDestroy {
@ViewChild(CoreTabsComponent) tabsComponent: CoreTabsComponent;
@ViewChild(CoreSiteHomeIndexComponent) siteHomeComponent: CoreSiteHomeIndexComponent;
@ViewChildren(CoreBlockComponent) blocksComponents: QueryList<CoreBlockComponent>;
@ViewChild(CoreCoursesMyCoursesComponent) mcComponent: CoreCoursesMyCoursesComponent;
firstSelectedTab: number;
siteHomeEnabled = false;
@ -186,6 +188,26 @@ export class CoreCoursesDashboardPage implements OnDestroy {
});
}
/**
* Refresh the dashboard data and My Courses.
*
* @param {any} refresher Refresher.
*/
refreshMyCourses(refresher: any): void {
// First of all, refresh dashboard blocks, maybe a new block was added and now we can display the dashboard.
this.dashboardProvider.invalidateDashboardBlocks().finally(() => {
return this.loadDashboardContent();
}).finally(() => {
if (!this.dashboardEnabled) {
// Dashboard still not enabled. Refresh my courses.
this.mcComponent && this.mcComponent.refreshCourses(refresher);
} else {
this.tabsComponent.selectTab(1);
refresher.complete();
}
});
}
/**
* Toggle download enabled.
*/

View File

@ -3,33 +3,20 @@
<ion-title>{{ 'core.courses.mycourses' | translate }}</ion-title>
<ion-buttons end>
<button *ngIf="searchEnabled" ion-button icon-only (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
<button *ngIf="mcComponent && mcComponent.searchEnabled" ion-button icon-only (click)="openSearch()" [attr.aria-label]="'core.courses.searchcourses' | translate">
<ion-icon name="search"></ion-icon>
</button>
<core-context-menu>
<core-context-menu-item [hidden]="!downloadAllCoursesEnabled || !courses || courses.length < 2" [priority]="800" [content]="'core.courses.downloadcourses' | translate" (action)="prefetchCourses()" [iconAction]="prefetchCoursesData.icon" [closeOnClick]="false" [badge]="prefetchCoursesData.badge"></core-context-menu-item>
<core-context-menu-item [hidden]="!courses || courses.length <= 5" [priority]="700" [content]="'core.courses.filtermycourses' | translate" (action)="switchFilter()" [iconAction]="'funnel'"></core-context-menu-item>
<core-context-menu *ngIf="mcComponent">
<core-context-menu-item [hidden]="!mcComponent.downloadAllCoursesEnabled || !mcComponent.courses || mcComponent.courses.length < 2" [priority]="800" [content]="'core.courses.downloadcourses' | translate" (action)="mcComponent.prefetchCourses()" [iconAction]="mcComponent.prefetchCoursesData.icon" [closeOnClick]="false" [badge]="mcComponent.prefetchCoursesData.badge"></core-context-menu-item>
<core-context-menu-item [hidden]="!mcComponent.courses || mcComponent.courses.length <= 5" [priority]="700" [content]="'core.courses.filtermycourses' | translate" (action)="mcComponent.switchFilter()" [iconAction]="'funnel'"></core-context-menu-item>
</core-context-menu>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-refresher [enabled]="coursesLoaded" (ionRefresh)="refreshCourses($event)">
<ion-refresher [enabled]="mcComponent && mcComponent.coursesLoaded" (ionRefresh)="mcComponent.refreshCourses($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="coursesLoaded">
<ion-searchbar #searchbar *ngIf="showFilter" [(ngModel)]="filter" (ionInput)="filterChanged($event)" (ionCancel)="filterChanged()" [placeholder]="'core.courses.filtermycourses' | translate">
</ion-searchbar>
<ion-grid no-padding>
<ion-row no-padding>
<ion-col *ngFor="let course of filteredCourses" no-padding col-12 col-sm-6 col-md-6 col-lg-4 col-xl-4 align-self-stretch>
<core-courses-course-progress [course]="course" class="core-courseoverview" showAll="true"></core-courses-course-progress>
</ion-col>
</ion-row>
</ion-grid>
<core-empty-box *ngIf="!courses || !courses.length" icon="ionic" [message]="'core.courses.nocourses' | translate">
<p *ngIf="searchEnabled">{{ 'core.courses.searchcoursesadvice' | translate }}</p>
</core-empty-box>
</core-loading>
<core-courses-my-courses></core-courses-my-courses>
</ion-content>

View File

@ -12,15 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, OnDestroy, ViewChild } from '@angular/core';
import { IonicPage, Searchbar, NavController } from 'ionic-angular';
import { CoreEventsProvider } from '@providers/events';
import { CoreSitesProvider } from '@providers/sites';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreCoursesProvider } from '../../providers/courses';
import { CoreCoursesHelperProvider } from '../../providers/helper';
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
import { Component, ViewChild } from '@angular/core';
import { IonicPage, NavController } from 'ionic-angular';
import { CoreCoursesMyCoursesComponent } from '../../components/my-courses/my-courses';
/**
* Page that displays the list of courses the user is enrolled in.
@ -30,131 +24,10 @@ import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delega
selector: 'page-core-courses-my-courses',
templateUrl: 'my-courses.html',
})
export class CoreCoursesMyCoursesPage implements OnDestroy {
@ViewChild('searchbar') searchbar: Searchbar;
export class CoreCoursesMyCoursesPage {
@ViewChild(CoreCoursesMyCoursesComponent) mcComponent: CoreCoursesMyCoursesComponent;
courses: any[];
filteredCourses: any[];
searchEnabled: boolean;
filter = '';
showFilter = false;
coursesLoaded = false;
prefetchCoursesData: any = {};
downloadAllCoursesEnabled: boolean;
protected prefetchIconInitialized = false;
protected myCoursesObserver;
protected siteUpdatedObserver;
protected isDestroyed = false;
protected courseIds = '';
constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider,
private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider,
private sitesProvider: CoreSitesProvider, private courseHelper: CoreCourseHelperProvider,
private courseOptionsDelegate: CoreCourseOptionsDelegate, private coursesHelper: CoreCoursesHelperProvider) { }
/**
* View loaded.
*/
ionViewDidLoad(): void {
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
this.fetchCourses().finally(() => {
this.coursesLoaded = true;
});
this.myCoursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
this.fetchCourses();
}, this.sitesProvider.getCurrentSiteId());
// Refresh the enabled flags if site is updated.
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
const wasEnabled = this.downloadAllCoursesEnabled;
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
if (!wasEnabled && this.downloadAllCoursesEnabled && this.coursesLoaded) {
// Download all courses is enabled now, initialize it.
this.initPrefetchCoursesIcon();
}
}, this.sitesProvider.getCurrentSiteId());
}
/**
* Fetch the user courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchCourses(): Promise<any> {
return this.coursesProvider.getUserCourses().then((courses) => {
const promises = [],
courseIds = courses.map((course) => {
return course.id;
});
this.courseIds = courseIds.join(',');
promises.push(this.coursesHelper.loadCoursesExtraInfo(courses));
if (this.coursesProvider.canGetAdminAndNavOptions()) {
promises.push(this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => {
courses.forEach((course) => {
course.navOptions = options.navOptions[course.id];
course.admOptions = options.admOptions[course.id];
});
}));
}
return Promise.all(promises).then(() => {
this.courses = courses;
this.filteredCourses = this.courses;
this.filter = '';
this.initPrefetchCoursesIcon();
});
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true);
});
}
/**
* Refresh the courses.
*
* @param {any} refresher Refresher.
*/
refreshCourses(refresher: any): void {
const promises = [];
promises.push(this.coursesProvider.invalidateUserCourses());
promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions());
if (this.courseIds) {
promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds));
}
Promise.all(promises).finally(() => {
this.prefetchIconInitialized = false;
this.fetchCourses().finally(() => {
refresher.complete();
});
});
}
/**
* Show or hide the filter.
*/
switchFilter(): void {
this.filter = '';
this.showFilter = !this.showFilter;
this.filteredCourses = this.courses;
if (this.showFilter) {
setTimeout(() => {
this.searchbar.setFocus();
}, 500);
}
}
constructor(private navCtrl: NavController) { }
/**
* Go to search courses.
@ -162,89 +35,4 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
openSearch(): void {
this.navCtrl.push('CoreCoursesSearchPage');
}
/**
* The filter has changed.
*
* @param {any} Received Event.
*/
filterChanged(event: any): void {
const newValue = event.target.value && event.target.value.trim().toLowerCase();
if (!newValue || !this.courses) {
this.filteredCourses = this.courses;
} else {
// Use displayname if avalaible, or fullname if not.
if (this.courses.length > 0 && typeof this.courses[0].displayname != 'undefined') {
this.filteredCourses = this.courses.filter((course) => {
return course.displayname.toLowerCase().indexOf(newValue) > -1;
});
} else {
this.filteredCourses = this.courses.filter((course) => {
return course.fullname.toLowerCase().indexOf(newValue) > -1;
});
}
}
}
/**
* Prefetch all the courses.
*
* @return {Promise<any>} Promise resolved when done.
*/
prefetchCourses(): Promise<any> {
const initialIcon = this.prefetchCoursesData.icon;
this.prefetchCoursesData.icon = 'spinner';
this.prefetchCoursesData.badge = '';
return this.courseHelper.confirmAndPrefetchCourses(this.courses, (progress) => {
this.prefetchCoursesData.badge = progress.count + ' / ' + progress.total;
}).then(() => {
this.prefetchCoursesData.icon = 'ion-android-refresh';
}).catch((error) => {
if (!this.isDestroyed) {
this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
this.prefetchCoursesData.icon = initialIcon;
}
}).finally(() => {
this.prefetchCoursesData.badge = '';
});
}
/**
* Initialize the prefetch icon for the list of courses.
*/
protected initPrefetchCoursesIcon(): void {
if (this.prefetchIconInitialized || !this.downloadAllCoursesEnabled) {
// Already initialized.
return;
}
this.prefetchIconInitialized = true;
if (!this.courses || this.courses.length < 2) {
// Not enough courses.
this.prefetchCoursesData.icon = '';
return;
}
this.courseHelper.determineCoursesStatus(this.courses).then((status) => {
let icon = this.courseHelper.getCourseStatusIconAndTitleFromStatus(status).icon;
if (icon == 'spinner') {
// It seems all courses are being downloaded, show a download button instead.
icon = 'cloud-download';
}
this.prefetchCoursesData.icon = icon;
});
}
/**
* Page destroyed.
*/
ngOnDestroy(): void {
this.isDestroyed = true;
this.myCoursesObserver && this.myCoursesObserver.off();
this.siteUpdatedObserver && this.siteUpdatedObserver.off();
}
}