diff --git a/native/navigation/options.js b/native/navigation/options.js index b244d466b..6b10aab82 100644 --- a/native/navigation/options.js +++ b/native/navigation/options.js @@ -1,14 +1,46 @@ // @flow -import type { StackOptions } from '@react-navigation/core'; +import type { + StackOptions, + StackCardInterpolationProps, + TransitionPreset, + StackCardInterpolatedStyle, +} from '@react-navigation/core'; +import { TransitionPresets } from '@react-navigation/stack'; import { Platform } from 'react-native'; const defaultStackScreenOptions: StackOptions = { gestureEnabled: Platform.OS === 'ios', animationEnabled: Platform.OS !== 'web' && Platform.OS !== 'windows' && Platform.OS !== 'macos', }; -export { defaultStackScreenOptions }; +const baseTransitionPreset: TransitionPreset = Platform.select({ + ios: TransitionPresets.ModalSlideFromBottomIOS, + default: TransitionPresets.FadeFromBottomAndroid, +}); +const transitionPreset = { + ...baseTransitionPreset, + cardStyleInterpolator: ( + interpolatorProps: StackCardInterpolationProps, + ): StackCardInterpolatedStyle => { + const baseCardStyleInterpolator = + baseTransitionPreset.cardStyleInterpolator(interpolatorProps); + const overlayOpacity = interpolatorProps.current.progress.interpolate({ + inputRange: [0, 1], + outputRange: ([0, 0.7]: number[]), // Flow... + extrapolate: 'clamp', + }); + return { + ...baseCardStyleInterpolator, + overlayStyle: [ + baseCardStyleInterpolator.overlayStyle, + { opacity: overlayOpacity }, + ], + }; + }, +}; + +export { defaultStackScreenOptions, transitionPreset }; diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js index e10db95e9..7ad3fe74e 100644 --- a/native/navigation/root-navigator.react.js +++ b/native/navigation/root-navigator.react.js @@ -1,316 +1,290 @@ // @flow import type { StackNavigationState, StackOptions, StackNavigationEventMap, StackNavigatorProps, ExtraStackNavigatorProps, ParamListBase, StackNavigationHelpers, StackNavigationProp, StackRouterOptions, RouteProp, - StackCardInterpolationProps, - TransitionPreset, } from '@react-navigation/core'; import { createNavigatorFactory, useNavigationBuilder, } from '@react-navigation/native'; -import { StackView, TransitionPresets } from '@react-navigation/stack'; +import { StackView } from '@react-navigation/stack'; import * as React from 'react'; import { Platform } from 'react-native'; import { enableScreens } from 'react-native-screens'; import AppNavigator from './app-navigator.react.js'; import InviteLinkModal from './invite-link-modal.react.js'; -import { defaultStackScreenOptions } from './options.js'; +import { defaultStackScreenOptions, transitionPreset } from './options.js'; import { RootNavigatorContext } from './root-navigator-context.js'; import RootRouter, { type RootRouterExtraNavigationHelpers, type RootRouterNavigationAction, } from './root-router.js'; import { LoggedOutModalRouteName, AppRouteName, ThreadPickerModalRouteName, ImagePasteModalRouteName, AddUsersModalRouteName, CustomServerModalRouteName, ColorSelectorModalRouteName, ComposeSubchannelModalRouteName, SidebarListModalRouteName, SubchannelsListModalRouteName, MessageReactionsModalRouteName, type ScreenParamList, type RootParamList, TermsAndPrivacyRouteName, RegistrationRouteName, InviteLinkModalRouteName, InviteLinkNavigatorRouteName, CommunityCreationRouteName, RolesNavigatorRouteName, QRCodeSignInNavigatorRouteName, UserProfileBottomSheetNavigatorRouteName, KeyserverSelectionBottomSheetRouteName, } from './route-names.js'; import LoggedOutModal from '../account/logged-out-modal.react.js'; import RegistrationNavigator from '../account/registration/registration-navigator.react.js'; import TermsAndPrivacyModal from '../account/terms-and-privacy-modal.react.js'; import ThreadPickerModal from '../calendar/thread-picker-modal.react.js'; import ImagePasteModal from '../chat/image-paste-modal.react.js'; import MessageReactionsModal from '../chat/message-reactions-modal.react.js'; import AddUsersModal from '../chat/settings/add-users-modal.react.js'; import ColorSelectorModal from '../chat/settings/color-selector-modal.react.js'; import ComposeSubchannelModal from '../chat/settings/compose-subchannel-modal.react.js'; import SidebarListModal from '../chat/sidebar-list-modal.react.js'; import SubchannelsListModal from '../chat/subchannels-list-modal.react.js'; import CommunityCreationNavigator from '../community-creation/community-creation-navigator.react.js'; import InviteLinksNavigator from '../invite-links/invite-links-navigator.react.js'; import CustomServerModal from '../profile/custom-server-modal.react.js'; import KeyserverSelectionBottomSheet from '../profile/keyserver-selection-bottom-sheet.react.js'; import QRCodeSignInNavigator from '../qr-code/qr-code-sign-in-navigator.react.js'; import RolesNavigator from '../roles/roles-navigator.react.js'; import UserProfileBottomSheetNavigator from '../user-profile/user-profile-bottom-sheet-navigator.react.js'; enableScreens(); export type RootNavigationHelpers = { ...$Exact>, ...RootRouterExtraNavigationHelpers, ... }; type RootNavigatorProps = StackNavigatorProps>; function RootNavigator({ initialRouteName, children, screenOptions, defaultScreenOptions, screenListeners, id, ...rest }: RootNavigatorProps) { const [keyboardHandlingEnabled, setKeyboardHandlingEnabled] = React.useState(true); const mergedScreenOptions = React.useMemo(() => { if (typeof screenOptions === 'function') { return (input: { +route: RouteProp<>, +navigation: RootNavigationHelpers<>, }) => ({ ...screenOptions(input), keyboardHandlingEnabled, }); } return { ...screenOptions, keyboardHandlingEnabled, }; }, [screenOptions, keyboardHandlingEnabled]); const { state, descriptors, navigation } = useNavigationBuilder< StackNavigationState, RootRouterNavigationAction, StackOptions, StackRouterOptions, RootNavigationHelpers<>, StackNavigationEventMap, ExtraStackNavigatorProps, >(RootRouter, { id, initialRouteName, children, screenOptions: mergedScreenOptions, defaultScreenOptions, screenListeners, }); const rootNavigationContext = React.useMemo( () => ({ setKeyboardHandlingEnabled }), [setKeyboardHandlingEnabled], ); return ( ); } const createRootNavigator = createNavigatorFactory< StackNavigationState, StackOptions, StackNavigationEventMap, RootNavigationHelpers<>, ExtraStackNavigatorProps, >(RootNavigator); -const baseTransitionPreset: TransitionPreset = Platform.select({ - ios: TransitionPresets.ModalSlideFromBottomIOS, - default: TransitionPresets.FadeFromBottomAndroid, -}); -const transitionPreset = { - ...baseTransitionPreset, - cardStyleInterpolator: (interpolatorProps: StackCardInterpolationProps) => { - const baseCardStyleInterpolator = - baseTransitionPreset.cardStyleInterpolator(interpolatorProps); - const overlayOpacity = interpolatorProps.current.progress.interpolate({ - inputRange: [0, 1], - outputRange: ([0, 0.7]: number[]), // Flow... - extrapolate: 'clamp', - }); - return { - ...baseCardStyleInterpolator, - overlayStyle: [ - baseCardStyleInterpolator.overlayStyle, - { opacity: overlayOpacity }, - ], - }; - }, -}; - const defaultScreenOptions = { ...defaultStackScreenOptions, ...transitionPreset, cardStyle: { backgroundColor: 'transparent' }, presentation: 'modal', headerShown: false, }; const disableGesturesScreenOptions = { gestureEnabled: false, }; const modalOverlayScreenOptions = { cardOverlayEnabled: true, presentation: 'transparentModal', }; const termsAndPrivacyModalScreenOptions = { gestureEnabled: false, cardOverlayEnabled: true, presentation: 'transparentModal', }; export type RootRouterNavigationProp< ParamList: ParamListBase = ParamListBase, RouteName: $Keys = $Keys, > = { ...StackNavigationProp, ...RootRouterExtraNavigationHelpers, }; export type RootNavigationProp< RouteName: $Keys = $Keys, > = { ...StackNavigationProp, ...RootRouterExtraNavigationHelpers, }; const Root = createRootNavigator< ScreenParamList, RootParamList, RootNavigationHelpers, >(); function RootComponent(): React.Node { return ( ); } export default RootComponent;