diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-09-05 18:39:28 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-05 08:39:28 -0700 |
commit | daed047bb41bcdac374398b06f87895511ea34a8 (patch) | |
tree | 559fa4d9c0d65eb4fd0c8269ee53a73e5a0d7934 /src/view/shell | |
parent | ee3e08393882a9d72ae9cab5f765ed2885c5a98d (diff) | |
download | voidsky-daed047bb41bcdac374398b06f87895511ea34a8.tar.zst |
[Perf] Drawer gesture perf fix + related cleanup (#8953)
* split drawer layout into own component * don't put props in dep array * memoize pager view
Diffstat (limited to 'src/view/shell')
-rw-r--r-- | src/view/shell/index.tsx | 135 |
1 files changed, 72 insertions, 63 deletions
diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx index 277e5c523..5075f05cb 100644 --- a/src/view/shell/index.tsx +++ b/src/view/shell/index.tsx @@ -45,25 +45,10 @@ import {Composer} from './Composer' import {DrawerContent} from './Drawer' function ShellInner() { - const t = useTheme() - const isDrawerOpen = useIsDrawerOpen() - const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled() - const setIsDrawerOpen = useSetDrawerOpen() const winDim = useWindowDimensions() const insets = useSafeAreaInsets() const {state: policyUpdateState} = usePolicyUpdateContext() - const renderDrawerContent = useCallback(() => <DrawerContent />, []) - const onOpenDrawer = useCallback( - () => setIsDrawerOpen(true), - [setIsDrawerOpen], - ) - const onCloseDrawer = useCallback( - () => setIsDrawerOpen(false), - [setIsDrawerOpen], - ) - const canGoBack = useNavigationState(state => !isStateAtTabRoot(state)) - const {hasSession} = useSession() const closeAnyActiveElement = useCloseAnyActiveElement() useNotificationsRegistration() @@ -102,60 +87,14 @@ function ShellInner() { } }, [dedupe, navigation]) - const swipeEnabled = !canGoBack && hasSession && !isDrawerSwipeDisabled - const [trendingScrollGesture] = useState(() => Gesture.Native()) return ( <> <View style={[a.h_full]}> <ErrorBoundary style={{paddingTop: insets.top, paddingBottom: insets.bottom}}> - <Drawer - renderDrawerContent={renderDrawerContent} - drawerStyle={{width: Math.min(400, winDim.width * 0.8)}} - configureGestureHandler={handler => { - handler = handler.requireExternalGestureToFail( - trendingScrollGesture, - ) - - if (swipeEnabled) { - if (isDrawerOpen) { - return handler.activeOffsetX([-1, 1]) - } else { - return ( - handler - // Any movement to the left is a pager swipe - // so fail the drawer gesture immediately. - .failOffsetX(-1) - // Don't rush declaring that a movement to the right - // is a drawer swipe. It could be a vertical scroll. - .activeOffsetX(5) - ) - } - } else { - // Fail the gesture immediately. - // This seems more reliable than the `swipeEnabled` prop. - // With `swipeEnabled` alone, the gesture may freeze after toggling off/on. - return handler.failOffsetX([0, 0]).failOffsetY([0, 0]) - } - }} - open={isDrawerOpen} - onOpen={onOpenDrawer} - onClose={onCloseDrawer} - swipeEdgeWidth={winDim.width} - swipeMinVelocity={100} - swipeMinDistance={10} - drawerType={isIOS ? 'slide' : 'front'} - overlayStyle={{ - backgroundColor: select(t.name, { - light: 'rgba(0, 57, 117, 0.1)', - dark: isAndroid - ? 'rgba(16, 133, 254, 0.1)' - : 'rgba(1, 82, 168, 0.1)', - dim: 'rgba(10, 13, 16, 0.8)', - }), - }}> + <DrawerLayout> <TabsNavigator /> - </Drawer> + </DrawerLayout> </ErrorBoundary> </View> @@ -182,6 +121,76 @@ function ShellInner() { ) } +function DrawerLayout({children}: {children: React.ReactNode}) { + const t = useTheme() + const isDrawerOpen = useIsDrawerOpen() + const setIsDrawerOpen = useSetDrawerOpen() + const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled() + const winDim = useWindowDimensions() + + const canGoBack = useNavigationState(state => !isStateAtTabRoot(state)) + const {hasSession} = useSession() + + const swipeEnabled = !canGoBack && hasSession && !isDrawerSwipeDisabled + const [trendingScrollGesture] = useState(() => Gesture.Native()) + + const renderDrawerContent = useCallback(() => <DrawerContent />, []) + const onOpenDrawer = useCallback( + () => setIsDrawerOpen(true), + [setIsDrawerOpen], + ) + const onCloseDrawer = useCallback( + () => setIsDrawerOpen(false), + [setIsDrawerOpen], + ) + + return ( + <Drawer + renderDrawerContent={renderDrawerContent} + drawerStyle={{width: Math.min(400, winDim.width * 0.8)}} + configureGestureHandler={handler => { + handler = handler.requireExternalGestureToFail(trendingScrollGesture) + + if (swipeEnabled) { + if (isDrawerOpen) { + return handler.activeOffsetX([-1, 1]) + } else { + return ( + handler + // Any movement to the left is a pager swipe + // so fail the drawer gesture immediately. + .failOffsetX(-1) + // Don't rush declaring that a movement to the right + // is a drawer swipe. It could be a vertical scroll. + .activeOffsetX(5) + ) + } + } else { + // Fail the gesture immediately. + // This seems more reliable than the `swipeEnabled` prop. + // With `swipeEnabled` alone, the gesture may freeze after toggling off/on. + return handler.failOffsetX([0, 0]).failOffsetY([0, 0]) + } + }} + open={isDrawerOpen} + onOpen={onOpenDrawer} + onClose={onCloseDrawer} + swipeEdgeWidth={winDim.width} + swipeMinVelocity={100} + swipeMinDistance={10} + drawerType={isIOS ? 'slide' : 'front'} + overlayStyle={{ + backgroundColor: select(t.name, { + light: 'rgba(0, 57, 117, 0.1)', + dark: isAndroid ? 'rgba(16, 133, 254, 0.1)' : 'rgba(1, 82, 168, 0.1)', + dim: 'rgba(10, 13, 16, 0.8)', + }), + }}> + {children} + </Drawer> + ) +} + export function Shell() { const t = useTheme() const {status: geolocation} = useGeolocationStatus() |