From 2dea93a60f5166c6c1fa2d13a86b7013be56ae40 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 12 Jan 2022 10:57:29 +0100 Subject: [PATCH 1/2] MOBILE-3922 core: Display tab to select in first position --- src/core/classes/delegate-sorted.ts | 4 ++-- .../services/handlers/dashboard-home.ts | 3 +-- .../services/handlers/my-courses-mainmenu.ts | 6 +++++ .../features/mainmenu/pages/home/home.html | 2 +- src/core/features/mainmenu/pages/home/home.ts | 24 ++++--------------- .../mainmenu/services/home-delegate.ts | 7 +----- .../mainmenu/services/mainmenu-delegate.ts | 5 ++++ .../services/handlers/sitehome-home.ts | 4 ++-- 8 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/core/classes/delegate-sorted.ts b/src/core/classes/delegate-sorted.ts index ea4e99cce..d9e6069d7 100644 --- a/src/core/classes/delegate-sorted.ts +++ b/src/core/classes/delegate-sorted.ts @@ -118,14 +118,14 @@ export class CoreSortedDelegate< const handler = this.enabledHandlers[name]; const data = handler.getDisplayData(); - data.priority = handler.priority || 0; + data.priority = data.priority ?? handler.priority ?? 0; data.name = handler.name; displayData.push(data); } // Sort them by priority. - displayData.sort((a, b) => b.priority! - a.priority!); + displayData.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0)); this.loaded = true; this.sortedHandlersRxJs.next(displayData); diff --git a/src/core/features/courses/services/handlers/dashboard-home.ts b/src/core/features/courses/services/handlers/dashboard-home.ts index c06582993..521038dea 100644 --- a/src/core/features/courses/services/handlers/dashboard-home.ts +++ b/src/core/features/courses/services/handlers/dashboard-home.ts @@ -27,7 +27,7 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler static readonly PAGE_NAME = 'dashboard'; name = 'CoreCoursesDashboard'; - priority = 1100; + priority = 1200; /** * Check if the handler is enabled on a site level. @@ -92,7 +92,6 @@ export class CoreDashboardHomeHandlerService implements CoreMainMenuHomeHandler page: CoreDashboardHomeHandlerService.PAGE_NAME, class: 'core-courses-dashboard-handler', icon: 'fas-tachometer-alt', - selectPriority: 1000, }; } diff --git a/src/core/features/courses/services/handlers/my-courses-mainmenu.ts b/src/core/features/courses/services/handlers/my-courses-mainmenu.ts index 4d27add17..b800900f8 100644 --- a/src/core/features/courses/services/handlers/my-courses-mainmenu.ts +++ b/src/core/features/courses/services/handlers/my-courses-mainmenu.ts @@ -13,6 +13,7 @@ // limitations under the License. import { Injectable } from '@angular/core'; +import { CoreSiteInfoUserHomepage } from '@classes/site'; import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate'; import { CoreSiteHomeHomeHandler } from '@features/sitehome/services/handlers/sitehome-home'; import { CoreSites } from '@services/sites'; @@ -59,11 +60,16 @@ export class CoreCoursesMyCoursesMainMenuHandlerService implements CoreMainMenuH * @inheritdoc */ getDisplayData(): CoreMainMenuHandlerData { + const site = CoreSites.getCurrentSite(); + + const displayMyCourses = site?.getInfo() && site?.getInfo()?.userhomepage === CoreSiteInfoUserHomepage.HOMEPAGE_MYCOURSES; + return { title: 'core.courses.mycourses', page: CoreCoursesMyCoursesMainMenuHandlerService.PAGE_NAME, class: 'core-courses-my-courses-handler', icon: 'fas-graduation-cap', + priority: displayMyCourses ? this.priority + 200 : this.priority, }; } diff --git a/src/core/features/mainmenu/pages/home/home.html b/src/core/features/mainmenu/pages/home/home.html index 7f670c80a..bb7bd1179 100644 --- a/src/core/features/mainmenu/pages/home/home.html +++ b/src/core/features/mainmenu/pages/home/home.html @@ -17,5 +17,5 @@ - + diff --git a/src/core/features/mainmenu/pages/home/home.ts b/src/core/features/mainmenu/pages/home/home.ts index a4d89d00e..373305766 100644 --- a/src/core/features/mainmenu/pages/home/home.ts +++ b/src/core/features/mainmenu/pages/home/home.ts @@ -39,10 +39,9 @@ export class CoreMainMenuHomePage implements OnInit { @ViewChild(CoreTabsOutletComponent) tabsComponent?: CoreTabsOutletComponent; - siteName!: string; + siteName = ''; tabs: CoreTabsOutletTab[] = []; loaded = false; - selectedTab?: number; protected subscription?: Subscription; protected updateSiteObserver?: CoreEventObserver; @@ -109,21 +108,6 @@ export class CoreMainMenuHomePage implements OnInit { // Sort them by priority so new handlers are in the right position. newTabs.sort((a, b) => (handlersMap[b.title].priority || 0) - (handlersMap[a.title].priority || 0)); - if (this.selectedTab === undefined && newTabs.length > 0) { - let maxPriority = 0; - - this.selectedTab = Object.entries(newTabs).reduce((maxIndex, [index, tab]) => { - const selectPriority = handlersMap[tab.title].selectPriority ?? 0; - - if (selectPriority > maxPriority) { - maxPriority = selectPriority; - maxIndex = Number(index); - } - - return maxIndex; - }, 0); - } - this.tabs = newTabs; // Try to prevent empty box displayed for an instant when it shouldn't. @@ -136,7 +120,7 @@ export class CoreMainMenuHomePage implements OnInit { * Load the site name. */ protected loadSiteName(): void { - this.siteName = CoreSites.getCurrentSite()!.getSiteName(); + this.siteName = CoreSites.getCurrentSite()?.getSiteName() || ''; } /** @@ -171,8 +155,8 @@ export class CoreMainMenuHomePage implements OnInit { const actions = await CoreContentLinksDelegate.getActionsFor(url, undefined); const action = CoreContentLinksHelper.getFirstValidAction(actions); - if (action) { - action.action(action.sites![0]); + if (action?.sites?.[0]) { + action.action(action.sites[0]); } } diff --git a/src/core/features/mainmenu/services/home-delegate.ts b/src/core/features/mainmenu/services/home-delegate.ts index 588549137..636c9e486 100644 --- a/src/core/features/mainmenu/services/home-delegate.ts +++ b/src/core/features/mainmenu/services/home-delegate.ts @@ -72,12 +72,7 @@ export interface CoreMainMenuHomeHandlerData { /** * Data returned by the delegate for each handler. */ -export interface CoreMainMenuHomeHandlerToDisplay extends CoreDelegateToDisplay, CoreMainMenuHomeHandlerData { - /** - * Priority to select handler. - */ - selectPriority?: number; -} +export interface CoreMainMenuHomeHandlerToDisplay extends CoreDelegateToDisplay, CoreMainMenuHomeHandlerData {} /** * Service to interact with plugins to be shown in the main menu. Provides functions to register a plugin diff --git a/src/core/features/mainmenu/services/mainmenu-delegate.ts b/src/core/features/mainmenu/services/mainmenu-delegate.ts index 2ecbb542d..97a7fa9ab 100644 --- a/src/core/features/mainmenu/services/mainmenu-delegate.ts +++ b/src/core/features/mainmenu/services/mainmenu-delegate.ts @@ -77,6 +77,11 @@ export interface CoreMainMenuHandlerData { * Whether the handler should only appear in More menu. */ onlyInMore?: boolean; + + /** + * Priority of the handler. If set, overrides the priority defined in CoreMainMenuHandler. + */ + priority?: number; } /** diff --git a/src/core/features/sitehome/services/handlers/sitehome-home.ts b/src/core/features/sitehome/services/handlers/sitehome-home.ts index dfae92fd4..61e86b46b 100644 --- a/src/core/features/sitehome/services/handlers/sitehome-home.ts +++ b/src/core/features/sitehome/services/handlers/sitehome-home.ts @@ -28,7 +28,7 @@ export class CoreSiteHomeHomeHandlerService implements CoreMainMenuHomeHandler { static readonly PAGE_NAME = 'site'; name = 'CoreSiteHomeDashboard'; - priority = 1200; + priority = 1100; /** * Check if the handler is enabled on a site level. @@ -64,7 +64,7 @@ export class CoreSiteHomeHomeHandlerService implements CoreMainMenuHomeHandler { page: CoreSiteHomeHomeHandlerService.PAGE_NAME, class: 'core-sitehome-dashboard-handler', icon: 'fas-home', - selectPriority: displaySiteHome ? 1100 : 900, + priority: displaySiteHome ? this.priority + 200 : this.priority, }; } From f53b783fc95de74d0849951d445275d5fe9f69a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Mon, 8 Nov 2021 16:19:08 +0100 Subject: [PATCH 2/2] MOBILE-3922 menu: Fix select initial main menu page --- .../features/mainmenu/mainmenu-lazy.module.ts | 1 - src/core/features/mainmenu/pages/home/home.ts | 3 +- src/core/features/mainmenu/pages/menu/menu.ts | 4 ++ src/core/guards/redirect.ts | 3 +- src/core/services/navigator.ts | 39 +++++++++++++++---- src/core/services/tests/navigator.test.ts | 19 +++++++-- 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/core/features/mainmenu/mainmenu-lazy.module.ts b/src/core/features/mainmenu/mainmenu-lazy.module.ts index 22f30d18b..579510de6 100644 --- a/src/core/features/mainmenu/mainmenu-lazy.module.ts +++ b/src/core/features/mainmenu/mainmenu-lazy.module.ts @@ -35,7 +35,6 @@ function buildRoutes(injector: Injector): Routes { { path: '', pathMatch: 'full', - redirectTo: CoreMainMenuHomeHandlerService.PAGE_NAME, }, { path: CoreMainMenuHomeHandlerService.PAGE_NAME, diff --git a/src/core/features/mainmenu/pages/home/home.ts b/src/core/features/mainmenu/pages/home/home.ts index 373305766..b5d9499a9 100644 --- a/src/core/features/mainmenu/pages/home/home.ts +++ b/src/core/features/mainmenu/pages/home/home.ts @@ -26,6 +26,7 @@ import { CoreCourseHelper } from '@features/course/services/course-helper'; import { CoreCourse } from '@features/course/services/course'; import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate'; import { CoreContentLinksHelper } from '@features/contentlinks/services/contentlinks-helper'; +import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/handlers/mainmenu'; /** * Page that displays the Home. @@ -96,7 +97,7 @@ export class CoreMainMenuHomePage implements OnInit { } return { - page: `/main/home/${handler.page}`, + page: `/main/${CoreMainMenuHomeHandlerService.PAGE_NAME}/${handler.page}`, pageParams: handler.pageParams, title: handler.title, class: handler.class, diff --git a/src/core/features/mainmenu/pages/menu/menu.ts b/src/core/features/mainmenu/pages/menu/menu.ts index 465352809..d2b74958b 100644 --- a/src/core/features/mainmenu/pages/menu/menu.ts +++ b/src/core/features/mainmenu/pages/menu/menu.ts @@ -173,6 +173,10 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { this.loaded = CoreMainMenuDelegate.areHandlersLoaded(); + if (this.loaded && this.tabs[0] && !CoreNavigator.getCurrentMainMenuTab()) { + // No tab selected, select the first one. + this.mainTabs?.select(this.tabs[0].page); + } } /** diff --git a/src/core/guards/redirect.ts b/src/core/guards/redirect.ts index 5217a123a..dcb7c2950 100644 --- a/src/core/guards/redirect.ts +++ b/src/core/guards/redirect.ts @@ -14,6 +14,7 @@ import { Injectable } from '@angular/core'; import { CanActivate, CanLoad, UrlTree } from '@angular/router'; +import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/handlers/mainmenu'; import { CoreApp } from '@services/app'; import { CoreRedirectPayload } from '@services/navigator'; import { CoreSites } from '@services/sites'; @@ -59,7 +60,7 @@ export class CoreRedirectGuard implements CanLoad, CanActivate { redirect.page, redirect.options, ); - const route = Router.parseUrl('/main/home'); + const route = Router.parseUrl(`/main/${CoreMainMenuHomeHandlerService.PAGE_NAME}`); route.queryParams = { redirectPath: redirect.page, diff --git a/src/core/services/navigator.ts b/src/core/services/navigator.ts index 8d7d02c81..a807a74ee 100644 --- a/src/core/services/navigator.ts +++ b/src/core/services/navigator.ts @@ -20,7 +20,6 @@ import { NavigationOptions } from '@ionic/angular/providers/nav-controller'; import { CoreConstants } from '@/core/constants'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreMainMenu } from '@features/mainmenu/services/mainmenu'; -import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/handlers/mainmenu'; import { CoreObject } from '@singletons/object'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; @@ -31,8 +30,8 @@ import { CoreScreen } from './screen'; import { CoreApp } from './app'; import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins'; import { CoreError } from '@classes/errors/error'; - -const DEFAULT_MAIN_MENU_TAB = CoreMainMenuHomeHandlerService.PAGE_NAME; +import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-delegate'; +import { CoreMainMenuHomeHandlerService } from '@features/mainmenu/services/handlers/mainmenu'; /** * Redirect payload. @@ -184,9 +183,12 @@ export class CoreNavigatorService { * @return Whether navigation suceeded. */ async navigateToSiteHome(options: Omit & { siteId?: string } = {}): Promise { - return this.navigateToSitePath(DEFAULT_MAIN_MENU_TAB, { + const landingPagePath = this.getLandingTabPage(); + + return this.navigateToSitePath(landingPagePath, { ...options, reset: true, + preferCurrentTab: false, }); } @@ -535,8 +537,13 @@ export class CoreNavigatorService { path = path.replace(/^(\.|\/main)?\//, ''); const pathRoot = /^[^/]+/.exec(path)?.[0] ?? ''; + if (!pathRoot) { + // No path root, going to the site home. + return this.navigate('/main', options); + } + const currentMainMenuTab = this.getCurrentMainMenuTab(); - const isMainMenuTab = pathRoot === currentMainMenuTab || (!currentMainMenuTab && path === DEFAULT_MAIN_MENU_TAB) || + const isMainMenuTab = pathRoot === currentMainMenuTab || (!currentMainMenuTab && path === this.getLandingTabPage()) || await CoreUtils.ignoreErrors(CoreMainMenu.isMainMenuTab(pathRoot), false); if (!options.preferCurrentTab && isMainMenuTab) { @@ -553,16 +560,32 @@ export class CoreNavigatorService { return this.navigate(`/main/${path}`, options); } - // Open the path within the default main tab. - return this.navigate(`/main/${DEFAULT_MAIN_MENU_TAB}`, { + // Open the path within the home tab. + return this.navigate(`/main/${CoreMainMenuHomeHandlerService.PAGE_NAME}`, { ...options, params: { - redirectPath: `/main/${DEFAULT_MAIN_MENU_TAB}/${path}`, + redirectPath: `/main/${CoreMainMenuHomeHandlerService.PAGE_NAME}/${path}`, redirectOptions: options.params || options.nextNavigation ? options : undefined, } as CoreRedirectPayload, }); } + /** + * Get the first page path using priority. + * + * @return Landing page path. + */ + protected getLandingTabPage(): string { + if (!CoreMainMenuDelegate.areHandlersLoaded()) { + // Handlers not loaded yet, landing page is the root page. + return ''; + } + + const handlers = CoreMainMenuDelegate.getHandlers(); + + return handlers[0]?.page || ''; + } + /** * Replace all objects in query params with an ID that can be used to retrieve the object later. * diff --git a/src/core/services/tests/navigator.test.ts b/src/core/services/tests/navigator.test.ts index a0000b07e..694ba3f78 100644 --- a/src/core/services/tests/navigator.test.ts +++ b/src/core/services/tests/navigator.test.ts @@ -21,6 +21,7 @@ import { NavController, Router } from '@singletons'; import { ActivatedRoute, RouterState } from '@angular/router'; import { CoreSites } from '@services/sites'; import { CoreMainMenu } from '@features/mainmenu/services/mainmenu'; +import { CoreMainMenuDelegate } from '@features/mainmenu/services/mainmenu-delegate'; describe('CoreNavigator', () => { @@ -118,7 +119,7 @@ describe('CoreNavigator', () => { }); }); - it('navigates to site paths ussing different path formats', async () => { + it('navigates to site paths using different path formats', async () => { currentMainMenuHandlers.push('users'); const assertNavigation = async (currentPath, sitePath, expectedPath) => { @@ -136,11 +137,23 @@ describe('CoreNavigator', () => { await assertNavigation('/main/home', '/users/user/42', '/main/users/user/42'); }); - it('navigates to site home', async () => { + it('navigates to site home: no handlers loaded', async () => { const success = await navigator.navigateToSiteHome(); expect(success).toBe(true); - expect(navControllerMock.navigateRoot).toHaveBeenCalledWith(['/main/home'], {}); + expect(navControllerMock.navigateRoot).toHaveBeenCalledWith(['/main'], {}); + }); + + it('navigates to site home: handlers loaded', async () => { + mockSingleton(CoreMainMenuDelegate, { + areHandlersLoaded: () => true, + getHandlers: () => [{ title: 'Test', page: 'initialpage', icon: '' }], + }); + + const success = await navigator.navigateToSiteHome(); + + expect(success).toBe(true); + expect(navControllerMock.navigateRoot).toHaveBeenCalledWith(['/main/initialpage'], {}); }); it.todo('navigates to a different site');