Extract shell state into separate context (#1824)
* WIP * Add shell state * Integrate new shell state for drawer and minimal shell mode * Replace isDrawerSwipeDisabled * Split shell state into separate contexts to avoid needless re-renders * Fix typo --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
parent
7158157f5f
commit
bfe196bac5
51 changed files with 368 additions and 238 deletions
|
@ -43,11 +43,13 @@ import {NavigationProp} from 'lib/routes/types'
|
|||
import {useNavigationTabState} from 'lib/hooks/useNavigationTabState'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {formatCount, formatCountShortOnly} from 'view/com/util/numeric/format'
|
||||
import {useSetDrawerOpen} from '#/state/shell'
|
||||
|
||||
export const DrawerContent = observer(function DrawerContentImpl() {
|
||||
const theme = useTheme()
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
const navigation = useNavigation<NavigationProp>()
|
||||
const {track} = useAnalytics()
|
||||
const {isAtHome, isAtSearch, isAtFeeds, isAtNotifications, isAtMyProfile} =
|
||||
|
@ -62,7 +64,7 @@ export const DrawerContent = observer(function DrawerContentImpl() {
|
|||
(tab: string) => {
|
||||
track('Menu:ItemClicked', {url: tab})
|
||||
const state = navigation.getState()
|
||||
store.shell.closeDrawer()
|
||||
setDrawerOpen(false)
|
||||
if (isWeb) {
|
||||
// hack because we have flat navigator for web and MyProfile does not exist on the web navigator -ansh
|
||||
if (tab === 'MyProfile') {
|
||||
|
@ -83,7 +85,7 @@ export const DrawerContent = observer(function DrawerContentImpl() {
|
|||
}
|
||||
}
|
||||
},
|
||||
[store, track, navigation],
|
||||
[store, track, navigation, setDrawerOpen],
|
||||
)
|
||||
|
||||
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
|
||||
|
@ -110,20 +112,20 @@ export const DrawerContent = observer(function DrawerContentImpl() {
|
|||
const onPressLists = React.useCallback(() => {
|
||||
track('Menu:ItemClicked', {url: 'Lists'})
|
||||
navigation.navigate('Lists')
|
||||
store.shell.closeDrawer()
|
||||
}, [navigation, track, store.shell])
|
||||
setDrawerOpen(false)
|
||||
}, [navigation, track, setDrawerOpen])
|
||||
|
||||
const onPressModeration = React.useCallback(() => {
|
||||
track('Menu:ItemClicked', {url: 'Moderation'})
|
||||
navigation.navigate('Moderation')
|
||||
store.shell.closeDrawer()
|
||||
}, [navigation, track, store.shell])
|
||||
setDrawerOpen(false)
|
||||
}, [navigation, track, setDrawerOpen])
|
||||
|
||||
const onPressSettings = React.useCallback(() => {
|
||||
track('Menu:ItemClicked', {url: 'Settings'})
|
||||
navigation.navigate('Settings')
|
||||
store.shell.closeDrawer()
|
||||
}, [navigation, track, store.shell])
|
||||
setDrawerOpen(false)
|
||||
}, [navigation, track, setDrawerOpen])
|
||||
|
||||
const onPressFeedback = React.useCallback(() => {
|
||||
track('Menu:FeedbackClicked')
|
||||
|
@ -437,13 +439,14 @@ const InviteCodes = observer(function InviteCodesImpl({
|
|||
}) {
|
||||
const {track} = useAnalytics()
|
||||
const store = useStores()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
const pal = usePalette('default')
|
||||
const {invitesAvailable} = store.me
|
||||
const onPress = React.useCallback(() => {
|
||||
track('Menu:ItemClicked', {url: '#invite-codes'})
|
||||
store.shell.closeDrawer()
|
||||
setDrawerOpen(false)
|
||||
store.shell.openModal({name: 'invite-codes'})
|
||||
}, [store, track])
|
||||
}, [store, track, setDrawerOpen])
|
||||
return (
|
||||
<TouchableOpacity
|
||||
testID="menuItemInviteCodes"
|
||||
|
|
|
@ -37,7 +37,7 @@ export const BottomBar = observer(function BottomBarImpl({
|
|||
const {isAtHome, isAtSearch, isAtFeeds, isAtNotifications, isAtMyProfile} =
|
||||
useNavigationTabState()
|
||||
|
||||
const {footerMinimalShellTransform} = useMinimalShellMode()
|
||||
const {minimalShellMode, footerMinimalShellTransform} = useMinimalShellMode()
|
||||
const {notifications} = store.me
|
||||
|
||||
const onPressTab = React.useCallback(
|
||||
|
@ -83,7 +83,7 @@ export const BottomBar = observer(function BottomBarImpl({
|
|||
pal.border,
|
||||
{paddingBottom: clamp(safeAreaInsets.bottom, 15, 30)},
|
||||
footerMinimalShellTransform,
|
||||
store.shell.minimalShellMode && styles.disabled,
|
||||
minimalShellMode && styles.disabled,
|
||||
]}>
|
||||
<Btn
|
||||
testID="bottomBarHomeBtn"
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
StyleSheet,
|
||||
useWindowDimensions,
|
||||
View,
|
||||
BackHandler,
|
||||
} from 'react-native'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {Drawer} from 'react-native-drawer-layout'
|
||||
|
@ -18,7 +19,6 @@ import {DrawerContent} from './Drawer'
|
|||
import {Composer} from './Composer'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import * as backHandler from 'lib/routes/back-handler'
|
||||
import {RoutesContainer, TabsNavigator} from '../../Navigation'
|
||||
import {isStateAtTabRoot} from 'lib/routes/helpers'
|
||||
import {
|
||||
|
@ -26,9 +26,18 @@ import {
|
|||
initialWindowMetrics,
|
||||
} from 'react-native-safe-area-context'
|
||||
import {useOTAUpdate} from 'lib/hooks/useOTAUpdate'
|
||||
import {
|
||||
useIsDrawerOpen,
|
||||
useSetDrawerOpen,
|
||||
useIsDrawerSwipeDisabled,
|
||||
} from '#/state/shell'
|
||||
import {isAndroid} from 'platform/detection'
|
||||
|
||||
const ShellInner = observer(function ShellInnerImpl() {
|
||||
const store = useStores()
|
||||
const isDrawerOpen = useIsDrawerOpen()
|
||||
const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled()
|
||||
const setIsDrawerOpen = useSetDrawerOpen()
|
||||
useOTAUpdate() // this hook polls for OTA updates every few seconds
|
||||
const winDim = useWindowDimensions()
|
||||
const safeAreaInsets = useSafeAreaInsets()
|
||||
|
@ -38,20 +47,26 @@ const ShellInner = observer(function ShellInnerImpl() {
|
|||
)
|
||||
const renderDrawerContent = React.useCallback(() => <DrawerContent />, [])
|
||||
const onOpenDrawer = React.useCallback(
|
||||
() => store.shell.openDrawer(),
|
||||
[store],
|
||||
() => setIsDrawerOpen(true),
|
||||
[setIsDrawerOpen],
|
||||
)
|
||||
const onCloseDrawer = React.useCallback(
|
||||
() => store.shell.closeDrawer(),
|
||||
[store],
|
||||
() => setIsDrawerOpen(false),
|
||||
[setIsDrawerOpen],
|
||||
)
|
||||
const canGoBack = useNavigationState(state => !isStateAtTabRoot(state))
|
||||
React.useEffect(() => {
|
||||
const listener = backHandler.init(store)
|
||||
return () => {
|
||||
listener()
|
||||
let listener = {remove() {}}
|
||||
if (isAndroid) {
|
||||
listener = BackHandler.addEventListener('hardwareBackPress', () => {
|
||||
setIsDrawerOpen(false)
|
||||
return store.shell.closeAnyActiveElement()
|
||||
})
|
||||
}
|
||||
}, [store])
|
||||
return () => {
|
||||
listener.remove()
|
||||
}
|
||||
}, [store, setIsDrawerOpen])
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -59,14 +74,12 @@ const ShellInner = observer(function ShellInnerImpl() {
|
|||
<ErrorBoundary>
|
||||
<Drawer
|
||||
renderDrawerContent={renderDrawerContent}
|
||||
open={store.shell.isDrawerOpen}
|
||||
open={isDrawerOpen}
|
||||
onOpen={onOpenDrawer}
|
||||
onClose={onCloseDrawer}
|
||||
swipeEdgeWidth={winDim.width / 2}
|
||||
swipeEnabled={
|
||||
!canGoBack &&
|
||||
store.session.hasSession &&
|
||||
!store.shell.isDrawerSwipeDisabled
|
||||
!canGoBack && store.session.hasSession && !isDrawerSwipeDisabled
|
||||
}>
|
||||
<TabsNavigator />
|
||||
</Drawer>
|
||||
|
|
|
@ -17,18 +17,22 @@ import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
|||
import {useNavigation} from '@react-navigation/native'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {useAuxClick} from 'lib/hooks/useAuxClick'
|
||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||
|
||||
const ShellInner = observer(function ShellInnerImpl() {
|
||||
const store = useStores()
|
||||
const isDrawerOpen = useIsDrawerOpen()
|
||||
const setDrawerOpen = useSetDrawerOpen()
|
||||
const {isDesktop, isMobile} = useWebMediaQueries()
|
||||
const navigator = useNavigation<NavigationProp>()
|
||||
useAuxClick()
|
||||
|
||||
useEffect(() => {
|
||||
navigator.addListener('state', () => {
|
||||
setDrawerOpen(false)
|
||||
store.shell.closeAnyActiveElement()
|
||||
})
|
||||
}, [navigator, store.shell])
|
||||
}, [navigator, store.shell, setDrawerOpen])
|
||||
|
||||
const showBottomBar = isMobile && !store.onboarding.isActive
|
||||
const showSideNavs =
|
||||
|
@ -57,9 +61,9 @@ const ShellInner = observer(function ShellInnerImpl() {
|
|||
{showBottomBar && <BottomBarWeb />}
|
||||
<ModalsContainer />
|
||||
<Lightbox />
|
||||
{!isDesktop && store.shell.isDrawerOpen && (
|
||||
{!isDesktop && isDrawerOpen && (
|
||||
<TouchableOpacity
|
||||
onPress={() => store.shell.closeDrawer()}
|
||||
onPress={() => setDrawerOpen(false)}
|
||||
style={styles.drawerMask}
|
||||
accessibilityLabel="Close navigation footer"
|
||||
accessibilityHint="Closes bottom navigation bar">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue