mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {
3 BackHandler,
4 DimensionValue,
5 StyleSheet,
6 useWindowDimensions,
7 View,
8} from 'react-native'
9import {Drawer} from 'react-native-drawer-layout'
10import Animated from 'react-native-reanimated'
11import {useSafeAreaInsets} from 'react-native-safe-area-context'
12import * as NavigationBar from 'expo-navigation-bar'
13import {StatusBar} from 'expo-status-bar'
14import {useNavigationState} from '@react-navigation/native'
15
16import {useSession} from '#/state/session'
17import {
18 useIsDrawerOpen,
19 useIsDrawerSwipeDisabled,
20 useSetDrawerOpen,
21} from '#/state/shell'
22import {useCloseAnyActiveElement} from '#/state/util'
23import {useNotificationsHandler} from 'lib/hooks/useNotificationHandler'
24import {usePalette} from 'lib/hooks/usePalette'
25import {useNotificationsRegistration} from 'lib/notifications/notifications'
26import {isStateAtTabRoot} from 'lib/routes/helpers'
27import {useTheme} from 'lib/ThemeContext'
28import {isAndroid} from 'platform/detection'
29import {useDialogStateContext} from 'state/dialogs'
30import {Lightbox} from 'view/com/lightbox/Lightbox'
31import {ModalsContainer} from 'view/com/modals/Modal'
32import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
33import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
34import {SigninDialog} from '#/components/dialogs/Signin'
35import {Outlet as PortalOutlet} from '#/components/Portal'
36import {NativeTranslationView} from '../../../modules/expo-bluesky-translate'
37import {RoutesContainer, TabsNavigator} from '../../Navigation'
38import {Composer} from './Composer'
39import {DrawerContent} from './Drawer'
40
41function ShellInner() {
42 const isDrawerOpen = useIsDrawerOpen()
43 const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled()
44 const setIsDrawerOpen = useSetDrawerOpen()
45 const winDim = useWindowDimensions()
46 const safeAreaInsets = useSafeAreaInsets()
47 const containerPadding = React.useMemo(
48 () => ({height: '100%' as DimensionValue, paddingTop: safeAreaInsets.top}),
49 [safeAreaInsets],
50 )
51 const renderDrawerContent = React.useCallback(() => <DrawerContent />, [])
52 const onOpenDrawer = React.useCallback(
53 () => setIsDrawerOpen(true),
54 [setIsDrawerOpen],
55 )
56 const onCloseDrawer = React.useCallback(
57 () => setIsDrawerOpen(false),
58 [setIsDrawerOpen],
59 )
60 const canGoBack = useNavigationState(state => !isStateAtTabRoot(state))
61 const {hasSession} = useSession()
62 const closeAnyActiveElement = useCloseAnyActiveElement()
63 const {importantForAccessibility} = useDialogStateContext()
64
65 useNotificationsRegistration()
66 useNotificationsHandler()
67
68 React.useEffect(() => {
69 let listener = {remove() {}}
70 if (isAndroid) {
71 listener = BackHandler.addEventListener('hardwareBackPress', () => {
72 return closeAnyActiveElement()
73 })
74 }
75 return () => {
76 listener.remove()
77 }
78 }, [closeAnyActiveElement])
79
80 return (
81 <>
82 <Animated.View
83 style={containerPadding}
84 importantForAccessibility={importantForAccessibility}>
85 <ErrorBoundary>
86 <Drawer
87 renderDrawerContent={renderDrawerContent}
88 open={isDrawerOpen}
89 onOpen={onOpenDrawer}
90 onClose={onCloseDrawer}
91 swipeEdgeWidth={winDim.width / 2}
92 swipeEnabled={!canGoBack && hasSession && !isDrawerSwipeDisabled}>
93 <TabsNavigator />
94 </Drawer>
95 </ErrorBoundary>
96 </Animated.View>
97 <NativeTranslationView />
98 <Composer winHeight={winDim.height} />
99 <ModalsContainer />
100 <MutedWordsDialog />
101 <SigninDialog />
102 <Lightbox />
103 <PortalOutlet />
104 </>
105 )
106}
107
108export const Shell: React.FC = function ShellImpl() {
109 const pal = usePalette('default')
110 const theme = useTheme()
111 React.useEffect(() => {
112 if (isAndroid) {
113 NavigationBar.setBackgroundColorAsync(theme.palette.default.background)
114 NavigationBar.setBorderColorAsync(theme.palette.default.background)
115 NavigationBar.setButtonStyleAsync(
116 theme.colorScheme === 'dark' ? 'light' : 'dark',
117 )
118 }
119 }, [theme])
120 return (
121 <View testID="mobileShellView" style={[styles.outerContainer, pal.view]}>
122 <StatusBar style={theme.colorScheme === 'dark' ? 'light' : 'dark'} />
123 <RoutesContainer>
124 <ShellInner />
125 </RoutesContainer>
126 </View>
127 )
128}
129
130const styles = StyleSheet.create({
131 outerContainer: {
132 height: '100%',
133 },
134})