Refactor NavigationStore (#6842)

This commit is contained in:
Elias Nahum
2022-12-07 16:44:21 +02:00
committed by GitHub
parent fe4a0a28f4
commit d676568c61
20 changed files with 120 additions and 181 deletions

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -271,7 +271,7 @@ const OptionItem = ({
Boolean(info) &&
<View style={styles.infoContainer}>
<Text
style={[styles.info, destructive && {color: theme.dndIndicator}]}
style={[styles.info, !actionComponent && styles.iconContainer, destructive && {color: theme.dndIndicator}]}
testID={`${testID}.info`}
>
{info}

View File

@@ -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;

View File

@@ -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;

View File

@@ -157,15 +157,6 @@ export const SCREENS_WITH_TRANSPARENT_BACKGROUND = new Set<string>([
USER_PROFILE,
]);
export const OVERLAY_SCREENS = new Set<string>([
GALLERY,
IN_APP_NOTIFICATION,
REVIEW_APP,
SHARE_FEEDBACK,
SNACK_BAR,
TERMS_OF_SERVICE,
]);
export const NOT_READY = [
CHANNEL_ADD_PEOPLE,
CHANNEL_MENTION,

View File

@@ -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;
}

View File

@@ -19,7 +19,7 @@ export const useKeyboardTrackingPaused = (keyboardTrackingRef: RefObject<Keyboar
});
const commandCompletedListener = Navigation.events().registerCommandCompletedListener(() => {
const id = NavigationStore.getNavigationTopComponentId();
const id = NavigationStore.getVisibleScreen();
if (screens.includes(id) && isPostDraftPaused.current) {
isPostDraftPaused.current = false;
keyboardTrackingRef.current?.resumeTracking(trackerId);

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -164,7 +164,7 @@ class CustomStatusModal extends NavigationComponent<Props, State> {
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 {

View File

@@ -113,7 +113,7 @@ class ClearAfterModal extends NavigationComponent<Props, State> {
onBackPress = () => {
const {componentId} = this.props;
if (NavigationStore.getNavigationTopComponentId() === componentId) {
if (NavigationStore.getVisibleScreen() === componentId) {
if (this.props.isModal) {
dismissModal({componentId});
} else {

View File

@@ -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;

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);
}
};
}

View File

@@ -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);
}