MOBILE-2341 core: Support split views in course formats

main
Albert Gasset 2018-05-11 19:22:22 +02:00
parent bc71bbbdfc
commit b34adcaa42
9 changed files with 129 additions and 35 deletions

View File

@ -84,25 +84,6 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR
} }
} }
/**
* Refresh the data.
*
* @param {any} [refresher] Refresher.
* @param {Function} [done] Function to call when done.
* @param {boolean} [showErrors=false] If show errors to the user of hide them.
* @return {Promise<any>} Promise resolved when done.
*/
doRefresh(refresher?: any, done?: () => void, showErrors: boolean = false): Promise<any> {
if (this.loaded) {
return this.refreshContent(true, showErrors).finally(() => {
refresher && refresher.complete();
done && done();
});
}
return Promise.resolve();
}
/** /**
* Compares sync event data with current data to check if refresh content is needed. * Compares sync event data with current data to check if refresh content is needed.
* *

View File

@ -17,7 +17,8 @@ import { TranslateService } from '@ngx-translate/core';
import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreCourseModuleMainComponent } from '@core/course/providers/module-delegate'; import { CoreCourseModuleMainComponent, CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
import { CoreCourseSectionPage } from '@core/course/pages/section/section.ts';
/** /**
* Template class to easily create CoreCourseModuleMainComponent of resources (or activities without syncing). * Template class to easily create CoreCourseModuleMainComponent of resources (or activities without syncing).
@ -50,12 +51,16 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
protected courseHelper: CoreCourseHelperProvider; protected courseHelper: CoreCourseHelperProvider;
protected translate: TranslateService; protected translate: TranslateService;
protected domUtils: CoreDomUtilsProvider; protected domUtils: CoreDomUtilsProvider;
protected moduleDelegate: CoreCourseModuleDelegate;
protected courseSectionPage: CoreCourseSectionPage;
constructor(injector: Injector) { constructor(injector: Injector) {
this.textUtils = injector.get(CoreTextUtilsProvider); this.textUtils = injector.get(CoreTextUtilsProvider);
this.courseHelper = injector.get(CoreCourseHelperProvider); this.courseHelper = injector.get(CoreCourseHelperProvider);
this.translate = injector.get(TranslateService); this.translate = injector.get(TranslateService);
this.domUtils = injector.get(CoreDomUtilsProvider); this.domUtils = injector.get(CoreDomUtilsProvider);
this.moduleDelegate = injector.get(CoreCourseModuleDelegate);
this.courseSectionPage = injector.get(CoreCourseSectionPage, null);
this.dataRetrieved = new EventEmitter(); this.dataRetrieved = new EventEmitter();
} }
@ -73,15 +78,27 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
/** /**
* Refresh the data. * Refresh the data.
* *
* @param {any} [refresher] Refresher. * @param {any} [refresher] Refresher.
* @param {Function} [done] Function to call when done. * @param {Function} [done] Function to call when done.
* @param {boolean} [showErrors=false] If show errors to the user of hide them.
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
doRefresh(refresher?: any, done?: () => void): Promise<any> { doRefresh(refresher?: any, done?: () => void, showErrors: boolean = false): Promise<any> {
if (this.loaded) { if (this.loaded) {
return this.refreshContent().finally(() => { /* If it's a single activity course and the refresher is displayed within the component,
refresher && refresher.complete(); call doRefresh on the section page to refresh the course data. */
done && done(); let promise;
if (this.courseSectionPage && !this.moduleDelegate.displayRefresherInSingleActivity(this.module.modname)) {
promise = this.courseSectionPage.doRefresh();
} else {
promise = Promise.resolve();
}
return promise.finally(() => {
return this.refreshContent(true, showErrors).finally(() => {
refresher && refresher.complete();
done && done();
});
}); });
} }
@ -91,9 +108,11 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
/** /**
* Perform the refresh content function. * Perform the refresh content function.
* *
* @param {boolean} [sync=false] If the refresh needs syncing.
* @param {boolean} [showErrors=false] Wether to show errors to the user or hide them.
* @return {Promise<any>} Resolved when done. * @return {Promise<any>} Resolved when done.
*/ */
protected refreshContent(): Promise<any> { protected refreshContent(sync: boolean = false, showErrors: boolean = false): Promise<any> {
this.refreshIcon = 'spinner'; this.refreshIcon = 'spinner';
return this.invalidateContent().catch(() => { return this.invalidateContent().catch(() => {

View File

@ -14,6 +14,7 @@
import { Injectable, Injector } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { CoreCourseFormatHandler } from '../../../providers/format-delegate'; import { CoreCourseFormatHandler } from '../../../providers/format-delegate';
import { CoreCourseModuleDelegate } from '../../../providers/module-delegate';
import { CoreCourseFormatSingleActivityComponent } from '../components/singleactivity'; import { CoreCourseFormatSingleActivityComponent } from '../components/singleactivity';
/** /**
@ -24,7 +25,7 @@ export class CoreCourseFormatSingleActivityHandler implements CoreCourseFormatHa
name = 'CoreCourseFormatSingleActivity'; name = 'CoreCourseFormatSingleActivity';
format = 'singleactivity'; format = 'singleactivity';
constructor() { constructor(private moduleDelegate: CoreCourseModuleDelegate) {
// Nothing to do. // Nothing to do.
} }
@ -83,6 +84,22 @@ export class CoreCourseFormatSingleActivityHandler implements CoreCourseFormatHa
return false; return false;
} }
/**
* Whether the course refresher should be displayed. If it returns false, a refresher must be included in the course format,
* and the doRefresh method of CoreCourseSectionPage must be called on refresh. Defaults to true.
*
* @param {any} course The course to check.
* @param {any[]} sections List of course sections.
* @return {boolean} Whether the refresher should be displayed.
*/
displayRefresher(course: any, sections: any[]): boolean {
if (sections && sections[0] && sections[0].modules) {
return this.moduleDelegate.displayRefresherInSingleActivity(sections[0].modules[0].modname);
} else {
return true;
}
}
/** /**
* Return the Component to use to display the course format instead of using the default one. * Return the Component to use to display the course format instead of using the default one.
* Use it if you want to display a format completely different from the default one. * Use it if you want to display a format completely different from the default one.

View File

@ -17,7 +17,7 @@
</core-context-menu> </core-context-menu>
</core-navbar-buttons> </core-navbar-buttons>
<ion-content> <ion-content>
<ion-refresher [enabled]="dataLoaded" (ionRefresh)="doRefresh($event)"> <ion-refresher [enabled]="dataLoaded && displayRefresher" (ionRefresh)="doRefresh($event)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher> </ion-refresher>

View File

@ -54,6 +54,7 @@ export class CoreCourseSectionPage implements OnDestroy {
}; };
moduleId: number; moduleId: number;
displayEnableDownload: boolean; displayEnableDownload: boolean;
displayRefresher: boolean;
protected module: any; protected module: any;
protected completionObserver; protected completionObserver;
@ -188,6 +189,9 @@ export class CoreCourseSectionPage implements OnDestroy {
// Get the title again now that we have sections. // Get the title again now that we have sections.
this.title = this.courseFormatDelegate.getCourseTitle(this.course, this.sections); this.title = this.courseFormatDelegate.getCourseTitle(this.course, this.sections);
// Get whether to show the refresher now that we have sections.
this.displayRefresher = this.courseFormatDelegate.displayRefresher(this.course, this.sections);
}); });
})); }));
@ -212,13 +216,23 @@ export class CoreCourseSectionPage implements OnDestroy {
/** /**
* Refresh the data. * Refresh the data.
* *
* @param {any} refresher Refresher. * @param {any} [refresher] Refresher.
* @return {Promise<any>} Promise resolved when done.
*/ */
doRefresh(refresher: any): void { doRefresh(refresher?: any): Promise<any> {
this.invalidateData().finally(() => { return this.invalidateData().finally(() => {
this.loadData(true).finally(() => { return this.loadData(true).finally(() => {
this.formatComponent.doRefresh(refresher).finally(() => { /* Do not call doRefresh on the format component if the refresher is defined in the format component
refresher.complete(); to prevent an inifinite loop. */
let promise;
if (this.displayRefresher) {
promise = this.formatComponent.doRefresh(refresher);
} else {
promise = Promise.resolve();
}
return promise.finally(() => {
refresher && refresher.complete();
}); });
}); });
}); });

View File

@ -77,6 +77,18 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
return true; return true;
} }
/**
* Whether the course refresher should be displayed. If it returns false, a refresher must be included in the course format,
* and the doRefresh method of CoreCourseSectionPage must be called on refresh. Defaults to true.
*
* @param {any} course The course to check.
* @param {any[]} sections List of course sections.
* @return {boolean} Whether the refresher should be displayed.
*/
displayRefresher?(course: any, sections: any[]): boolean {
return true;
}
/** /**
* Given a list of sections, get the "current" section that should be displayed first. * Given a list of sections, get the "current" section that should be displayed first.
* *

View File

@ -89,4 +89,14 @@ export class CoreCourseModuleDefaultHandler implements CoreCourseModuleHandler {
// We can't inject CoreCourseUnsupportedModuleComponent here due to circular dependencies. // We can't inject CoreCourseUnsupportedModuleComponent here due to circular dependencies.
// Don't return anything, by default it will use CoreCourseUnsupportedModuleComponent. // Don't return anything, by default it will use CoreCourseUnsupportedModuleComponent.
} }
/**
* Whether to display the course refresher in single activity course format. If it returns false, a refresher must be
* included in the template that calls the doRefresh method of the component. Defaults to true.
*
* @return {boolean} Whether the refresher should be displayed.
*/
displayRefresherInSingleActivity(): boolean {
return true;
}
} }

View File

@ -65,6 +65,16 @@ export interface CoreCourseFormatHandler extends CoreDelegateHandler {
*/ */
displaySectionSelector?(course: any): boolean; displaySectionSelector?(course: any): boolean;
/**
* Whether the course refresher should be displayed. If it returns false, a refresher must be included in the course format,
* and the doRefresh method of CoreCourseSectionPage must be called on refresh. Defaults to true.
*
* @param {any} course The course to check.
* @param {any[]} sections List of course sections.
* @type {boolean} Whether the refresher should be displayed.
*/
displayRefresher?(course: any, sections: any[]): boolean;
/** /**
* Given a list of sections, get the "current" section that should be displayed first. Defaults to first section. * Given a list of sections, get the "current" section that should be displayed first. Defaults to first section.
* *
@ -183,6 +193,18 @@ export class CoreCourseFormatDelegate extends CoreDelegate {
return this.executeFunctionOnEnabled(course.format, 'displayEnableDownload', [course]); return this.executeFunctionOnEnabled(course.format, 'displayEnableDownload', [course]);
} }
/**
* Whether the course refresher should be displayed. If it returns false, a refresher must be included in the course format,
* and the doRefresh method of CoreCourseSectionPage must be called on refresh. Defaults to true.
*
* @param {any} course The course to check.
* @param {any[]} sections List of course sections.
* @return {boolean} Whether the refresher should be displayed.
*/
displayRefresher(course: any, sections: any[]): boolean {
return this.executeFunctionOnEnabled(course.format, 'displayRefresher', [course, sections]);
}
/** /**
* Whether the default section selector should be displayed. Defaults to true. * Whether the default section selector should be displayed. Defaults to true.
* *

View File

@ -53,6 +53,14 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler {
* @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found. * @return {any|Promise<any>} The component (or promise resolved with component) to use, undefined if not found.
*/ */
getMainComponent(injector: Injector, course: any, module: any): any | Promise<any>; getMainComponent(injector: Injector, course: any, module: any): any | Promise<any>;
/**
* Whether to display the course refresher in single activity course format. If it returns false, a refresher must be
* included in the template that calls the doRefresh method of the component. Defaults to true.
*
* @return {boolean} Whether the refresher should be displayed.
*/
displayRefresherInSingleActivity?(): boolean;
} }
/** /**
@ -247,4 +255,15 @@ export class CoreCourseModuleDelegate extends CoreDelegate {
return false; return false;
} }
/**
* Whether to display the course refresher in single activity course format. If it returns false, a refresher must be
* included in the template that calls the doRefresh method of the component. Defaults to true.
*
* @param {any} modname The name of the module type.
* @return {boolean} Whether the refresher should be displayed.
*/
displayRefresherInSingleActivity(modname: string): boolean {
return this.executeFunctionOnEnabled(modname, 'displayRefresherInSingleActivity');
}
} }