forked from EVOgeek/Vmeda.Online
		
	MOBILE-2738 tabs: Control navigation when backbutton is actioned
This commit is contained in:
		
							parent
							
								
									ac9bd47da0
								
							
						
					
					
						commit
						d35f0e2ffc
					
				@ -12,10 +12,12 @@
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Component, Optional, ElementRef, Renderer, ViewEncapsulation, forwardRef, ViewChild, Input } from '@angular/core';
 | 
			
		||||
import { Component, Optional, ElementRef, Renderer, ViewEncapsulation, forwardRef, ViewChild, Input,
 | 
			
		||||
    OnDestroy } from '@angular/core';
 | 
			
		||||
import { Tabs, NavController, ViewController, App, Config, Platform, DeepLinker, Keyboard, RootNode } from 'ionic-angular';
 | 
			
		||||
import { CoreIonTabComponent } from './ion-tab';
 | 
			
		||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
import { CoreAppProvider } from '@providers/app';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Equivalent to ion-tabs. It has 2 improvements:
 | 
			
		||||
@ -28,7 +30,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
    encapsulation: ViewEncapsulation.None,
 | 
			
		||||
    providers: [{provide: RootNode, useExisting: forwardRef(() => CoreIonTabsComponent) }]
 | 
			
		||||
})
 | 
			
		||||
export class CoreIonTabsComponent extends Tabs {
 | 
			
		||||
export class CoreIonTabsComponent extends Tabs implements OnDestroy {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the tabs have been loaded. If defined, tabs won't be initialized until it's set to true.
 | 
			
