diff --git a/native/navigation/community-drawer-navigator.react.js b/native/navigation/community-drawer-navigator.react.js --- a/native/navigation/community-drawer-navigator.react.js +++ b/native/navigation/community-drawer-navigator.react.js @@ -11,6 +11,8 @@ import { useStyles } from '../themes/colors'; import type { AppNavigationProp } from './app-navigator.react'; import CommunityDrawerContent from './community-drawer-content.react'; +import { drawerSwipeEnabledSelector } from './nav-selectors'; +import { NavContext } from './navigation-context'; import { TabNavigatorRouteName } from './route-names'; import type { NavigationRoute, @@ -40,12 +42,19 @@ function CommunityDrawerNavigator(props: Props): React.Node { const styles = useStyles(unboundStyles); + const navContext = React.useContext(NavContext); + const swipeEnabled = React.useMemo( + () => drawerSwipeEnabledSelector(navContext), + [navContext], + ); + const screenOptions = React.useMemo( () => ({ drawerStyle: styles.drawerStyle, headerShown: false, + swipeEnabled, }), - [styles.drawerStyle], + [styles.drawerStyle, swipeEnabled], ); return ( diff --git a/native/navigation/nav-selectors.js b/native/navigation/nav-selectors.js --- a/native/navigation/nav-selectors.js +++ b/native/navigation/nav-selectors.js @@ -272,6 +272,54 @@ ); } +const drawerSwipeEnabledSelector: ( + context: ?NavContextType, +) => boolean = createSelector( + (context: ?NavContextType) => context && context.state, + (navigationState: ?PossiblyStaleNavigationState) => { + if (!navigationState) { + return true; + } + + // First, we recurse into the navigation state until we find the tab route + // The tab route should always be accessible by recursing through the first + // routes of each subsequent nested navigation state + const [firstRootSubroute] = navigationState.routes; + if (firstRootSubroute.name !== AppRouteName) { + return true; + } + const appState = getStateFromNavigatorRoute(firstRootSubroute); + const [firstAppSubroute] = appState.routes; + if (firstAppSubroute.name !== CommunityDrawerNavigatorRouteName) { + return true; + } + const communityDrawerState = getStateFromNavigatorRoute(firstAppSubroute); + const [firstCommunityDrawerSubroute] = communityDrawerState.routes; + if (firstCommunityDrawerSubroute.name !== TabNavigatorRouteName) { + return true; + } + const tabState = getStateFromNavigatorRoute(firstCommunityDrawerSubroute); + + // Once we have the tab state, we want to figure out if we currently have + // an active StackNavigator + const currentTabSubroute = tabState.routes[tabState.index]; + if (!currentTabSubroute.state) { + return true; + } + const currentTabSubrouteState = getStateFromNavigatorRoute( + currentTabSubroute, + ); + if (currentTabSubrouteState.type !== 'stack') { + return true; + } + + // Finally, we want to disable the swipe gesture if there is a stack with + // more than one subroute, since then the stack will have its own swipe + // gesture that will conflict with the drawer's + return currentTabSubrouteState.routes.length < 2; + }, +); + export { createIsForegroundSelector, useIsAppLoggedIn, @@ -286,4 +334,5 @@ nativeCalendarQuery, nonThreadCalendarQuery, useCalendarQuery, + drawerSwipeEnabledSelector, };