Merge pull request #1850 from sammarshallou/MOBILE-2906
MOBILE-2906 Add course option type that appears in menu
This commit is contained in:
		
						commit
						839fe09fa7
					
				| @ -15,6 +15,7 @@ | ||||
|                         <core-context-menu-item *ngIf="displayEnableDownload" [priority]="2000" [content]="'core.settings.showdownloadoptions' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item> | ||||
|                         <core-context-menu-item [hidden]="!downloadCourseEnabled" [priority]="1900" [content]="prefetchCourseData.title | translate" (action)="prefetchCourse()" [iconAction]="prefetchCourseData.prefetchCourseIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|                         <core-context-menu-item [priority]="1800" [content]="'core.course.coursesummary' | translate" (action)="openCourseSummary()" iconAction="fa-graduation-cap"></core-context-menu-item> | ||||
|                         <core-context-menu-item *ngFor="let item of courseMenuHandlers" [priority]="item.priority" (action)="openMenuItem(item)" [content]="item.data.title | translate" [iconAction]="item.data.icon" [class]="item.data.class"></core-context-menu-item> | ||||
|                     </core-context-menu> | ||||
|                 </core-navbar-buttons> | ||||
|                 <ion-content #courseSectionContent> | ||||
|  | ||||
| @ -24,7 +24,8 @@ import { CoreCourseProvider } from '../../providers/course'; | ||||
| import { CoreCourseHelperProvider } from '../../providers/helper'; | ||||
| import { CoreCourseFormatDelegate } from '../../providers/format-delegate'; | ||||
| import { CoreCourseModulePrefetchDelegate } from '../../providers/module-prefetch-delegate'; | ||||
| import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from '../../providers/options-delegate'; | ||||
| import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay, | ||||
|     CoreCourseOptionsMenuHandlerToDisplay } from '../../providers/options-delegate'; | ||||
| import { CoreCourseSyncProvider } from '../../providers/sync'; | ||||
| import { CoreCourseFormatComponent } from '../../components/format/format'; | ||||
| import { CoreCoursesProvider } from '@core/courses/providers/courses'; | ||||
| @ -49,6 +50,7 @@ export class CoreCourseSectionPage implements OnDestroy { | ||||
|     sectionId: number; | ||||
|     sectionNumber: number; | ||||
|     courseHandlers: CoreCourseOptionsHandlerToDisplay[]; | ||||
|     courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[] = []; | ||||
|     dataLoaded: boolean; | ||||
|     downloadEnabled: boolean; | ||||
|     downloadEnabledIcon = 'square-outline'; // Disabled by default.
 | ||||
| @ -301,6 +303,11 @@ export class CoreCourseSectionPage implements OnDestroy { | ||||
|                 } | ||||
|             })); | ||||
| 
 | ||||
|             // Load the course menu handlers.
 | ||||
|             promises.push(this.courseOptionsDelegate.getMenuHandlersToDisplay(this.injector, this.course).then((handlers) => { | ||||
|                 this.courseMenuHandlers = handlers; | ||||
|             })); | ||||
| 
 | ||||
|             // Load the course format options when course completion is enabled to show completion progress on sections.
 | ||||
