forked from EVOgeek/Vmeda.Online
		
	MOBILE-3708 android: Handle back button in tabs
This commit is contained in:
		
							parent
							
								
									81bf906fef
								
							
						
					
					
						commit
						3d80e57402
					
				| @ -115,6 +115,8 @@ export class AppComponent implements OnInit, AfterViewInit { | |||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         this.onPlatformReady(); |         this.onPlatformReady(); | ||||||
|  | 
 | ||||||
|  |         // @todo: Quit app with back button. How to tell if we're at root level?
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -25,9 +25,9 @@ import { | |||||||
|     ElementRef, |     ElementRef, | ||||||
| } from '@angular/core'; | } from '@angular/core'; | ||||||
| import { IonSlides } from '@ionic/angular'; | import { IonSlides } from '@ionic/angular'; | ||||||
|  | import { BackButtonEvent } from '@ionic/core'; | ||||||
| import { Subscription } from 'rxjs'; | import { Subscription } from 'rxjs'; | ||||||
| 
 | 
 | ||||||
| import { CoreApp } from '@services/app'; |  | ||||||
| import { Platform, Translate } from '@singletons'; | import { Platform, Translate } from '@singletons'; | ||||||
| import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; | import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; | ||||||
| 
 | 
 | ||||||
| @ -81,7 +81,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|     protected selectHistory: string[] = []; |     protected selectHistory: string[] = []; | ||||||
| 
 | 
 | ||||||
|     protected firstSelectedTab?: string; // ID of the first selected tab to control history.
 |     protected firstSelectedTab?: string; // ID of the first selected tab to control history.
 | ||||||
|     protected unregisterBackButtonAction: any; |     protected backButtonFunction: (event: BackButtonEvent) => void; | ||||||
|     protected languageChangedSubscription?: Subscription; |     protected languageChangedSubscription?: Subscription; | ||||||
|     protected isInTransition = false; // Weather Slides is in transition.
 |     protected isInTransition = false; // Weather Slides is in transition.
 | ||||||
|     protected slidesSwiper: any; // eslint-disable-line @typescript-eslint/no-explicit-any
 |     protected slidesSwiper: any; // eslint-disable-line @typescript-eslint/no-explicit-any
 | ||||||