		||||
@ -62,9 +64,12 @@ export class CoreIonTabsComponent extends Tabs {
 | 
			
		||||
    protected viewInit = false; // Whether the view has been initialized.
 | 
			
		||||
    protected initialized = false; // Whether tabs have been initialized.
 | 
			
		||||
 | 
			
		||||
    constructor(protected utils: CoreUtilsProvider, @Optional() parent: NavController, @Optional() viewCtrl: ViewController,
 | 
			
		||||
            _app: App, config: Config, elementRef: ElementRef, _plt: Platform, renderer: Renderer, _linker: DeepLinker,
 | 
			
		||||
            keyboard?: Keyboard) {
 | 
			
		||||
    protected firstSelectedTab: string;
 | 
			
		||||
    protected unregisterBackButtonAction: any;
 | 
			
		||||
 | 
			
		||||
    constructor(protected utils: CoreUtilsProvider, protected appProvider: CoreAppProvider, @Optional() parent: NavController,
 | 
			
		||||
            @Optional() viewCtrl: ViewController, _app: App, config: Config, elementRef: ElementRef, _plt: Platform,
 | 
			
		||||
            renderer: Renderer, _linker: DeepLinker, keyboard?: Keyboard) {
 | 
			
		||||
        super(parent, viewCtrl, _app, config, elementRef, _plt, renderer, _linker, keyboard);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -75,6 +80,8 @@ export class CoreIonTabsComponent extends Tabs {
 | 
			
		||||
        this.viewInit = true;
 | 
			
		||||
 | 
			
		||||
        super.ngAfterViewInit();
 | 
			
		||||
 | 
			
		||||
        this.registerBackButtonAction();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -146,6 +153,8 @@ export class CoreIonTabsComponent extends Tabs {
 | 
			
		||||
                        this.select(tab);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.firstSelectedTab = this._selectHistory[0] || null;
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
            // Tabs not loaded yet. Set the tab bar position so the tab bar is shown, it'll have a spinner.
 | 
			
		||||
@ -155,6 +164,42 @@ export class CoreIonTabsComponent extends Tabs {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register back button action.
 | 
			
		||||
     */
 | 
			
		||||
    protected registerBackButtonAction(): void {
 | 
			
		||||
        this.unregisterBackButtonAction = this.appProvider.registerBackButtonAction(() => {
 | 
			
		||||
            let tab = this.previousTab(true);
 | 
			
		||||
            if (tab) {
 | 
			
		||||
                const selectedTab = this.getSelected();
 | 
			
		||||
 | 
			
		||||
                // Remove curent and previous tabs from history.
 | 
			
		||||
                this._selectHistory = this._selectHistory.filter((tabId) => {
 | 
			
		||||
                    return selectedTab.id != tabId && tab.id != tabId;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.select(tab);
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            } else  {
 | 
			
		||||
                const selected = this.getSelected();
 | 
			
		||||
                if (selected && this.firstSelectedTab && selected.id != this.firstSelectedTab) {
 | 
			
		||||
                    // All history is gone but we are not in the first selected tab.
 | 
			
		||||
                    this._selectHistory = [];
 | 
			
		||||
 | 
			
		||||
                    tab = this._tabs.find((t) => { return t.id === this.firstSelectedTab; });
 | 
			
		||||
                    if (tab && tab.enabled && tab.show) {
 | 
			
		||||
                        this.select(tab);
 | 
			
		||||
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }, 250);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Remove a tab from the list of tabs.
 | 
			
		||||
     *
 | 
			
		||||
@ -204,4 +249,12 @@ export class CoreIonTabsComponent extends Tabs {
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component destroyed.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        // Unregister the custom back button action for this page
 | 
			
		||||
        this.unregisterBackButtonAction && this.unregisterBackButtonAction();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,9 +16,10 @@ import {
 | 
			
		||||
    Component, Input, Output, EventEmitter, OnInit, OnChanges, OnDestroy, AfterViewInit, ViewChild, ElementRef,
 | 
			
		||||
    SimpleChange
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { CoreTabComponent } from './tab';
 | 
			
		||||
import { Content, Slides } from 'ionic-angular';
 | 
			
		||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
			
		||||
import { CoreAppProvider } from '@providers/app';
 | 
			
		||||
import { CoreTabComponent } from './tab';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This component displays some tabs that usually share data between them.
 | 
			
		||||
@ -72,8 +73,13 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
 | 
			
		||||
    protected isCurrentView = true;
 | 
			
		||||
    protected shouldSlideToInitial = false; // Whether we need to slide to the initial slide because it's out of view.
 | 
			
		||||
    protected hasSliddenToInitial = false; // Whether we've already slidden to the initial slide or there was no need.
 | 
			
		||||
    protected selectHistory = [];
 | 
			
		||||
 | 
			
		||||
    constructor(element: ElementRef, protected content: Content, protected domUtils: CoreDomUtilsProvider) {
 | 
			
		||||
    protected firstSelectedTab: number;
 | 
			
		||||
    protected unregisterBackButtonAction: any;
 | 
			
		||||
 | 
			
		||||
    constructor(element: ElementRef, protected content: Content, protected domUtils: CoreDomUtilsProvider,
 | 
			
		||||
            protected appProvider: CoreAppProvider) {
 | 
			
		||||
        this.tabBarElement = element.nativeElement;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -128,12 +134,47 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
 | 
			
		||||
        if (this.initialized) {
 | 
			
		||||
            this.calculateSlides();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.registerBackButtonAction();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Register back button action.
 | 
			
		||||
     */
 | 
			
		||||
    protected registerBackButtonAction(): void {
 | 
			
		||||
        this.unregisterBackButtonAction = this.appProvider.registerBackButtonAction(() => {
 | 
			
		||||
            // The previous page in history is not the last one, we need the previous one.
 | 
			
		||||
            if (this.selectHistory.length > 1) {
 | 
			
		||||
                const tab = this.selectHistory[this.selectHistory.length - 2];
 | 
			
		||||
 | 
			
		||||
                // Remove curent and previous tabs from history.
 | 
			
		||||
                this.selectHistory = this.selectHistory.filter((tabId) => {
 | 
			
		||||
                    return this.selected != tabId && tab != tabId;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.selectTab(tab);
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            } else if (this.selected != this.firstSelectedTab) {
 | 
			
		||||
                // All history is gone but we are not in the first selected tab.
 | 
			
		||||
                this.selectHistory = [];
 | 
			
		||||
 | 
			
		||||
                this.selectTab(this.firstSelectedTab);
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }, 750);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * User left the page that contains the component.
 | 
			
		||||
     */
 | 
			
		||||
    ionViewDidLeave(): void {
 | 
			
		||||
        // Unregister the custom back button action for this page
 | 
			
		||||
        this.unregisterBackButtonAction && this.unregisterBackButtonAction();
 | 
			
		||||
 | 
			
		||||
        this.isCurrentView = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -229,6 +270,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (selectedTab) {
 | 
			
		||||
            this.firstSelectedTab = selectedIndex;
 | 
			
		||||
            this.selectTab(selectedIndex);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -405,6 +447,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges, OnDe
 | 
			
		||||
            this.slides.slideTo(index);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.selectHistory.push(index);
 | 
			
		||||
        this.selected = index;
 | 
			
		||||
        newTab.selectTab();
 | 
			
		||||
        this.ionChange.emit(newTab);
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Injectable, NgZone } from '@angular/core';
 | 
			
		||||
import { Platform, App, NavController } from 'ionic-angular';
 | 
			
		||||
import { Platform, App, NavController, MenuController } from 'ionic-angular';
 | 
			
		||||
import { Keyboard } from '@ionic-native/keyboard';
 | 
			
		||||
import { Network } from '@ionic-native/network';
 | 
			
		||||
 | 
			
		||||
@ -68,9 +68,11 @@ export class CoreAppProvider {
 | 
			
		||||
    protected logger;
 | 
			
		||||
    protected ssoAuthenticationPromise: Promise<any>;
 | 
			
		||||
    protected isKeyboardShown = false;
 | 
			
		||||
    protected backActions = [];
 | 
			
		||||
 | 
			
		||||
    constructor(dbProvider: CoreDbProvider, private platform: Platform, private keyboard: Keyboard, private appCtrl: App,
 | 
			
		||||
            private network: Network, logger: CoreLoggerProvider, events: CoreEventsProvider, zone: NgZone) {
 | 
			
		||||
            private network: Network, logger: CoreLoggerProvider, events: CoreEventsProvider, zone: NgZone,
 | 
			
		||||
            private menuCtrl: MenuController) {
 | 
			
		||||
        this.logger = logger.getInstance('CoreAppProvider');
 | 
			
		||||
        this.db = dbProvider.getDB(this.DBNAME);
 | 
			
		||||
 | 
			
		||||
@ -92,6 +94,10 @@ export class CoreAppProvider {
 | 
			
		||||
                events.trigger(CoreEventsProvider.KEYBOARD_CHANGE, 0);
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.platform.registerBackButtonAction(() => {
 | 
			
		||||
            this.backButtonAction();
 | 
			
		||||
        }, 100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -382,4 +388,95 @@ export class CoreAppProvider {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Implement the backbutton actions pile.
 | 
			
		||||
     */
 | 
			
		||||
    backButtonAction(): void {
 | 
			
		||||
        let x = 0;
 | 
			
		||||
        for (; x < this.backActions.length; x++) {
 | 
			
		||||
            if (this.backActions[x].priority < 1000) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            // Stop in the first action taken.
 | 
			
		||||
            if (this.backActions[x].fn()) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Close open modals if any.
 | 
			
		||||
        if (this.menuCtrl && this.menuCtrl.isOpen()) {
 | 
			
		||||
            this.menuCtrl.close();
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Remaining actions will have priority less than 1000.
 | 
			
		||||
        for (; x < this.backActions.length; x++) {
 | 
			
		||||
            if (this.backActions[x].priority < 500) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            // Stop in the first action taken.
 | 
			
		||||
            if (this.backActions[x].fn()) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Nothing found, go back.
 | 
			
		||||
        const navPromise = this.appCtrl.navPop();
 | 
			
		||||
        if (navPromise) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // No views to go back to.
 | 
			
		||||
 | 
			
		||||
        // Remaining actions will have priority less than 500.
 | 
			
		||||
        for (; x < this.backActions.length; x++) {
 | 
			
		||||
            // Stop in the first action taken.
 | 
			
		||||
            if (this.backActions[x].fn()) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Ionic will decide (exit the app).
 | 
			
		||||
        this.appCtrl.goBack();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The back button event is triggered when the user presses the native
 | 
			
		||||
     * platform's back button, also referred to as the "hardware" back button.
 | 
			
		||||
     * This event is only used within Cordova apps running on Android and
 | 
			
		||||
     * Windows platforms. This event is not fired on iOS since iOS doesn't come
 | 
			
		||||
     * with a hardware back button in the same sense an Android or Windows device
 | 
			
		||||
     * does.
 | 
			
		||||
     *
 | 
			
		||||
     * Registering a hardware back button action and setting a priority allows
 | 
			
		||||
     * apps to control which action should be called when the hardware back
 | 
			
		||||
     * button is pressed. This method decides which of the registered back button
 | 
			
		||||
     * actions has the highest priority and should be called.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {Function} fn Called when the back button is pressed,
 | 
			
		||||
     * if this registered action has the highest priority.
 | 
			
		||||
     * @param {number} priority Set the priority for this action. All actions sorted by priority will be executed since one of
 | 
			
		||||
     * them returns true.
 | 
			
		||||
     *   * Priorities higher or equal than 1000 will go before closing modals
 | 
			
		||||
     *   * Priorities lower than 500 will only be executed if you are in the first state of the app (before exit).
 | 
			
		||||
     * @returns {Function} A function that, when called, will unregister
 | 
			
		||||
     * the back button action.
 | 
			
		||||
     */
 | 
			
		||||
    registerBackButtonAction(fn: Function, priority: number = 0): Function {
 | 
			
		||||
        const action = { fn: fn, priority: priority };
 | 
			
		||||
 | 
			
		||||
        this.backActions.push(action);
 | 
			
		||||
 | 
			
		||||
        this.backActions.sort((a, b) => {
 | 
			
		||||
            return b.priority - a.priority;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return (): boolean => {
 | 
			
		||||
            const index = this.backActions.indexOf(action);
 | 
			
		||||
 | 
			
		||||
            return index >= 0 && !!this.backActions.splice(index, 1);
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user