From d676568c61d8be8301ced1f787649d3a8b2f50b0 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Wed, 7 Dec 2022 16:44:21 +0200 Subject: [PATCH] Refactor NavigationStore (#6842) --- app/actions/remote/entry/common.ts | 4 +- app/actions/websocket/posts.ts | 2 +- app/components/option_item/index.tsx | 2 +- .../post_draft/post_input/post_input.tsx | 2 +- app/constants/navigation.ts | 1 - app/constants/screens.ts | 9 -- app/hooks/android_back_handler.ts | 2 +- app/hooks/keyboard_tracking.ts | 2 +- app/init/app.ts | 52 +------ app/init/push_notifications.ts | 4 +- app/products/calls/alerts.ts | 2 +- .../calls/screens/call_screen/call_screen.tsx | 4 +- app/screens/channel/channel.tsx | 2 +- app/screens/custom_status/index.tsx | 2 +- .../custom_status_clear_after/index.tsx | 2 +- .../home/channel_list/channel_list.tsx | 2 +- app/screens/home/index.tsx | 3 +- app/screens/navigation.ts | 73 ++++++---- app/store/navigation_store.ts | 129 +++++++----------- app/utils/theme/index.ts | 2 +- 20 files changed, 120 insertions(+), 181 deletions(-) diff --git a/app/actions/remote/entry/common.ts b/app/actions/remote/entry/common.ts index 6827cc1bbb..f22c4dede6 100644 --- a/app/actions/remote/entry/common.ts +++ b/app/actions/remote/entry/common.ts @@ -546,7 +546,7 @@ export async function handleEntryAfterLoadNavigation( // Switched channels while loading if (!channelMembers.find((m) => m.channel_id === currentChannelIdAfterLoad)) { const tabletDevice = await isTablet(); - const navComponents = NavigationStore.getNavigationComponents(); + const navComponents = NavigationStore.getScreensInStack(); if (tabletDevice || navComponents.includes(Screens.CHANNEL) || navComponents.includes(Screens.THREAD)) { await handleKickFromChannel(serverUrl, currentChannelIdAfterLoad); } else { @@ -555,7 +555,7 @@ export async function handleEntryAfterLoadNavigation( } } else if (currentChannelIdAfterLoad !== initialChannelId) { const tabletDevice = await isTablet(); - const navComponents = NavigationStore.getNavigationComponents(); + const navComponents = NavigationStore.getScreensInStack(); if (tabletDevice || navComponents.includes(Screens.CHANNEL) || navComponents.includes(Screens.THREAD)) { await handleKickFromChannel(serverUrl, currentChannelIdAfterLoad); } else { diff --git a/app/actions/websocket/posts.ts b/app/actions/websocket/posts.ts index 82976d110f..88e5ea87cc 100644 --- a/app/actions/websocket/posts.ts +++ b/app/actions/websocket/posts.ts @@ -129,7 +129,7 @@ export async function handleNewPostEvent(serverUrl: string, msg: WebSocketMessag markAsViewed = true; markAsRead = false; } else if ((post.channel_id === currentChannelId)) { - const isChannelScreenMounted = NavigationStore.getNavigationComponents().includes(Screens.CHANNEL); + const isChannelScreenMounted = NavigationStore.getScreensInStack().includes(Screens.CHANNEL); const isTabletDevice = await isTablet(); if (isChannelScreenMounted || isTabletDevice) { diff --git a/app/components/option_item/index.tsx b/app/components/option_item/index.tsx index 1915e9ae39..dfd8ea3154 100644 --- a/app/components/option_item/index.tsx +++ b/app/components/option_item/index.tsx @@ -271,7 +271,7 @@ const OptionItem = ({ Boolean(info) && {info} diff --git a/app/components/post_draft/post_input/post_input.tsx b/app/components/post_draft/post_input/post_input.tsx index 83cc3834a4..0fe0e1d9e4 100644 --- a/app/components/post_draft/post_input/post_input.tsx +++ b/app/components/post_draft/post_input/post_input.tsx @@ -227,7 +227,7 @@ export default function PostInput({ }, [addFiles, intl]); const handleHardwareEnterPress = useCallback((keyEvent: {pressedKey: string}) => { - const topScreen = NavigationStore.getNavigationTopComponentId(); + const topScreen = NavigationStore.getVisibleScreen(); let sourceScreen = Screens.CHANNEL; if (rootId) { sourceScreen = Screens.THREAD; diff --git a/app/constants/navigation.ts b/app/constants/navigation.ts index b7c1e94e4d..3ef3dd94f7 100644 --- a/app/constants/navigation.ts +++ b/app/constants/navigation.ts @@ -7,7 +7,6 @@ const Navigation = keyMirror({ NAVIGATE_TO_TAB: null, NAVIGATION_HOME: null, NAVIGATION_SHOW_OVERLAY: null, - NAVIGATION_DISMISS_AND_POP_TO_ROOT: null, }); export default Navigation; diff --git a/app/constants/screens.ts b/app/constants/screens.ts index dbc8156951..a5b40dc78d 100644 --- a/app/constants/screens.ts +++ b/app/constants/screens.ts @@ -157,15 +157,6 @@ export const SCREENS_WITH_TRANSPARENT_BACKGROUND = new Set([ USER_PROFILE, ]); -export const OVERLAY_SCREENS = new Set([ - GALLERY, - IN_APP_NOTIFICATION, - REVIEW_APP, - SHARE_FEEDBACK, - SNACK_BAR, - TERMS_OF_SERVICE, -]); - export const NOT_READY = [ CHANNEL_ADD_PEOPLE, CHANNEL_MENTION, diff --git a/app/hooks/android_back_handler.ts b/app/hooks/android_back_handler.ts index 6ac3337225..d789cf5299 100644 --- a/app/hooks/android_back_handler.ts +++ b/app/hooks/android_back_handler.ts @@ -9,7 +9,7 @@ import NavigationStore from '@store/navigation_store'; const useAndroidHardwareBackHandler = (componentId: string, callback: () => void) => { useEffect(() => { const backHandler = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === componentId) { + if (NavigationStore.getVisibleScreen() === componentId) { callback(); return true; } diff --git a/app/hooks/keyboard_tracking.ts b/app/hooks/keyboard_tracking.ts index 8ab934d45e..806b21ff02 100644 --- a/app/hooks/keyboard_tracking.ts +++ b/app/hooks/keyboard_tracking.ts @@ -19,7 +19,7 @@ export const useKeyboardTrackingPaused = (keyboardTrackingRef: RefObject { - const id = NavigationStore.getNavigationTopComponentId(); + const id = NavigationStore.getVisibleScreen(); if (screens.includes(id) && isPostDraftPaused.current) { isPostDraftPaused.current = false; keyboardTrackingRef.current?.resumeTracking(trackerId); diff --git a/app/init/app.ts b/app/init/app.ts index 8e446a7c49..76d6dd0ae3 100644 --- a/app/init/app.ts +++ b/app/init/app.ts @@ -1,11 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {DeviceEventEmitter} from 'react-native'; -import {ComponentDidAppearEvent, ComponentDidDisappearEvent, ModalDismissedEvent, Navigation, ScreenPoppedEvent} from 'react-native-navigation'; - -import {Events, Screens} from '@constants'; -import {OVERLAY_SCREENS} from '@constants/screens'; import DatabaseManager from '@database/manager'; import {getAllServerCredentials} from '@init/credentials'; import {initialLaunch} from '@init/launch'; @@ -16,7 +11,7 @@ import NetworkManager from '@managers/network_manager'; import SessionManager from '@managers/session_manager'; import WebsocketManager from '@managers/websocket_manager'; import {registerScreens} from '@screens/index'; -import NavigationStore from '@store/navigation_store'; +import {registerNavigationListeners} from '@screens/navigation'; let alreadyInitialized = false; let serverCredentials: ServerCredential[]; @@ -46,48 +41,3 @@ export async function start() { registerScreens(); initialLaunch(); } - -function registerNavigationListeners() { - Navigation.events().registerComponentDidAppearListener(screenDidAppearListener); - Navigation.events().registerComponentDidDisappearListener(screenDidDisappearListener); - Navigation.events().registerComponentWillAppearListener(screenWillAppear); - Navigation.events().registerScreenPoppedListener(screenPoppedListener); - Navigation.events().registerModalDismissedListener(modalDismissedListener); -} - -function screenWillAppear({componentId}: ComponentDidAppearEvent) { - if (componentId === Screens.HOME) { - DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); - } -} - -function screenDidAppearListener({componentId, componentType}: ComponentDidAppearEvent) { - if (!OVERLAY_SCREENS.has(componentId) && componentType === 'Component') { - NavigationStore.addNavigationComponentId(componentId); - } -} - -function screenDidDisappearListener({componentId}: ComponentDidDisappearEvent) { - if (componentId !== Screens.HOME) { - if (NavigationStore.getNavigationTopComponentId() === Screens.HOME) { - DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); - } - } -} - -function screenPoppedListener({componentId}: ScreenPoppedEvent) { - NavigationStore.removeNavigationComponentId(componentId); - if (NavigationStore.getNavigationTopComponentId() === Screens.HOME) { - DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); - } -} - -function modalDismissedListener({componentId}: ModalDismissedEvent) { - const topScreen = NavigationStore.getNavigationTopComponentId(); - const topModal = NavigationStore.getNavigationTopModalId(); - const toRemove = topScreen === topModal ? topModal : componentId; - NavigationStore.removeNavigationModal(toRemove); - if (NavigationStore.getNavigationTopComponentId() === Screens.HOME) { - DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); - } -} diff --git a/app/init/push_notifications.ts b/app/init/push_notifications.ts index e0c976a206..ec78be8f7e 100644 --- a/app/init/push_notifications.ts +++ b/app/init/push_notifications.ts @@ -121,11 +121,11 @@ class PushNotifications { const isSameChannelNotification = payload?.channel_id === channelId; const isSameThreadNotification = isThreadNotification && payload?.root_id === EphemeralStore.getCurrentThreadId(); - let isInChannelScreen = NavigationStore.getNavigationTopComponentId() === Screens.CHANNEL; + let isInChannelScreen = NavigationStore.getVisibleScreen() === Screens.CHANNEL; if (isTabletDevice) { isInChannelScreen = NavigationStore.getVisibleTab() === Screens.HOME; } - const isInThreadScreen = NavigationStore.getNavigationTopComponentId() === Screens.THREAD; + const isInThreadScreen = NavigationStore.getVisibleScreen() === Screens.THREAD; // Conditions: // 1. If not in channel screen or thread screen, show the notification diff --git a/app/products/calls/alerts.ts b/app/products/calls/alerts.ts index 9b8c203760..fc954f101d 100644 --- a/app/products/calls/alerts.ts +++ b/app/products/calls/alerts.ts @@ -226,7 +226,7 @@ export const recordingAlert = (isHost: boolean, intl: IntlShape) => { // Need to pop the call screen, if it's somewhere in the stack. await dismissAllModals(); - if (NavigationStore.getNavigationComponents().includes(Screens.CALL)) { + if (NavigationStore.getScreensInStack().includes(Screens.CALL)) { await dismissAllModalsAndPopToScreen(Screens.CALL, 'Call'); Navigation.pop(Screens.CALL).catch(() => null); } diff --git a/app/products/calls/screens/call_screen/call_screen.tsx b/app/products/calls/screens/call_screen/call_screen.tsx index 67e3d3d423..cd694c6163 100644 --- a/app/products/calls/screens/call_screen/call_screen.tsx +++ b/app/products/calls/screens/call_screen/call_screen.tsx @@ -421,7 +421,7 @@ const CallScreen = ({ useEffect(() => { const listener = DeviceEventEmitter.addListener(WebsocketEvents.CALLS_CALL_END, ({channelId}) => { - if (channelId === currentCall?.channelId && NavigationStore.getNavigationTopComponentId() === componentId) { + if (channelId === currentCall?.channelId && NavigationStore.getVisibleScreen() === componentId) { Navigation.pop(componentId); } }); @@ -433,7 +433,7 @@ const CallScreen = ({ // Note: this happens because the screen is "rendered", even after the screen has been popped, and the // currentCall will have already been set to null when those extra renders run. We probably don't ever need // to pop, but just in case. - if (NavigationStore.getNavigationTopComponentId() === componentId) { + if (NavigationStore.getVisibleScreen() === componentId) { // ignore the error because the call screen has likely already been popped async Navigation.pop(componentId).catch(() => null); } diff --git a/app/screens/channel/channel.tsx b/app/screens/channel/channel.tsx index 2e25f1cf5c..bb26e3181c 100644 --- a/app/screens/channel/channel.tsx +++ b/app/screens/channel/channel.tsx @@ -70,7 +70,7 @@ const Channel = ({ let back: NativeEventSubscription|undefined; if (!isTablet && componentId) { back = BackHandler.addEventListener('hardwareBackPress', () => { - if (NavigationStore.getNavigationTopComponentId() === componentId) { + if (NavigationStore.getVisibleScreen() === componentId) { popTopScreen(componentId); return true; } diff --git a/app/screens/custom_status/index.tsx b/app/screens/custom_status/index.tsx index e923a0526a..7c41a8399f 100644 --- a/app/screens/custom_status/index.tsx +++ b/app/screens/custom_status/index.tsx @@ -164,7 +164,7 @@ class CustomStatusModal extends NavigationComponent { onBackPress = () => { const {componentId} = this.props; - if (NavigationStore.getNavigationTopComponentId() === componentId) { + if (NavigationStore.getVisibleScreen() === componentId) { if (this.props.isTablet) { DeviceEventEmitter.emit(Events.ACCOUNT_SELECT_TABLET_VIEW, ''); } else { diff --git a/app/screens/custom_status_clear_after/index.tsx b/app/screens/custom_status_clear_after/index.tsx index 100f77c34c..76aaa8aab0 100644 --- a/app/screens/custom_status_clear_after/index.tsx +++ b/app/screens/custom_status_clear_after/index.tsx @@ -113,7 +113,7 @@ class ClearAfterModal extends NavigationComponent { onBackPress = () => { const {componentId} = this.props; - if (NavigationStore.getNavigationTopComponentId() === componentId) { + if (NavigationStore.getVisibleScreen() === componentId) { if (this.props.isModal) { dismissModal({componentId}); } else { diff --git a/app/screens/home/channel_list/channel_list.tsx b/app/screens/home/channel_list/channel_list.tsx index c547cf9a37..b0902a50bc 100644 --- a/app/screens/home/channel_list/channel_list.tsx +++ b/app/screens/home/channel_list/channel_list.tsx @@ -78,7 +78,7 @@ const ChannelListScreen = (props: ChannelProps) => { const canAddOtherServers = managedConfig?.allowOtherServers !== 'false'; const handleBackPress = useCallback(() => { - const isHomeScreen = NavigationStore.getNavigationTopComponentId() === Screens.HOME; + const isHomeScreen = NavigationStore.getVisibleScreen() === Screens.HOME; const homeTab = NavigationStore.getVisibleTab() === Screens.HOME; const focused = navigation.isFocused() && isHomeScreen && homeTab; diff --git a/app/screens/home/index.tsx b/app/screens/home/index.tsx index 5389ce3f88..ca08e7e66a 100644 --- a/app/screens/home/index.tsx +++ b/app/screens/home/index.tsx @@ -83,8 +83,7 @@ export default function HomeScreen(props: HomeProps) { useEffect(() => { const listener = HWKeyboardEvent.onHWKeyPressed((keyEvent: {pressedKey: string}) => { - const screen = NavigationStore.getAllNavigationComponents(); - if (!screen.includes(Screens.FIND_CHANNELS) && keyEvent.pressedKey === 'find-channels') { + if (!NavigationStore.getScreensInStack().includes(Screens.FIND_CHANNELS) && keyEvent.pressedKey === 'find-channels') { findChannels( intl.formatMessage({id: 'find_channels.title', defaultMessage: 'Find Channels'}), theme, diff --git a/app/screens/navigation.ts b/app/screens/navigation.ts index ece2179a60..c5ba53c199 100644 --- a/app/screens/navigation.ts +++ b/app/screens/navigation.ts @@ -5,11 +5,11 @@ import merge from 'deepmerge'; import {Appearance, DeviceEventEmitter, NativeModules, StatusBar, Platform, Alert} from 'react-native'; -import {ImageResource, Navigation, Options, OptionsModalPresentationStyle, OptionsTopBarButton} from 'react-native-navigation'; +import {ImageResource, Navigation, Options, OptionsModalPresentationStyle, OptionsTopBarButton, ScreenPoppedEvent} from 'react-native-navigation'; import tinyColor from 'tinycolor2'; import CompassIcon from '@components/compass_icon'; -import {Device, Events, Screens, Navigation as NavigationConstants, Launch} from '@constants'; +import {Device, Events, Screens, Launch} from '@constants'; import {NOT_READY} from '@constants/screens'; import {getDefaultThemeByAppearance} from '@context/theme'; import EphemeralStore from '@store/ephemeral_store'; @@ -29,6 +29,45 @@ const alpha = { duration: 150, }; +export function registerNavigationListeners() { + Navigation.events().registerScreenPoppedListener(screenPoppedListener); + Navigation.events().registerCommandListener(registerCommandListener); +} + +function registerCommandListener(name: string, params: any) { + switch (name) { + case 'setRoot': + NavigationStore.clearScreensFromStack(); + NavigationStore.addScreenToStack(params.layout.root.children[0].id); + break; + case 'push': + NavigationStore.addScreenToStack(params.layout.id); + break; + case 'showModal': + NavigationStore.addModalToStack(params.layout.children[0].id); + break; + case 'popToRoot': + NavigationStore.clearScreensFromStack(); + NavigationStore.addScreenToStack(Screens.HOME); + break; + case 'popTo': + NavigationStore.popTo(params.componentId); + break; + case 'dismissModal': + NavigationStore.removeModalFromStack(params.componentId); + break; + } + + if (NavigationStore.getVisibleScreen() === Screens.HOME) { + DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, true); + } +} + +function screenPoppedListener({componentId}: ScreenPoppedEvent) { + // screen pop does not trigger registerCommandListener, but does trigger screenPoppedListener + NavigationStore.removeScreenFromStack(componentId); +} + export const loginAnimationOptions = () => { const theme = getThemeFromState(); return { @@ -159,7 +198,7 @@ Navigation.setDefaultOptions({ Appearance.addChangeListener(() => { const theme = getThemeFromState(); - const screens = NavigationStore.getAllNavigationComponents(); + const screens = NavigationStore.getScreensInStack(); if (screens.includes(Screens.SERVER) || screens.includes(Screens.ONBOARDING)) { for (const screen of screens) { @@ -214,8 +253,6 @@ export function resetToHome(passProps: LaunchProps = {launchType: Launch.Normal} return ''; } - NavigationStore.clearNavigationComponents(); - const stack = { children: [{ component: { @@ -256,8 +293,6 @@ export function resetToSelectServer(passProps: LaunchProps) { const isDark = tinyColor(theme.sidebarBg).isDark(); StatusBar.setBarStyle(isDark ? 'light-content' : 'dark-content'); - NavigationStore.clearNavigationComponents(); - const children = [{ component: { id: Screens.SERVER, @@ -304,8 +339,6 @@ export function resetToOnboarding(passProps: LaunchProps) { const isDark = tinyColor(theme.sidebarBg).isDark(); StatusBar.setBarStyle(isDark ? 'light-content' : 'dark-content'); - NavigationStore.clearNavigationComponents(); - const children = [{ component: { id: Screens.ONBOARDING, @@ -352,8 +385,6 @@ export function resetToTeams() { const isDark = tinyColor(theme.sidebarBg).isDark(); StatusBar.setBarStyle(isDark ? 'light-content' : 'dark-content'); - NavigationStore.clearNavigationComponents(); - return Navigation.setRoot({ root: { stack: { @@ -395,8 +426,7 @@ export function goToScreen(name: string, title: string, passProps = {}, options const theme = getThemeFromState(); const isDark = tinyColor(theme.sidebarBg).isDark(); - const componentId = NavigationStore.getNavigationTopComponentId(); - DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, false); + const componentId = NavigationStore.getVisibleScreen(); const defaultOptions: Options = { layout: { componentBackgroundColor: theme.centerChannelBg, @@ -427,6 +457,8 @@ export function goToScreen(name: string, title: string, passProps = {}, options }, }; + DeviceEventEmitter.emit(Events.TAB_BAR_VISIBLE, false); + return Navigation.push(componentId, { component: { id: name, @@ -441,13 +473,13 @@ export function popTopScreen(screenId?: string) { if (screenId) { Navigation.pop(screenId); } else { - const componentId = NavigationStore.getNavigationTopComponentId(); + const componentId = NavigationStore.getVisibleScreen(); Navigation.pop(componentId); } } export async function popToRoot() { - const componentId = NavigationStore.getNavigationTopComponentId(); + const componentId = NavigationStore.getVisibleScreen(); try { await Navigation.popToRoot(componentId); @@ -460,8 +492,6 @@ export async function popToRoot() { export async function dismissAllModalsAndPopToRoot() { await dismissAllModals(); await popToRoot(); - - DeviceEventEmitter.emit(NavigationConstants.NAVIGATION_DISMISS_AND_POP_TO_ROOT); } /** @@ -474,7 +504,7 @@ export async function dismissAllModalsAndPopToRoot() { */ export async function dismissAllModalsAndPopToScreen(screenId: string, title: string, passProps = {}, options = {}) { await dismissAllModals(); - if (NavigationStore.getNavigationComponents().includes(screenId)) { + if (NavigationStore.getScreensInStack().includes(screenId)) { let mergeOptions = options; if (title) { mergeOptions = merge(mergeOptions, { @@ -533,7 +563,6 @@ export function showModal(name: string, title: string, passProps = {}, options: modal: {swipeToDismiss: false}, }; - NavigationStore.addNavigationModal(name); Navigation.showModal({ stack: { children: [{ @@ -615,11 +644,10 @@ export async function dismissModal(options?: Options & { componentId: string}) { return; } - const componentId = options?.componentId || NavigationStore.getNavigationTopModalId(); + const componentId = options?.componentId || NavigationStore.getVisibleModal(); if (componentId) { try { await Navigation.dismissModal(componentId, options); - NavigationStore.removeNavigationModal(componentId); } catch (error) { // RNN returns a promise rejection if there is no modal to // dismiss. We'll do nothing in this case. @@ -633,9 +661,8 @@ export async function dismissAllModals() { } try { - const modals = [...NavigationStore.getAllNavigationModals()]; + const modals = [...NavigationStore.getModalsInStack()]; for await (const modal of modals) { - NavigationStore.removeNavigationModal(modal); await Navigation.dismissModal(modal, {animations: {dismissModal: {enabled: false}}}); } } catch (error) { diff --git a/app/store/navigation_store.ts b/app/store/navigation_store.ts index f0ea8b38c9..ab7a0a7b46 100644 --- a/app/store/navigation_store.ts +++ b/app/store/navigation_store.ts @@ -2,96 +2,69 @@ // See LICENSE.txt for license information. class NavigationStore { - allNavigationComponentIds: string[] = []; - navigationComponentIdStack: string[] = []; - navigationModalStack: string[] = []; - visibleTab = 'Home'; - tosOpen = false; + private screensInStack: string[] = []; + private modalsInStack: string[] = []; + private visibleTab = 'Home'; + private tosOpen = false; - setToSOpen = (open: boolean) => { - this.tosOpen = open; + addModalToStack = (modalId: string) => { + this.removeModalFromStack(modalId); + this.addScreenToStack(modalId); + this.modalsInStack.unshift(modalId); }; - isToSOpen = () => { - return this.tosOpen; + addScreenToStack = (screenId: string) => { + this.removeScreenFromStack(screenId); + this.screensInStack.unshift(screenId); }; - addNavigationComponentId = (componentId: string) => { - this.addToNavigationComponentIdStack(componentId); - this.addToAllNavigationComponentIds(componentId); + clearScreensFromStack = () => { + this.screensInStack = []; }; - addToAllNavigationComponentIds = (componentId: string) => { - if (!this.allNavigationComponentIds.includes(componentId)) { - this.allNavigationComponentIds.unshift(componentId); - } - }; + getModalsInStack = () => this.modalsInStack; - addToNavigationComponentIdStack = (componentId: string) => { - const index = this.navigationComponentIdStack.indexOf(componentId); - if (index >= 0) { - this.navigationComponentIdStack.splice(index, 1); - } + getScreensInStack = () => this.screensInStack; - this.navigationComponentIdStack.unshift(componentId); - }; + getVisibleModal = () => this.modalsInStack[0]; - addNavigationModal = (componentId: string) => { - this.navigationModalStack.unshift(componentId); - }; - - clearNavigationComponents = () => { - this.navigationComponentIdStack = []; - this.navigationModalStack = []; - this.allNavigationComponentIds = []; - }; - - clearNavigationModals = () => { - this.navigationModalStack = []; - }; - - getAllNavigationComponents = () => this.allNavigationComponentIds; - - getAllNavigationModals = () => this.navigationModalStack; - - getNavigationTopComponentId = () => { - return this.navigationComponentIdStack[0]; - }; - - getNavigationTopModalId = () => { - return this.navigationModalStack[0]; - }; - - getNavigationComponents = () => { - return this.navigationComponentIdStack; - }; + getVisibleScreen = () => this.screensInStack[0]; getVisibleTab = () => this.visibleTab; - hasModalsOpened = () => this.navigationModalStack.length > 0; + hasModalsOpened = () => this.modalsInStack.length > 0; - private removeNavigationComponent = (componentId: string) => { - const index = this.allNavigationComponentIds.indexOf(componentId); - if (index >= 0) { - this.allNavigationComponentIds.splice(index, 1); + isToSOpen = () => this.tosOpen; + + popTo = (screenId: string) => { + const index = this.screensInStack.indexOf(screenId); + if (index > -1) { + this.screensInStack.splice(0, index); } }; - removeNavigationComponentId = (componentId: string) => { - this.removeNavigationComponent(componentId); - const index = this.navigationComponentIdStack.indexOf(componentId); - if (index >= 0) { - this.navigationComponentIdStack.splice(index, 1); + removeScreenFromStack = (screenId: string) => { + const index = this.screensInStack.indexOf(screenId); + if (index > -1) { + this.screensInStack.splice(index, 1); } }; - removeNavigationModal = (componentId: string) => { - this.removeNavigationComponentId(componentId); - const index = this.navigationModalStack.indexOf(componentId); - - if (index >= 0) { - this.navigationModalStack.splice(index, 1); + removeModalFromStack = (modalId: string) => { + const indexInStack = this.screensInStack.indexOf(modalId); + if (indexInStack > -1) { + // This removes all the screens that were on top of the modal + this.screensInStack.splice(0, indexInStack + 1); } + + const index = this.modalsInStack.indexOf(modalId); + if (index > -1) { + this.modalsInStack.splice(index, 1); + } + }; + + setToSOpen = (open: boolean) => { + this.tosOpen = open; }; setVisibleTap = (tab: string) => { @@ -103,15 +76,15 @@ class NavigationStore { * Use this function only if you know what you are doing * this function will run until the screen appears in the stack * and can easily run forever if the screen is never prevesented. - * @param componentId string + * @param screenId string */ - waitUntilScreenHasLoaded = async (componentId: string) => { + waitUntilScreenHasLoaded = async (screenId: string) => { let found = false; while (!found) { // eslint-disable-next-line no-await-in-loop await (new Promise((r) => requestAnimationFrame(r))); - found = this.navigationComponentIdStack.includes(componentId); + found = this.screensInStack.includes(screenId); } }; @@ -119,15 +92,15 @@ class NavigationStore { * Waits until a passed screen is the top screen * Use this function only if you know what you are doing * this function will run until the screen is in the top - * @param componentId string + * @param screenId string */ - waitUntilScreenIsTop = async (componentId: string) => { + waitUntilScreenIsTop = async (screenId: string) => { let found = false; while (!found) { // eslint-disable-next-line no-await-in-loop await (new Promise((r) => requestAnimationFrame(r))); - found = this.getNavigationTopComponentId() === componentId; + found = this.getVisibleScreen() === screenId; } }; @@ -136,15 +109,15 @@ class NavigationStore { * Use this function only if you know what you are doing * this function will run until the screen disappears from the stack * and can easily run forever if the screen is never removed. - * @param componentId string + * @param screenId string */ - waitUntilScreensIsRemoved = async (componentId: string) => { + waitUntilScreensIsRemoved = async (screenId: string) => { let found = false; while (!found) { // eslint-disable-next-line no-await-in-loop await (new Promise((r) => requestAnimationFrame(r))); - found = !this.navigationComponentIdStack.includes(componentId); + found = !this.screensInStack.includes(screenId); } }; } diff --git a/app/utils/theme/index.ts b/app/utils/theme/index.ts index 3f5217e538..6680380397 100644 --- a/app/utils/theme/index.ts +++ b/app/utils/theme/index.ts @@ -117,7 +117,7 @@ export function setNavigatorStyles(componentId: string, theme: Theme, additional } export function setNavigationStackStyles(theme: Theme) { - NavigationStore.allNavigationComponentIds.forEach((componentId) => { + NavigationStore.getScreensInStack().forEach((componentId) => { if (!appearanceControlledScreens.has(componentId)) { setNavigatorStyles(componentId, theme); }