| @ -91,6 +91,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|     constructor( |     constructor( | ||||||
|         protected element: ElementRef, |         protected element: ElementRef, | ||||||
|     ) { |     ) { | ||||||
|  |         this.backButtonFunction = this.backButtonClicked.bind(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -171,43 +172,47 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
| 
 | 
 | ||||||
|         this.calculateSlides(); |         this.calculateSlides(); | ||||||
| 
 | 
 | ||||||
|         this.registerBackButtonAction(); |         document.addEventListener('ionBackButton', this.backButtonFunction); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Register back button action. |      * Back button clicked. | ||||||
|  |      * | ||||||
|  |      * @param event Event. | ||||||
|      */ |      */ | ||||||
|     protected registerBackButtonAction(): void { |     protected backButtonClicked(event: BackButtonEvent): void { | ||||||
|         this.unregisterBackButtonAction = CoreApp.registerBackButtonAction(() => { |         event.detail.register(40, (processNextHandler: () => void) => { | ||||||
|             // The previous page in history is not the last one, we need the previous one.
 |  | ||||||
|             if (this.selectHistory.length > 1) { |             if (this.selectHistory.length > 1) { | ||||||
|                 const tabIndex = this.selectHistory[this.selectHistory.length - 2]; |                 // The previous page in history is not the last one, we need the previous one.
 | ||||||
|  |                 const previousTabId = this.selectHistory[this.selectHistory.length - 2]; | ||||||
| 
 | 
 | ||||||
|                 // Remove curent and previous tabs from history.
 |                 // Remove curent and previous tabs from history.
 | ||||||
|                 this.selectHistory = this.selectHistory.filter((tabId) => this.selected != tabId && tabIndex != tabId); |                 this.selectHistory = this.selectHistory.filter((tabId) => this.selected != tabId && previousTabId != tabId); | ||||||
| 
 | 
 | ||||||
|                 this.selectTab(tabIndex); |                 this.selectTab(previousTabId); | ||||||
| 
 | 
 | ||||||
|                 return true; |                 return; | ||||||
|             } else if (this.selected != this.firstSelectedTab) { |             } | ||||||
|  | 
 | ||||||
|  |             if (this.firstSelectedTab && this.selected != this.firstSelectedTab) { | ||||||
|                 // All history is gone but we are not in the first selected tab.
 |                 // All history is gone but we are not in the first selected tab.
 | ||||||
|                 this.selectHistory = []; |                 this.selectHistory = []; | ||||||
| 
 | 
 | ||||||
|                 this.selectTab(this.firstSelectedTab!); |                 this.selectTab(this.firstSelectedTab); | ||||||
| 
 | 
 | ||||||
|                 return true; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return false; |             processNextHandler(); | ||||||
|         }, 750); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * User left the page that contains the component. |      * User left the page that contains the component. | ||||||
|      */ |      */ | ||||||
|     ionViewDidLeave(): void { |     ionViewDidLeave(): void { | ||||||
|         // Unregister the custom back button action for this page
 |         // Unregister the custom back button action for this component.
 | ||||||
|         this.unregisterBackButtonAction && this.unregisterBackButtonAction(); |         document.removeEventListener('ionBackButton', this.backButtonFunction); | ||||||
| 
 | 
 | ||||||
|         this.isCurrentView = false; |         this.isCurrentView = false; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,4 +1,5 @@ | |||||||
| <ion-tabs #mainTabs [hidden]="!showTabs" [class]="'placement-' + tabsPlacement" [class.tabshidden]="hidden"> | <ion-tabs #mainTabs [hidden]="!showTabs" [class]="'placement-' + tabsPlacement" [class.tabshidden]="hidden" | ||||||
|  |     (ionTabsDidChange)="tabChanged($event)"> | ||||||
|     <ion-tab-bar slot="bottom" [hidden]="hidden"> |     <ion-tab-bar slot="bottom" [hidden]="hidden"> | ||||||
|         <ion-spinner *ngIf="!loaded"></ion-spinner> |         <ion-spinner *ngIf="!loaded"></ion-spinner> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ | |||||||
| import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core'; | import { Component, OnInit, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core'; | ||||||
| import { ActivatedRoute, Router } from '@angular/router'; | import { ActivatedRoute, Router } from '@angular/router'; | ||||||
| import { IonTabs } from '@ionic/angular'; | import { IonTabs } from '@ionic/angular'; | ||||||
|  | import { BackButtonEvent } from '@ionic/core'; | ||||||
| import { Subscription } from 'rxjs'; | import { Subscription } from 'rxjs'; | ||||||
| 
 | 
 | ||||||
| import { CoreApp } from '@services/app'; | import { CoreApp } from '@services/app'; | ||||||
| @ -50,6 +51,11 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | |||||||
|     protected pendingRedirect?: CoreRedirectPayload; |     protected pendingRedirect?: CoreRedirectPayload; | ||||||
|     protected urlToOpen?: string; |     protected urlToOpen?: string; | ||||||
|     protected keyboardObserver?: CoreEventObserver; |     protected keyboardObserver?: CoreEventObserver; | ||||||
|  |     protected resizeFunction: () => void; | ||||||
|  |     protected backButtonFunction: (event: BackButtonEvent) => void; | ||||||
|  |     protected selectHistory: string[] = []; | ||||||
|  |     protected selectedTab?: string; | ||||||
|  |     protected firstSelectedTab?: string; | ||||||
| 
 | 
 | ||||||
|     @ViewChild('mainTabs') mainTabs?: IonTabs; |     @ViewChild('mainTabs') mainTabs?: IonTabs; | ||||||
| 
 | 
 | ||||||
| @ -57,7 +63,10 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | |||||||
|         protected route: ActivatedRoute, |         protected route: ActivatedRoute, | ||||||
|         protected changeDetector: ChangeDetectorRef, |         protected changeDetector: ChangeDetectorRef, | ||||||
|         protected router: Router, |         protected router: Router, | ||||||
|     ) {} |     ) { | ||||||
|  |         this.resizeFunction = this.initHandlers.bind(this); | ||||||
|  |         this.backButtonFunction = this.backButtonClicked.bind(this); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Initialize the component. |      * Initialize the component. | ||||||
| @ -100,7 +109,8 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | |||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         window.addEventListener('resize', this.initHandlers.bind(this)); |         window.addEventListener('resize', this.resizeFunction); | ||||||
|  |         document.addEventListener('ionBackButton', this.backButtonFunction); | ||||||
| 
 | 
 | ||||||
|         if (CoreApp.isIOS()) { |         if (CoreApp.isIOS()) { | ||||||
|             // In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
 |             // In iOS, the resize event is triggered before the keyboard is opened/closed and not triggered again once done.
 | ||||||
| @ -209,7 +219,8 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | |||||||
|     ngOnDestroy(): void { |     ngOnDestroy(): void { | ||||||
|         this.subscription?.unsubscribe(); |         this.subscription?.unsubscribe(); | ||||||
|         this.redirectObs?.off(); |         this.redirectObs?.off(); | ||||||
|         window.removeEventListener('resize', this.initHandlers.bind(this)); |         window.removeEventListener('resize', this.resizeFunction); | ||||||
|  |         document.removeEventListener('ionBackButton', this.backButtonFunction); | ||||||
|         this.keyboardObserver?.off(); |         this.keyboardObserver?.off(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -262,4 +273,46 @@ export class CoreMainMenuPage implements OnInit, OnDestroy { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Selected tab has changed. | ||||||
|  |      * | ||||||
|  |      * @param event Event. | ||||||
|  |      */ | ||||||
|  |     tabChanged(event: {tab: string}): void { | ||||||
|  |         this.selectedTab = event.tab; | ||||||
|  |         this.firstSelectedTab = this.firstSelectedTab ?? event.tab; | ||||||
|  |         this.selectHistory.push(event.tab); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Back button clicked. | ||||||
|  |      * | ||||||
|  |      * @param event Event. | ||||||
|  |      */ | ||||||
|  |     protected backButtonClicked(event: BackButtonEvent): void { | ||||||
|  |         event.detail.register(20, (processNextHandler: () => void) => { | ||||||
|  |             if (this.selectHistory.length > 1) { | ||||||
|  |                 // The previous page in history is not the last one, we need the previous one.
 | ||||||
|  |                 const previousTab = this.selectHistory[this.selectHistory.length - 2]; | ||||||
|  | 
 | ||||||
|  |                 // Remove curent and previous tabs from history.
 | ||||||
|  |                 this.selectHistory = this.selectHistory.filter((tab) => this.selectedTab != tab && previousTab != tab); | ||||||
|  | 
 | ||||||
|  |                 this.mainTabs?.select(previousTab); | ||||||
|  | 
 | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (this.firstSelectedTab && this.selectedTab != this.firstSelectedTab) { | ||||||
|  |                 // All history is gone but we are not in the first selected tab.
 | ||||||
|  |                 this.selectHistory = []; | ||||||
|  |                 this.mainTabs?.select(this.firstSelectedTab); | ||||||
|  | 
 | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             processNextHandler(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -56,7 +56,6 @@ export class CoreAppProvider { | |||||||
|     protected isKeyboardShown = false; |     protected isKeyboardShown = false; | ||||||
|     protected keyboardOpening = false; |     protected keyboardOpening = false; | ||||||
|     protected keyboardClosing = false; |     protected keyboardClosing = false; | ||||||
|     protected backActions: {callback: () => boolean; priority: number}[] = []; |  | ||||||
|     protected forceOffline = false; |     protected forceOffline = false; | ||||||
|     protected redirect?: CoreRedirectData; |     protected redirect?: CoreRedirectData; | ||||||
| 
 | 
 | ||||||
| @ -68,11 +67,6 @@ export class CoreAppProvider { | |||||||
|         this.schemaVersionsManager = new Promise(resolve => this.resolveSchemaVersionsManager = resolve); |         this.schemaVersionsManager = new Promise(resolve => this.resolveSchemaVersionsManager = resolve); | ||||||
|         this.db = CoreDB.getDB(DBNAME); |         this.db = CoreDB.getDB(DBNAME); | ||||||
|         this.logger = CoreLogger.getInstance('CoreAppProvider'); |         this.logger = CoreLogger.getInstance('CoreAppProvider'); | ||||||
| 
 |  | ||||||
|         // @todo
 |  | ||||||
|         // this.platform.registerBackButtonAction(() => {
 |  | ||||||
|         //     this.backButtonAction();
 |  | ||||||
|         // }, 100);
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -592,37 +586,18 @@ export class CoreAppProvider { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * The back button event is triggered when the user presses the native |      * Register a back button action. | ||||||
|      * platform's back button, also referred to as the "hardware" back button. |      * This function is deprecated and no longer works. You should now use Ionic events directly, please see: | ||||||
|      * This event is only used within Cordova apps running on Android and |      * https://ionicframework.com/docs/developing/hardware-back-button
 | ||||||
|      * 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 |      * @param callback Called when the back button is pressed. | ||||||
|      * apps to control which action should be called when the hardware back |      * @param priority Priority. | ||||||
|      * button is pressed. This method decides which of the registered back button |  | ||||||
|      * actions has the highest priority and should be called. |  | ||||||
|      * |  | ||||||
|      * @param callback Called when the back button is pressed, if this registered action has the highest priority. |  | ||||||
|      * @param 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). |  | ||||||
|      * @return A function that, when called, will unregister the back button action. |      * @return A function that, when called, will unregister the back button action. | ||||||
|  |      * @deprecated since 3.9.5 | ||||||
|      */ |      */ | ||||||
|     registerBackButtonAction(callback: () => boolean, priority: number = 0): () => boolean { |     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||||
|         const action = { callback, priority }; |     registerBackButtonAction(callback: () => boolean, priority = 0): () => boolean { | ||||||
| 
 |         return () => false; | ||||||
|         this.backActions.push(action); |  | ||||||
| 
 |  | ||||||
|         this.backActions.sort((a, b) => 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