|             if (this.course.enablecompletion && this.coursesProvider.isGetCoursesByFieldAvailable()) { | ||||
|                 promises.push(this.coursesProvider.getCourseByField('id', this.course.id).catch(() => { | ||||
| @ -417,7 +424,8 @@ export class CoreCourseSectionPage implements OnDestroy { | ||||
|      * Prefetch the whole course. | ||||
|      */ | ||||
|     prefetchCourse(): void { | ||||
|         this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course, this.sections, this.courseHandlers) | ||||
|         this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course, this.sections, | ||||
|                 this.courseHandlers, this.courseMenuHandlers) | ||||
|                 .then(() => { | ||||
|             if (this.downloadEnabled) { | ||||
|                 // Recalculate the status.
 | ||||
| @ -459,6 +467,16 @@ export class CoreCourseSectionPage implements OnDestroy { | ||||
|         this.navCtrl.push('CoreCoursesCoursePreviewPage', {course: this.course, avoidOpenCourse: true}); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Opens a menu item registered to the delegate. | ||||
|      * | ||||
|      * @param {CoreCourseMenuHandlerToDisplay} item Item to open | ||||
|      */ | ||||
|     openMenuItem(item: CoreCourseOptionsMenuHandlerToDisplay): void { | ||||
|         const params = Object.assign({ course: this.course}, item.data.pageParams); | ||||
|         this.navCtrl.push(item.data.page, params); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Page destroyed. | ||||
|      */ | ||||
|  | ||||
| @ -25,7 +25,8 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||
| import { CoreTimeUtilsProvider } from '@providers/utils/time'; | ||||
| import { CoreUtilsProvider } from '@providers/utils/utils'; | ||||
| import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay } from './options-delegate'; | ||||
| import { CoreCourseOptionsDelegate, CoreCourseOptionsHandlerToDisplay, | ||||
|     CoreCourseOptionsMenuHandlerToDisplay } from './options-delegate'; | ||||
| import { CoreSiteHomeProvider } from '@core/sitehome/providers/sitehome'; | ||||
| import { CoreCoursesProvider } from '@core/courses/providers/courses'; | ||||
| import { CoreCourseProvider } from './course'; | ||||
| @ -270,10 +271,11 @@ export class CoreCourseHelperProvider { | ||||
|      * @param {any} course Course to prefetch. | ||||
|      * @param {any[]} [sections] List of course sections. | ||||
|      * @param {CoreCourseOptionsHandlerToDisplay[]} courseHandlers List of course handlers. | ||||
|      * @param {CoreCourseOptionsMenuHandlerToDisplay[]} menuHandlers List of course menu handlers. | ||||
|      * @return {Promise<boolean>} Promise resolved when the download finishes, rejected if an error occurs or the user cancels. | ||||
|      */ | ||||
|     confirmAndPrefetchCourse(data: any, course: any, sections?: any[], courseHandlers?: CoreCourseOptionsHandlerToDisplay[]) | ||||
|             : Promise<boolean> { | ||||
|     confirmAndPrefetchCourse(data: any, course: any, sections?: any[], courseHandlers?: CoreCourseOptionsHandlerToDisplay[], | ||||
|             menuHandlers?: CoreCourseOptionsMenuHandlerToDisplay[]): Promise<boolean> { | ||||
| 
 | ||||
|         const initialIcon = data.prefetchCourseIcon, | ||||
|             initialTitle = data.title, | ||||
| @ -295,15 +297,23 @@ export class CoreCourseHelperProvider { | ||||
|             // Confirm the download.
 | ||||
|             return this.confirmDownloadSizeSection(course.id, undefined, sections, true).then(() => { | ||||
|                 // User confirmed, get the course handlers if needed.
 | ||||
|                 if (courseHandlers) { | ||||
|                     promise = Promise.resolve(courseHandlers); | ||||
|                 } else { | ||||
|                     promise = this.courseOptionsDelegate.getHandlersToDisplay(this.injector, course); | ||||
|                 const subPromises = []; | ||||
|                 if (!courseHandlers) { | ||||
|                     subPromises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.injector, course) | ||||
|                         .then((cHandlers) => { | ||||
|                         courseHandlers = cHandlers; | ||||
|                     })); | ||||
|                 } | ||||
|                 if (!menuHandlers) { | ||||
|                     subPromises.push(this.courseOptionsDelegate.getMenuHandlersToDisplay(this.injector, course) | ||||
|                         .then((mHandlers) => { | ||||
|                         menuHandlers = mHandlers; | ||||
|                     })); | ||||
|                 } | ||||
| 
 | ||||
|                 return promise.then((handlers: CoreCourseOptionsHandlerToDisplay[]) => { | ||||
|                 return Promise.all(subPromises).then(() => { | ||||
|                     // Now we have all the data, download the course.
 | ||||
|                     return this.prefetchCourse(course, sections, handlers, siteId); | ||||
|                     return this.prefetchCourse(course, sections, courseHandlers, menuHandlers, siteId); | ||||
|                 }).then(() => { | ||||
|                     // Download successful.
 | ||||
|                     return true; | ||||
| @ -338,6 +348,7 @@ export class CoreCourseHelperProvider { | ||||
|                 const subPromises = []; | ||||
|                 let sections, | ||||
|                     handlers, | ||||
|                     menuHandlers, | ||||
|                     success = true; | ||||
| 
 | ||||
|                 // Get the sections and the handlers.
 | ||||
| @ -347,9 +358,12 @@ export class CoreCourseHelperProvider { | ||||
|                 subPromises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.injector, course).then((cHandlers) => { | ||||
|                     handlers = cHandlers; | ||||
|                 })); | ||||
|                 subPromises.push(this.courseOptionsDelegate.getMenuHandlersToDisplay(this.injector, course).then((mHandlers) => { | ||||
|                     menuHandlers = mHandlers; | ||||
|                 })); | ||||
| 
 | ||||
|                 promises.push(Promise.all(subPromises).then(() => { | ||||
|                     return this.prefetchCourse(course, sections, handlers, siteId); | ||||
|                     return this.prefetchCourse(course, sections, handlers, menuHandlers, siteId); | ||||
|                 }).catch((error) => { | ||||
|                     success = false; | ||||
| 
 | ||||
| @ -1187,11 +1201,12 @@ export class CoreCourseHelperProvider { | ||||
|      * @param {any} course The course to prefetch. | ||||
|      * @param {any[]} sections List of course sections. | ||||
|      * @param {CoreCourseOptionsHandlerToDisplay[]} courseHandlers List of course options handlers. | ||||
|      * @param {CoreCourseOptionsMenuHandlerToDisplay[]} courseMenuHandlers List of course menu handlers. | ||||
|      * @param {string} [siteId] Site ID. If not defined, current site. | ||||
|      * @return {Promise}                Promise resolved when the download finishes. | ||||
|      */ | ||||
|     prefetchCourse(course: any, sections: any[], courseHandlers: CoreCourseOptionsHandlerToDisplay[], siteId?: string) | ||||
|             : Promise<any> { | ||||
|     prefetchCourse(course: any, sections: any[], courseHandlers: CoreCourseOptionsHandlerToDisplay[], | ||||
|            courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[], siteId?: string): Promise<any> { | ||||
|         siteId = siteId || this.sitesProvider.getCurrentSiteId(); | ||||
| 
 | ||||
|         if (this.courseDwnPromises[siteId] && this.courseDwnPromises[siteId][course.id]) { | ||||
| @ -1220,6 +1235,11 @@ export class CoreCourseHelperProvider { | ||||
|                     promises.push(handler.prefetch(course)); | ||||
|                 } | ||||
|             }); | ||||
|             courseMenuHandlers.forEach((handler) => { | ||||
|                 if (handler.prefetch) { | ||||
|                     promises.push(handler.prefetch(course)); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|             // Prefetch other data needed to render the course.
 | ||||
|             if (this.coursesProvider.isGetCoursesByFieldAvailable()) { | ||||
|  | ||||
| @ -31,6 +31,12 @@ export interface CoreCourseOptionsHandler extends CoreDelegateHandler { | ||||
|      */ | ||||
|     priority: number; | ||||
| 
 | ||||
|     /** | ||||
|      * True if this handler should appear in menu rather than as a tab. | ||||
|      * @type {boolean} | ||||
|      */ | ||||
|     isMenuHandler?: boolean; | ||||
| 
 | ||||
|     /** | ||||
|      * Whether or not the handler is enabled for a certain course. | ||||
|      * | ||||
| @ -70,6 +76,21 @@ export interface CoreCourseOptionsHandler extends CoreDelegateHandler { | ||||
|     prefetch?(course: any): Promise<any>; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Interface that course options handlers implement if they appear in the menu rather than as a tab. | ||||
|  */ | ||||
| export interface CoreCourseOptionsMenuHandler extends CoreCourseOptionsHandler { | ||||
|     /** | ||||
|      * Returns the data needed to render the handler. | ||||
|      * | ||||
|      * @param {Injector} injector Injector. | ||||
|      * @param {number} courseId The course ID. | ||||
|      * @return {CoreCourseOptionsMenuHandlerData|Promise<CoreCourseOptionsMenuHandlerData>} Data or promise resolved with data. | ||||
|      */ | ||||
|     getMenuDisplayData(injector: Injector, courseId: number): | ||||
|         CoreCourseOptionsMenuHandlerData | Promise<CoreCourseOptionsMenuHandlerData>; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Data needed to render a course handler. It's returned by the handler. | ||||
|  */ | ||||
| @ -99,6 +120,41 @@ export interface CoreCourseOptionsHandlerData { | ||||
|     componentData?: any; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Data needed to render a course menu handler. It's returned by the handler. | ||||
|  */ | ||||
| export interface CoreCourseOptionsMenuHandlerData { | ||||
|     /** | ||||
|      * Title to display for the handler. | ||||
|      * @type {string} | ||||
|      */ | ||||
|     title: string; | ||||
| 
 | ||||
|     /** | ||||
|      * Class to add to the displayed handler. | ||||
|      * @type {string} | ||||
|      */ | ||||
|     class?: string; | ||||
| 
 | ||||
|     /** | ||||
|      * Name of the page to load for the handler. | ||||
|      * @type {string} | ||||
|      */ | ||||
|     page: string; | ||||
| 
 | ||||
|     /** | ||||
|      * Params to pass to the page (other than 'course' which is always sent). | ||||
|      * @type {any} | ||||
|      */ | ||||
|     pageParams?: any; | ||||
| 
 | ||||
|     /** | ||||
|      * Name of the icon to display for the handler. | ||||
|      * @type {string} | ||||
|      */ | ||||
|     icon: string; // Name of the icon to display in the tab.
 | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Data returned by the delegate for each handler. | ||||
|  */ | ||||
| @ -130,6 +186,37 @@ export interface CoreCourseOptionsHandlerToDisplay { | ||||
|     prefetch?(course: any): Promise<any>; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Additional data returned if it is a menu item. | ||||
|  */ | ||||
| export interface CoreCourseOptionsMenuHandlerToDisplay { | ||||
|     /** | ||||
|      * Data to display. | ||||
|      * @type {CoreCourseOptionsMenuHandlerData} | ||||
|      */ | ||||
|     data: CoreCourseOptionsMenuHandlerData; | ||||
| 
 | ||||
|     /** | ||||
|      * Name of the handler, or name and sub context (AddonMessages, AddonMessages:blockContact, ...). | ||||
|      * @type {string} | ||||
|      */ | ||||
|     name: string; | ||||
| 
 | ||||
|     /** | ||||
|      * The highest priority is displayed first. | ||||
|      * @type {number} | ||||
|      */ | ||||
|     priority?: number; | ||||
| 
 | ||||
|     /** | ||||
|      * Called when a course is downloaded. It should prefetch all the data to be able to see the addon in offline. | ||||
|      * | ||||
|      * @param {any} course The course. | ||||
|      * @return {Promise<any>} Promise resolved when done. | ||||
|      */ | ||||
|     prefetch?(course: any): Promise<any>; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Service to interact with plugins to be shown in each course (participants, learning plans, ...). | ||||
|  */ | ||||
| @ -139,7 +226,8 @@ export class CoreCourseOptionsDelegate extends CoreDelegate { | ||||
|     protected lastUpdateHandlersForCoursesStart: any = {}; | ||||
|     protected coursesHandlers: { | ||||
|         [courseId: number]: { | ||||
|             access?: any, navOptions?: any, admOptions?: any, deferred?: PromiseDefer, enabledHandlers?: CoreCourseOptionsHandler[] | ||||
|             access?: any, navOptions?: any, admOptions?: any, deferred?: PromiseDefer, | ||||
|             enabledHandlers?: CoreCourseOptionsHandler[], enabledMenuHandlers?: CoreCourseOptionsMenuHandler[] | ||||
|         } | ||||
|     } = {}; | ||||
| 
 | ||||
| @ -258,6 +346,43 @@ export class CoreCourseOptionsDelegate extends CoreDelegate { | ||||
|      */ | ||||
|     getHandlersToDisplay(injector: Injector, course: any, refresh?: boolean, isGuest?: boolean, navOptions?: any, admOptions?: any): | ||||
|             Promise<CoreCourseOptionsHandlerToDisplay[]> { | ||||
|         return <Promise<CoreCourseOptionsHandlerToDisplay[]>> this.getHandlersToDisplayInternal( | ||||
|                 false, injector, course, refresh, isGuest, navOptions, admOptions); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the list of menu handlers that should be displayed for a course. | ||||
|      * This function should be called only when the handlers need to be displayed, since it can call several WebServices. | ||||
|      * | ||||
|      * @param {Injector} injector Injector. | ||||
|      * @param {any} course The course object. | ||||
|      * @param {boolean} [refresh] True if it should refresh the list. | ||||
|      * @param {boolean} [isGuest] Whether it's guest. | ||||
|      * @param {any} [navOptions] Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions. | ||||
|      * @param {any} [admOptions] Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. | ||||
|      * @return {Promise<CoreCourseOptionsMenuHandlerToDisplay[]>} Promise resolved with array of handlers. | ||||
|      */ | ||||
|     getMenuHandlersToDisplay(injector: Injector, course: any, refresh?: boolean, isGuest?: boolean, | ||||
|             navOptions?: any, admOptions?: any): Promise<CoreCourseOptionsMenuHandlerToDisplay[]> { | ||||
|         return <Promise<CoreCourseOptionsMenuHandlerToDisplay[]>> this.getHandlersToDisplayInternal( | ||||
|                 true, injector, course, refresh, isGuest, navOptions, admOptions); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get the list of menu handlers that should be displayed for a course. | ||||
|      * This function should be called only when the handlers need to be displayed, since it can call several WebServices. | ||||
|      * | ||||
|      * @param {boolean} menu If true, gets menu handlers; false, gets tab handlers | ||||
|      * @param {Injector} injector Injector. | ||||
|      * @param {any} course The course object. | ||||
|      * @param {boolean} refresh True if it should refresh the list. | ||||
|      * @param {boolean} isGuest Whether it's guest. | ||||
|      * @param {any} navOptions Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions. | ||||
|      * @param {any} admOptions Course admin options for current user. See CoreCoursesProvider.getUserAdministrationOptions. | ||||
|      * @return {Promise<any[]>} Promise resolved with array of handlers. | ||||
|      */ | ||||
|     protected getHandlersToDisplayInternal(menu: boolean, injector: Injector, course: any, refresh: boolean, isGuest: boolean, | ||||
|             navOptions: any, admOptions: any): Promise<any[]> { | ||||
|         course.id = parseInt(course.id, 10); | ||||
| 
 | ||||
|         const accessData = { | ||||
| @ -278,8 +403,16 @@ export class CoreCourseOptionsDelegate extends CoreDelegate { | ||||
|         }).then(() => { | ||||
|             const promises = []; | ||||
| 
 | ||||
|             this.coursesHandlers[course.id].enabledHandlers.forEach((handler) => { | ||||
|                 promises.push(Promise.resolve(handler.getDisplayData(injector, course)).then((data) => { | ||||
|             let handlerList; | ||||
|             if (menu) { | ||||
|                 handlerList = this.coursesHandlers[course.id].enabledMenuHandlers; | ||||
|             } else { | ||||
|                 handlerList = this.coursesHandlers[course.id].enabledHandlers; | ||||
|             } | ||||
| 
 | ||||
|             handlerList.forEach((handler) => { | ||||
|                 const getFunction = menu ? handler.getMenuDisplayData : handler.getDisplayData; | ||||
|                 promises.push(Promise.resolve(getFunction.call(handler, injector, course)).then((data) => { | ||||
|                     handlersToDisplay.push({ | ||||
|                         data: data, | ||||
|                         priority: handler.priority, | ||||
| @ -444,6 +577,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate { | ||||
|     updateHandlersForCourse(courseId: number, accessData: any, navOptions?: any, admOptions?: any): Promise<any> { | ||||
|         const promises = [], | ||||
|             enabledForCourse = [], | ||||
|             enabledForCourseMenu = [], | ||||
|             siteId = this.sitesProvider.getCurrentSiteId(), | ||||
|             now = Date.now(); | ||||
| 
 | ||||
| @ -456,7 +590,11 @@ export class CoreCourseOptionsDelegate extends CoreDelegate { | ||||
|             promises.push(Promise.resolve(handler.isEnabledForCourse(courseId, accessData, navOptions, admOptions)) | ||||
|                 .then((enabled) => { | ||||
|                     if (enabled) { | ||||
|                         enabledForCourse.push(handler); | ||||
|                         if (handler.isMenuHandler) { | ||||
|                             enabledForCourseMenu.push(<CoreCourseOptionsMenuHandler> handler); | ||||
|                         } else { | ||||
|                             enabledForCourse.push(handler); | ||||
|                         } | ||||
|                     } else { | ||||
|                         return Promise.reject(null); | ||||
|                     } | ||||
| @ -476,6 +614,7 @@ export class CoreCourseOptionsDelegate extends CoreDelegate { | ||||
|             if (this.isLastUpdateCourseCall(courseId, now) && this.sitesProvider.getCurrentSiteId() === siteId) { | ||||
|                 // Update the coursesHandlers array with the new enabled addons.
 | ||||
|                 this.coursesHandlers[courseId].enabledHandlers = enabledForCourse; | ||||
|                 this.coursesHandlers[courseId].enabledMenuHandlers = enabledForCourseMenu; | ||||
|                 this.loaded[courseId] = true; | ||||
| 
 | ||||
|                 // Resolve the promise.
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user