import { assertExists } from '@ulangi/assert' ; import { Navigation , Options } from '@ulangi/react-native-navigation' ; import { LightBoxState , ScreenName } from '@ulangi/ulangi-common/enums' ; import { SelectionMenu } from '@ulangi/ulangi-common/interfaces' ; import { ObservableLightBox , ObservableThemeStore , } from '@ulangi/ulangi-observable' ; import { debounce } from 'lodash-decorators' ; import { when } from 'mobx' ; import { BackHandler } from 'react-native' ; import { ScreenContainers } from '../../constants/ScreenContainers' ; import { ExtractPassedProps } from '../../types/ExtractPassedProps' ; export class NavigatorDelegate { private static isWaitingToShowLightBox : boolean = false ; private static isWaitingToDismissLightBox : boolean = false ; private componentId : string ; private screenType : undefined | 'full' | 'modal' ; private observableLightBox : ObservableLightBox ; private themeStore : ObservableThemeStore ; public constructor ( componentId , screenType , observableLightBox , themeStore ) { this . componentId = componentId ; this . screenType = screenType ; this . observableLightBox = observableLightBox ; this . themeStore = themeStore ; } public mergeOptions ( options ) { Navigation . mergeOptions ( this . componentId , options ) ; } public push < T extends keyof typeof ScreenContainers > ( screenName , passProps , options ? ) { this . debouncedPush ( screenName , passProps , options ) ; } public showModal < T extends keyof typeof ScreenContainers > ( screenName , passProps , options ? ) { this . debouncedShowModal ( screenName , passProps , options ) ; } public resetTo < T extends keyof typeof ScreenContainers > ( screenName , passProps , options ? ) { Navigation . setStackRoot ( this . componentId , { component : { name : screenName , passProps : { theme : this . themeStore . theme , get passedProps ( ) : ExtractPassedProps < typeof ScreenContainers [ T ] > { return passProps ; } , } , options , } , } ) ; } public dismissScreen ( ) { if ( this . screenType === 'full' ) { this . debouncedPop ( ) ; } else if ( this . screenType === 'modal' ) { this . debouncedDismissModel ( ) ; } } public showLightBox < T extends keyof typeof ScreenContainers > ( screenName , passProps , styles ) { if ( NavigatorDelegate . isWaitingToShowLightBox === false && ( this . observableLightBox . state === LightBoxState . UNMOUNTED || this . observableLightBox . state === LightBoxState . WILL_DISMISS ) ) { NavigatorDelegate . isWaitingToShowLightBox = this . observableLightBox . state === LightBoxState . WILL_DISMISS ; when ( ( ) : boolean => NavigatorDelegate . isWaitingToShowLightBox === false || this . observableLightBox . state === LightBoxState . UNMOUNTED , ( ) : void => { NavigatorDelegate . isWaitingToShowLightBox = false ; this . observableLightBox . state = LightBoxState . WILL_SHOW ; this . handleLightBoxBackButton ( ) ; Navigation . showOverlay ( { component : { name : screenName , passProps : { theme : this . themeStore . theme , styles , get passedProps ( ) : ExtractPassedProps < typeof ScreenContainers [ T ] > { return passProps ; } , } , } , } ) ; } ) ; } } public dismissLightBox ( ) { if ( NavigatorDelegate . isWaitingToDismissLightBox === false && ( this . observableLightBox . state === LightBoxState . WILL_SHOW || this . observableLightBox . state === LightBoxState . MOUNTED ) ) { NavigatorDelegate . isWaitingToDismissLightBox = this . observableLightBox . state === LightBoxState . WILL_SHOW ; when ( ( ) : boolean => NavigatorDelegate . isWaitingToDismissLightBox === false || this . observableLightBox . state === LightBoxState . MOUNTED , ( ) : void => { NavigatorDelegate . isWaitingToDismissLightBox = false ; this . observableLightBox . state = LightBoxState . WILL_DISMISS ; when ( ( ) : boolean => this . observableLightBox . pendingAnimations . length === 0 , ( ) : void => { const componentId = assertExists ( this . observableLightBox . componentId , 'The componentId of the light box should not be null when it is mounted.' ) ; Navigation . dismissOverlay ( componentId ) ; } ) ; } ) ; } } public showSelectionMenu ( selectionMenu , styles ) { this . observableLightBox . selectionMenu = selectionMenu ; this . showLightBox ( ScreenName . LIGHT_BOX_SELECTION_MENU_SCREEN , { } , styles ) ; } private handleLightBoxBackButton ( ) { const handler = ( ) : boolean => { if ( this . observableLightBox . state === LightBoxState . MOUNTED ) { this . dismissLightBox ( ) ; } return true ; } ; when ( ( ) : boolean => this . observableLightBox . state === LightBoxState . WILL_SHOW , ( ) : void => { BackHandler . addEventListener ( 'hardwareBackPress' , handler ) ; } ) ; when ( ( ) : boolean => this . observableLightBox . state === LightBoxState . UNMOUNTED , ( ) : void => { BackHandler . removeEventListener ( 'hardwareBackPress' , handler ) ; } ) ; } @ debounce ( 500 , { leading : true , trailing : false } ) private debouncedPush < T extends keyof typeof ScreenContainers > ( screenName , passProps , options ? ) { Navigation . push ( this . componentId , { component : { name : screenName , passProps : { theme : this . themeStore . theme , screenType : 'full' , get passedProps ( ) : ExtractPassedProps < typeof ScreenContainers [ T ] > { return passProps ; } , } , options , } , } ) ; } @ debounce ( 500 , { leading : true , trailing : false } ) private debouncedShowModal < T extends keyof typeof ScreenContainers > ( screenName , passProps , options ? ) { Navigation . showModal ( { stack : { children : [ { component : { name : screenName , passProps : { theme : this . themeStore . theme , screenType : 'modal' , get passedProps ( ) : ExtractPassedProps < typeof ScreenContainers [ T ] > { return passProps ; } , } , options , } , } , ] , } , } ) ; } @ debounce ( 500 , { leading : true , trailing : false } ) private debouncedPop ( ) { Navigation . pop ( this . componentId ) ; } @ debounce ( 500 , { leading : true , trailing : false } ) private debouncedDismissModel ( ) { Navigation . dismissModal ( this . componentId ) ; } }