MOBILE-2903 menu: Show menu items depending on device width

main
Pau Ferrer Ocaña 2019-03-06 14:54:40 +01:00
parent 4eeb3de749
commit 19e0cf59e5
4 changed files with 78 additions and 27 deletions

View File

@ -223,6 +223,10 @@ export class CoreIonTabsComponent extends Tabs implements OnDestroy {
* @param {CoreIonTabComponent} tab The tab to remove. * @param {CoreIonTabComponent} tab The tab to remove.
*/ */
remove(tab: CoreIonTabComponent): void { remove(tab: CoreIonTabComponent): void {
if (tab.isSelected) {
// TODO: If selected we should move this navigation to the phantom tab.
}
// First search in the list of initialized tabs. // First search in the list of initialized tabs.
let index = this._tabs.indexOf(tab); let index = this._tabs.indexOf(tab);

View File

@ -30,6 +30,7 @@ import { CoreMainMenuDelegate, CoreMainMenuHandlerToDisplay } from '../../provid
}) })
export class CoreMainMenuPage implements OnDestroy { export class CoreMainMenuPage implements OnDestroy {
tabs: CoreMainMenuHandlerToDisplay[] = []; tabs: CoreMainMenuHandlerToDisplay[] = [];
allHandlers: CoreMainMenuHandlerToDisplay[];
loaded = false; loaded = false;
redirectPage: string; redirectPage: string;
redirectParams: any; redirectParams: any;
@ -42,7 +43,8 @@ export class CoreMainMenuPage implements OnDestroy {
@ViewChild('mainTabs') mainTabs: CoreIonTabsComponent; @ViewChild('mainTabs') mainTabs: CoreIonTabsComponent;
constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider, navParams: NavParams, constructor(private menuDelegate: CoreMainMenuDelegate, private sitesProvider: CoreSitesProvider, navParams: NavParams,
private navCtrl: NavController, private eventsProvider: CoreEventsProvider, private cdr: ChangeDetectorRef) { private navCtrl: NavController, private eventsProvider: CoreEventsProvider, private cdr: ChangeDetectorRef,
private mainMenuProvider: CoreMainMenuProvider) {
// Check if the menu was loaded with a redirect. // Check if the menu was loaded with a redirect.
const redirectPage = navParams.get('redirectPage'); const redirectPage = navParams.get('redirectPage');
@ -78,10 +80,32 @@ export class CoreMainMenuPage implements OnDestroy {
this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => { this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => {
// Remove the handlers that should only appear in the More menu. // Remove the handlers that should only appear in the More menu.
handlers = handlers.filter((handler) => { this.allHandlers = handlers.filter((handler) => {
return !handler.onlyInMore; return !handler.onlyInMore;
}); });
handlers = handlers.slice(0, CoreMainMenuProvider.NUM_MAIN_HANDLERS); // Get main handlers.
this.initHandlers();
if (this.loaded && this.pendingRedirect) {
// Wait for tabs to be initialized and then handle the redirect.
setTimeout(() => {
if (this.pendingRedirect) {
this.handleRedirect(this.pendingRedirect);
delete this.pendingRedirect;
}
});
}
});
window.addEventListener('resize', this.initHandlers.bind(this));
}
/**
* Init handlers on change (size or handlers).
*/
initHandlers(): void {
if (this.allHandlers) {
const handlers = this.allHandlers.slice(0, this.mainMenuProvider.getNumItems()); // Get main handlers.
// Re-build the list of tabs. If a handler is already in the list, use existing object to prevent re-creating the tab. // Re-build the list of tabs. If a handler is already in the list, use existing object to prevent re-creating the tab.
const newTabs = []; const newTabs = [];
@ -105,17 +129,7 @@ export class CoreMainMenuPage implements OnDestroy {
}); });
this.loaded = this.menuDelegate.areHandlersLoaded(); this.loaded = this.menuDelegate.areHandlersLoaded();
if (this.loaded && this.pendingRedirect) {
// Wait for tabs to be initialized and then handle the redirect.
setTimeout(() => {
if (this.pendingRedirect) {
this.handleRedirect(this.pendingRedirect);
delete this.pendingRedirect;
} }
});
}
});
} }
/** /**
@ -153,5 +167,6 @@ export class CoreMainMenuPage implements OnDestroy {
ngOnDestroy(): void { ngOnDestroy(): void {
this.subscription && this.subscription.unsubscribe(); this.subscription && this.subscription.unsubscribe();
this.redirectObs && this.redirectObs.off(); this.redirectObs && this.redirectObs.off();
window.removeEventListener('resize', this.initHandlers.bind(this));
} }
} }

View File

@ -29,6 +29,7 @@ import { CoreMainMenuProvider, CoreMainMenuCustomItem } from '../../providers/ma
}) })
export class CoreMainMenuMorePage implements OnDestroy { export class CoreMainMenuMorePage implements OnDestroy {
handlers: CoreMainMenuHandlerData[]; handlers: CoreMainMenuHandlerData[];
allHandlers: CoreMainMenuHandlerData[];
handlersLoaded: boolean; handlersLoaded: boolean;
siteInfo: any; siteInfo: any;
siteName: string; siteName: string;
@ -58,32 +59,44 @@ export class CoreMainMenuMorePage implements OnDestroy {
ionViewDidLoad(): void { ionViewDidLoad(): void {
// Load the handlers. // Load the handlers.
this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => { this.subscription = this.menuDelegate.getHandlers().subscribe((handlers) => {
// Calculate the main handlers to not display them in this view. this.allHandlers = handlers;
const mainHandlers = handlers.filter((handler) => {
return !handler.onlyInMore;
}).slice(0, CoreMainMenuProvider.NUM_MAIN_HANDLERS);
// Get only the handlers that don't appear in the main view. this.initHandlers();
this.handlers = [];
handlers.forEach((handler) => {
if (mainHandlers.indexOf(handler) == -1) {
this.handlers.push(handler);
}
}); });
this.handlersLoaded = this.menuDelegate.areHandlersLoaded(); window.addEventListener('resize', this.initHandlers.bind(this));
});
} }
/** /**
* Page destroyed. * Page destroyed.
*/ */
ngOnDestroy(): void { ngOnDestroy(): void {
window.removeEventListener('resize', this.initHandlers.bind(this));
if (this.subscription) { if (this.subscription) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
} }
/**
* Init handlers on change (size or handlers).
*/
initHandlers(): void {
if (this.allHandlers) {
// Calculate the main handlers not to display them in this view.
const mainHandlers = this.allHandlers.filter((handler) => {
return !handler.onlyInMore;
}).slice(0, this.mainMenuProvider.getNumItems());
// Get only the handlers that don't appear in the main view.
this.handlers = this.allHandlers.filter((handler) => {
return mainHandlers.indexOf(handler) == -1;
});
this.handlersLoaded = this.menuDelegate.areHandlersLoaded();
}
}
/** /**
* Load the site info required by the view. * Load the site info required by the view.
*/ */

View File

@ -52,6 +52,7 @@ export interface CoreMainMenuCustomItem {
@Injectable() @Injectable()
export class CoreMainMenuProvider { export class CoreMainMenuProvider {
static NUM_MAIN_HANDLERS = 4; static NUM_MAIN_HANDLERS = 4;
static ITEM_MIN_WIDTH = 72; // Min with of every item, based on 5 items on a 360 pixel wide screen.
constructor(private langProvider: CoreLangProvider, private sitesProvider: CoreSitesProvider) { } constructor(private langProvider: CoreLangProvider, private sitesProvider: CoreSitesProvider) { }
@ -158,4 +159,22 @@ export class CoreMainMenuProvider {
}); });
}); });
} }
/**
* Get the number of items to be shown on the main menu bar.
*
* @return {number} Number of items depending on the device width.
*/
getNumItems(): number {
if (window && window.innerWidth) {
let numElements;
numElements = Math.floor(window.innerWidth / CoreMainMenuProvider.ITEM_MIN_WIDTH);
// Set a mínimum elements to show and skip more button.
return numElements > 1 ? numElements - 1 : 1;
}
return CoreMainMenuProvider.NUM_MAIN_HANDLERS;
}
} }