Skip to content

Commit

Permalink
Adjust split router to native stack
Browse files Browse the repository at this point in the history
  • Loading branch information
WojtekBoman committed Dec 2, 2024
1 parent 954a411 commit c7c315e
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 96 deletions.
2 changes: 1 addition & 1 deletion src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
/>
<RootStack.Screen
name={SCREENS.SEARCH.CENTRAL_PANE}
options={rootNavigatorOptions.fullScreen}
options={rootNavigatorOptions.searchPage}
getComponent={loadSearchPage}
initialParams={{q: SearchQueryUtils.buildSearchQueryString()}}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {useRoute} from '@react-navigation/native';
import React, {useRef} from 'react';
import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
import usePermissions from '@hooks/usePermissions';
import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator';
import FreezeWrapper from '@libs/Navigation/AppNavigator/FreezeWrapper';
import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions';
import getCurrentUrl from '@libs/Navigation/currentUrl';
import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom';
import type {ReportsSplitNavigatorParamList} from '@libs/Navigation/types';
Expand All @@ -20,7 +22,8 @@ const Stack = createSplitStackNavigator<ReportsSplitNavigatorParamList>();
function ReportsSplitNavigator() {
const {canUseDefaultRooms} = usePermissions();
const {activeWorkspaceID} = useActiveWorkspace();

const rootNavigatorOptions = useRootNavigatorOptions();
const route = useRoute();
let initialReportID: string | undefined;
const isInitialRender = useRef(true);

Expand All @@ -47,10 +50,13 @@ function ReportsSplitNavigator() {
<Stack.Navigator
sidebarScreen={SCREENS.HOME}
defaultCentralScreen={SCREENS.REPORT}
parentRoute={route}
screenOptions={rootNavigatorOptions.centralPaneNavigator}
>
<Stack.Screen
name={SCREENS.HOME}
getComponent={loadSidebarScreen}
options={rootNavigatorOptions.homeScreen}
/>
<Stack.Screen
name={SCREENS.REPORT}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import {useRoute} from '@react-navigation/native';
import React from 'react';
import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator';
import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions';
import type {SettingsSplitNavigatorParamList} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
Expand All @@ -27,33 +29,36 @@ const CENTRAL_PANE_SETTINGS_SCREENS = {
const Stack = createSplitStackNavigator<SettingsSplitNavigatorParamList>();

function SettingsSplitNavigator() {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const screenOptions = useRootNavigatorOptions();
const route = useRoute();
const rootNavigatorOptions = useRootNavigatorOptions();

return (
<FocusTrapForScreens>
<Stack.Navigator
sidebarScreen={SCREENS.SETTINGS.ROOT}
defaultCentralScreen={SCREENS.SETTINGS.PROFILE.ROOT}
parentRoute={route}
screenOptions={rootNavigatorOptions.centralPaneNavigator}
>
<Stack.Screen
name={SCREENS.SETTINGS.ROOT}
getComponent={loadInitialSettingsPage}
options={rootNavigatorOptions.homeScreen}
/>
{Object.entries(CENTRAL_PANE_SETTINGS_SCREENS).map(([screenName, componentGetter]) => {
// const options = {...screenOptions.centralPaneNavigator};
const options = {...screenOptions.fullScreen};

// if (screenName === SCREENS.SETTINGS.WORKSPACES) {
// options.animationEnabled = false;
// }
if (screenName === SCREENS.SETTINGS.WORKSPACES) {
options.animation = 'none';
}

return (
<Stack.Screen
key={screenName}
name={screenName as keyof Screens}
getComponent={componentGetter}
// options={options}
options={options}
/>
);
})}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {useRoute} from '@react-navigation/native';
import React from 'react';
import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen';
import createSplitStackNavigator from '@libs/Navigation/AppNavigator/createSplitStackNavigator';
import useRootNavigatorOptions from '@libs/Navigation/AppNavigator/useRootNavigatorOptions';
import type {WorkspaceSplitNavigatorParamList} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
Expand Down Expand Up @@ -30,15 +32,21 @@ const CENTRAL_PANE_WORKSPACE_SCREENS = {
const Stack = createSplitStackNavigator<WorkspaceSplitNavigatorParamList>();

function WorkspaceNavigator() {
const route = useRoute();
const rootNavigatorOptions = useRootNavigatorOptions();

return (
<FocusTrapForScreens>
<Stack.Navigator
sidebarScreen={SCREENS.WORKSPACE.INITIAL}
defaultCentralScreen={SCREENS.WORKSPACE.PROFILE}
parentRoute={route}
screenOptions={rootNavigatorOptions.centralPaneNavigator}
>
<Stack.Screen
name={SCREENS.WORKSPACE.INITIAL}
getComponent={loadWorkspaceInitialPage}
options={rootNavigatorOptions.homeScreen}
/>
{Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => (
<Stack.Screen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import {findFocusedRoute, StackRouter} from '@react-navigation/native';
import type {ParamListBase} from '@react-navigation/routers';
import useActiveWorkspace from '@hooks/useActiveWorkspace';
import * as Localize from '@libs/Localize';
import * as GetStateForActionHandlers from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator/GetStateForActionHandlers';
import syncBrowserHistory from '@libs/Navigation/AppNavigator/createResponsiveStackNavigator/syncBrowserHistory';
import isSideModalNavigator from '@libs/Navigation/isSideModalNavigator';
import {isOnboardingFlowName} from '@libs/NavigationUtils';
import * as Welcome from '@userActions/Welcome';
import CONST from '@src/CONST';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import * as GetStateForActionHandlers from './GetStateForActionHandlers';
import syncBrowserHistory from './syncBrowserHistory';
import type {CustomRouterAction, CustomRouterActionType, DismissModalActionType, PushActionType, ResponsiveStackNavigatorRouterOptions, SwitchPolicyIdActionType} from './types';

function isSwitchPolicyIdAction(action: CustomRouterAction): action is SwitchPolicyIdActionType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@ import {createNavigatorFactory} from '@react-navigation/native';
import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange';
import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent';
import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions';
import type {PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types';
import CustomRouter from './CustomRouter';
import RenderSearchRoute from './SearchRoute';
import useStateWithSearch from './useStateWithSearch';
import type {CustomStateHookProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types';
import {isFullScreenName} from '@libs/NavigationUtils';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';

const loadCustomRouter = require<ReactComponentModule>('@libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter').default;

function useCustomRouterState({state}: CustomStateHookProps) {
const lastSplitIndex = state.routes.findLastIndex((route) => isFullScreenName(route.name));
const routesToRender = state.routes.slice(Math.max(0, lastSplitIndex - 1), state.routes.length);

return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}};
}

const ResponsiveStackNavigatorComponent = createPlatformStackNavigatorComponent('ResponsiveStackNavigator', {
createRouter: CustomRouter,
createRouter: loadCustomRouter,
defaultScreenOptions: defaultPlatformStackScreenOptions,
useCustomState: useStateWithSearch,
useCustomEffects: useNavigationResetOnLayoutChange,
ExtraContent: RenderSearchRoute,
useCustomState: useCustomRouterState,
});

function createResponsiveStackNavigator<ParamList extends ParamListBase>() {
Expand Down
105 changes: 33 additions & 72 deletions src/libs/Navigation/AppNavigator/createSplitStackNavigator/index.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,50 @@
import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native';
import {createNavigatorFactory, useNavigationBuilder, useRoute} from '@react-navigation/native';
import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
import {StackView} from '@react-navigation/stack';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import FocusTrapForScreens from '@components/FocusTrap/FocusTrapForScreen';
import type {ParamListBase} from '@react-navigation/native';
import {createNavigatorFactory} from '@react-navigation/native';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions';
import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange';
import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent';
import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions';
import type {
CustomEffectsHookProps,
CustomStateHookProps,
PlatformStackNavigationEventMap,
PlatformStackNavigationOptions,
PlatformStackNavigationState,
} from '@libs/Navigation/PlatformStackNavigation/types';
import SplitStackRouter from './SplitStackRouter';
import type {SplitStackNavigatorProps, SplitStackNavigatorRouterOptions} from './types';
import useHandleScreenResize from './useHandleScreenResize';
import usePrepareSplitStackNavigatorChildren from './usePrepareSplitStackNavigatorChildren';
import usePreserveSplitNavigatorState from './usePreserveSplitNavigatorState';

function getStateToRender(state: StackNavigationState<ParamListBase>, isSmallScreenWidth: boolean): StackNavigationState<ParamListBase> {
function useCustomEffects(props: CustomEffectsHookProps, route) {
useNavigationResetOnLayoutChange(props);
usePreserveSplitNavigatorState(route, props.navigation.getState());
}

function useCustomSplitNavigatorState({state}: CustomStateHookProps) {
const {shouldUseNarrowLayout} = useResponsiveLayout();

const sidebarScreenRoute = state.routes.at(0);

if (!sidebarScreenRoute) {
return state;
}

const centralScreenRoutes = state.routes.slice(1);
const routes = isSmallScreenWidth ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)];
const routesToRender = shouldUseNarrowLayout ? state.routes.slice(-2) : [sidebarScreenRoute, ...centralScreenRoutes.slice(-2)];

return {
...state,
routes,
index: routes.length - 1,
};
return {stateToRender: {...state, routes: routesToRender, index: routesToRender.length - 1}};
}

function SplitStackNavigator<ParamList extends ParamListBase>(props: SplitStackNavigatorProps<ParamList>) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {shouldUseNarrowLayout} = useResponsiveLayout();


// const children = usePrepareSplitStackNavigatorChildren(props.children, props.sidebarScreen, screenOptions.homeScreen);

const route = useRoute();
const CustomFullScreenNavigatorComponent = createPlatformStackNavigatorComponent('CustomFullScreenNavigator', {
createRouter: SplitStackRouter,
useCustomEffects,
defaultScreenOptions: defaultPlatformStackScreenOptions,
useCustomState: useCustomSplitNavigatorState,
});

const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
StackNavigationState<ParamListBase>,
SplitStackNavigatorRouterOptions,
StackActionHelpers<ParamListBase>,
StackNavigationOptions,
StackNavigationEventMap
>(SplitStackRouter, {
children: props.children,
// screenOptions: screenOptions.centralPaneNavigator,
initialRouteName: props.initialRouteName,
sidebarScreen: props.sidebarScreen,
defaultCentralScreen: props.defaultCentralScreen,
parentRoute: route,
});

// We need to copy the state to the params so that the state is preserved when the root navigator unmount this route for performance reasons.
usePreserveSplitNavigatorState(route, state);
useHandleScreenResize(navigation);

const stateToRender = useMemo(() => getStateToRender(state, shouldUseNarrowLayout), [state, shouldUseNarrowLayout]);

return (
<FocusTrapForScreens>
<View style={styles.rootNavigatorContainerStyles(shouldUseNarrowLayout)}>
<NavigationContent>
<StackView
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
state={stateToRender}
descriptors={descriptors}
navigation={navigation}
/>
</NavigationContent>
</View>
</FocusTrapForScreens>
);
}

SplitStackNavigator.displayName = 'SplitStackNavigator';

export default function <ParamList extends ParamListBase>() {
return createNavigatorFactory<StackNavigationState<ParamList>, StackNavigationOptions, StackNavigationEventMap, React.ComponentType<SplitStackNavigatorProps<ParamList>>>(
SplitStackNavigator,
function createCustomFullScreenNavigator<ParamList extends ParamListBase>() {
return createNavigatorFactory<PlatformStackNavigationState<ParamList>, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomFullScreenNavigatorComponent>(
CustomFullScreenNavigatorComponent,
)<ParamList>();
}

export default createCustomFullScreenNavigator;
17 changes: 16 additions & 1 deletion src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,22 @@ const useRootNavigatorOptions = () => {
fullScreen: {
...commonScreenOptions,
// We need to turn off animation for the full screen to avoid delay when closing screens.
animation: shouldUseNarrowLayout ? Animations.SLIDE_FROM_RIGHT : Animations.NONE,
animation: Animations.NONE,
web: {
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}),
cardStyle: {
...StyleUtils.getNavigationModalCardStyle(),

// This is necessary to cover whole screen. Including translated sidebar.
// marginLeft: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth,
},
},
},

searchPage: {
...commonScreenOptions,
// We need to turn off animation for the full screen to avoid delay when closing screens.
animation: Animations.NONE,
web: {
cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}),
cardStyle: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
const ExtraContent = options?.ExtraContent;
const NavigationContentWrapper = options?.NavigationContentWrapper;

function PlatformNavigator({id, initialRouteName, screenOptions, screenListeners, children, ...props}: PlatformStackNavigatorProps<ParamListBase>) {
function PlatformNavigator({
id,
initialRouteName,
screenOptions,
screenListeners,
children,
sidebarScreen,
defaultCentralScreen,
parentRoute,
...props
}: PlatformStackNavigatorProps<ParamListBase>) {
const {
navigation,
state: originalState,
Expand All @@ -47,6 +57,9 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
defaultScreenOptions,
screenListeners,
initialRouteName,
sidebarScreen,
defaultCentralScreen,
parentRoute,
} as PlatformNavigationBuilderOptions<PlatformStackNavigationOptions, NativeStackNavigationEventMap, ParamListBase, RouterOptions>,
convertToNativeNavigationOptions,
);
Expand All @@ -73,7 +86,7 @@ function createPlatformStackNavigatorComponent<RouterOptions extends PlatformSta
);

// Executes custom effects defined in "useCustomEffects" navigator option.
useCustomEffects(customCodePropsWithCustomState);
useCustomEffects(customCodePropsWithCustomState, parentRoute);

const Content = useMemo(
() => (
Expand Down
Loading

0 comments on commit c7c315e

Please sign in to comment.