Fix drawer behaviors
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import 'react-native-gesture-handler' // must be first
|
||||||
|
|
||||||
import {LogBox} from 'react-native'
|
import {LogBox} from 'react-native'
|
||||||
LogBox.ignoreLogs(['Require cycle:']) // suppress require-cycle warnings, it's fine
|
LogBox.ignoreLogs(['Require cycle:']) // suppress require-cycle warnings, it's fine
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -70,14 +70,16 @@
|
|||||||
"react-native": "0.71.3",
|
"react-native": "0.71.3",
|
||||||
"react-native-appstate-hook": "^1.0.6",
|
"react-native-appstate-hook": "^1.0.6",
|
||||||
"react-native-background-fetch": "^4.1.8",
|
"react-native-background-fetch": "^4.1.8",
|
||||||
|
"react-native-drawer-layout": "^3.2.0",
|
||||||
"react-native-fast-image": "^8.6.3",
|
"react-native-fast-image": "^8.6.3",
|
||||||
"react-native-fs": "^2.20.0",
|
"react-native-fs": "^2.20.0",
|
||||||
|
"react-native-gesture-handler": "~2.9.0",
|
||||||
"react-native-haptic-feedback": "^1.14.0",
|
"react-native-haptic-feedback": "^1.14.0",
|
||||||
"react-native-image-crop-picker": "^0.38.1",
|
"react-native-image-crop-picker": "^0.38.1",
|
||||||
"react-native-inappbrowser-reborn": "^3.6.3",
|
"react-native-inappbrowser-reborn": "^3.6.3",
|
||||||
"react-native-linear-gradient": "^2.6.2",
|
"react-native-linear-gradient": "^2.6.2",
|
||||||
"react-native-progress": "^5.0.0",
|
"react-native-progress": "^5.0.0",
|
||||||
"react-native-reanimated": "^2.9.1",
|
"react-native-reanimated": "~2.14.4",
|
||||||
"react-native-root-siblings": "^4.1.1",
|
"react-native-root-siblings": "^4.1.1",
|
||||||
"react-native-safe-area-context": "^4.4.1",
|
"react-native-safe-area-context": "^4.4.1",
|
||||||
"react-native-screens": "^3.13.1",
|
"react-native-screens": "^3.13.1",
|
||||||
|
|||||||
@@ -8,6 +8,22 @@ export function getCurrentRoute(state: State) {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isStateAtTabRoot(state: State | undefined) {
|
||||||
|
if (!state) {
|
||||||
|
// NOTE
|
||||||
|
// if state is not defined it's because init is occuring
|
||||||
|
// and therefore we can safely assume we're at root
|
||||||
|
// -prf
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const currentRoute = getCurrentRoute(state)
|
||||||
|
return (
|
||||||
|
isTab(currentRoute.name, 'Home') ||
|
||||||
|
isTab(currentRoute.name, 'Search') ||
|
||||||
|
isTab(currentRoute.name, 'Notifications')
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export function isTab(current: string, route: string) {
|
export function isTab(current: string, route: string) {
|
||||||
// NOTE
|
// NOTE
|
||||||
// our tab routes can be variously referenced by 3 different names
|
// our tab routes can be variously referenced by 3 different names
|
||||||
@@ -19,3 +35,21 @@ export function isTab(current: string, route: string) {
|
|||||||
current === `${route}Inner`
|
current === `${route}Inner`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum TabState {
|
||||||
|
InsideAtRoot,
|
||||||
|
Inside,
|
||||||
|
Outside,
|
||||||
|
}
|
||||||
|
export function getTabState(state: State | undefined, tab: string): TabState {
|
||||||
|
if (!state) {
|
||||||
|
return TabState.Outside
|
||||||
|
}
|
||||||
|
const currentRoute = getCurrentRoute(state)
|
||||||
|
if (isTab(currentRoute.name, tab)) {
|
||||||
|
return TabState.InsideAtRoot
|
||||||
|
} else if (isTab(state.routes[state.index || 0].name, tab)) {
|
||||||
|
return TabState.Inside
|
||||||
|
}
|
||||||
|
return TabState.Outside
|
||||||
|
}
|
||||||
|
|||||||
+1
-19
@@ -20,26 +20,14 @@ export type HomeTabNavigatorParams = CommonNavigatorParams & {
|
|||||||
Home: undefined
|
Home: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HomeDrawerNavigatorParams = {
|
|
||||||
HomeInner: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SearchTabNavigatorParams = CommonNavigatorParams & {
|
export type SearchTabNavigatorParams = CommonNavigatorParams & {
|
||||||
Search: undefined
|
Search: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SearchDrawerNavigatorParams = {
|
|
||||||
SearchInner: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
|
export type NotificationsTabNavigatorParams = CommonNavigatorParams & {
|
||||||
Notifications: undefined
|
Notifications: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotificationsDrawerNavigatorParams = {
|
|
||||||
NotificationsInner: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AllNavigatorParams = CommonNavigatorParams & {
|
export type AllNavigatorParams = CommonNavigatorParams & {
|
||||||
HomeTab: undefined
|
HomeTab: undefined
|
||||||
Home: undefined
|
Home: undefined
|
||||||
@@ -53,13 +41,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
|
|||||||
// this isn't strictly correct but it should be close enough
|
// this isn't strictly correct but it should be close enough
|
||||||
// a TS wizard might be able to get this 100%
|
// a TS wizard might be able to get this 100%
|
||||||
// -prf
|
// -prf
|
||||||
export type NavigationProp = NativeStackNavigationProp<
|
export type NavigationProp = NativeStackNavigationProp<AllNavigatorParams>
|
||||||
CommonNavigatorParams & {
|
|
||||||
HomeTab: undefined
|
|
||||||
NotificationsTab: undefined
|
|
||||||
SearchTab: undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
|
|
||||||
export type State =
|
export type State =
|
||||||
| NavigationState
|
| NavigationState
|
||||||
|
|||||||
+3
-50
@@ -5,16 +5,12 @@ import {
|
|||||||
StackActions,
|
StackActions,
|
||||||
} from '@react-navigation/native'
|
} from '@react-navigation/native'
|
||||||
import {createNativeStackNavigator} from '@react-navigation/native-stack'
|
import {createNativeStackNavigator} from '@react-navigation/native-stack'
|
||||||
import {createDrawerNavigator} from '@react-navigation/drawer'
|
|
||||||
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
|
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HomeTabNavigatorParams,
|
HomeTabNavigatorParams,
|
||||||
HomeDrawerNavigatorParams,
|
|
||||||
SearchTabNavigatorParams,
|
SearchTabNavigatorParams,
|
||||||
SearchDrawerNavigatorParams,
|
|
||||||
NotificationsTabNavigatorParams,
|
NotificationsTabNavigatorParams,
|
||||||
NotificationsDrawerNavigatorParams,
|
|
||||||
AllNavigatorParams,
|
AllNavigatorParams,
|
||||||
State,
|
State,
|
||||||
} from 'lib/routes/types'
|
} from 'lib/routes/types'
|
||||||
@@ -38,12 +34,8 @@ import {LogScreen} from './view/screens/Log'
|
|||||||
|
|
||||||
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
|
||||||
|
|
||||||
const HomeDrawer = createDrawerNavigator<HomeDrawerNavigatorParams>()
|
|
||||||
const HomeTab = createNativeStackNavigator<HomeTabNavigatorParams>()
|
const HomeTab = createNativeStackNavigator<HomeTabNavigatorParams>()
|
||||||
const SearchDrawer = createDrawerNavigator<SearchDrawerNavigatorParams>()
|
|
||||||
const SearchTab = createNativeStackNavigator<SearchTabNavigatorParams>()
|
const SearchTab = createNativeStackNavigator<SearchTabNavigatorParams>()
|
||||||
const NotificationsDrawer =
|
|
||||||
createDrawerNavigator<NotificationsDrawerNavigatorParams>()
|
|
||||||
const NotificationsTab =
|
const NotificationsTab =
|
||||||
createNativeStackNavigator<NotificationsTabNavigatorParams>()
|
createNativeStackNavigator<NotificationsTabNavigatorParams>()
|
||||||
const Tab = createBottomTabNavigator()
|
const Tab = createBottomTabNavigator()
|
||||||
@@ -78,11 +70,8 @@ function r(pattern: string): Route {
|
|||||||
}
|
}
|
||||||
const ROUTES: Record<string, Route> = {
|
const ROUTES: Record<string, Route> = {
|
||||||
Home: r('/'),
|
Home: r('/'),
|
||||||
HomeInner: r('/'),
|
|
||||||
Search: r('/search'),
|
Search: r('/search'),
|
||||||
SearchInner: r('/search'),
|
|
||||||
Notifications: r('/notifications'),
|
Notifications: r('/notifications'),
|
||||||
NotificationsInner: r('/notifications'),
|
|
||||||
Settings: r('/settings'),
|
Settings: r('/settings'),
|
||||||
Profile: r('/profile/:name'),
|
Profile: r('/profile/:name'),
|
||||||
ProfileFollowers: r('/profile/:name/followers'),
|
ProfileFollowers: r('/profile/:name/followers'),
|
||||||
@@ -171,17 +160,6 @@ function commonScreens(Stack: typeof HomeTab) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function HomeDrawerNavigator() {
|
|
||||||
const drawerContent = React.useCallback(props => <Drawer {...props} />, [])
|
|
||||||
return (
|
|
||||||
<HomeDrawer.Navigator
|
|
||||||
drawerContent={drawerContent}
|
|
||||||
screenOptions={{swipeEdgeWidth: 300, headerShown: false}}>
|
|
||||||
<HomeDrawer.Screen name="HomeInner" component={HomeScreen} />
|
|
||||||
</HomeDrawer.Navigator>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function HomeTabNavigator() {
|
function HomeTabNavigator() {
|
||||||
return (
|
return (
|
||||||
<HomeTab.Navigator
|
<HomeTab.Navigator
|
||||||
@@ -190,23 +168,12 @@ function HomeTabNavigator() {
|
|||||||
fullScreenGestureEnabled: true,
|
fullScreenGestureEnabled: true,
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
}}>
|
}}>
|
||||||
<HomeTab.Screen name="Home" component={HomeDrawerNavigator} />
|
<HomeTab.Screen name="Home" component={HomeScreen} />
|
||||||
{commonScreens(HomeTab)}
|
{commonScreens(HomeTab)}
|
||||||
</HomeTab.Navigator>
|
</HomeTab.Navigator>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchDrawerNavigator() {
|
|
||||||
const drawerContent = React.useCallback(props => <Drawer {...props} />, [])
|
|
||||||
return (
|
|
||||||
<SearchDrawer.Navigator
|
|
||||||
drawerContent={drawerContent}
|
|
||||||
screenOptions={{swipeEdgeWidth: 300, headerShown: false}}>
|
|
||||||
<SearchDrawer.Screen name="SearchInner" component={SearchScreen} />
|
|
||||||
</SearchDrawer.Navigator>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function SearchTabNavigator() {
|
function SearchTabNavigator() {
|
||||||
return (
|
return (
|
||||||
<SearchTab.Navigator
|
<SearchTab.Navigator
|
||||||
@@ -215,26 +182,12 @@ function SearchTabNavigator() {
|
|||||||
fullScreenGestureEnabled: true,
|
fullScreenGestureEnabled: true,
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
}}>
|
}}>
|
||||||
<SearchTab.Screen name="Search" component={SearchDrawerNavigator} />
|
<SearchTab.Screen name="Search" component={SearchScreen} />
|
||||||
{commonScreens(SearchTab as typeof HomeTab)}
|
{commonScreens(SearchTab as typeof HomeTab)}
|
||||||
</SearchTab.Navigator>
|
</SearchTab.Navigator>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function NotificationsDrawerNavigator() {
|
|
||||||
const drawerContent = React.useCallback(props => <Drawer {...props} />, [])
|
|
||||||
return (
|
|
||||||
<NotificationsDrawer.Navigator
|
|
||||||
drawerContent={drawerContent}
|
|
||||||
screenOptions={{swipeEdgeWidth: 300, headerShown: false}}>
|
|
||||||
<NotificationsDrawer.Screen
|
|
||||||
name="NotificationsInner"
|
|
||||||
component={NotificationsScreen}
|
|
||||||
/>
|
|
||||||
</NotificationsDrawer.Navigator>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function NotificationsTabNavigator() {
|
function NotificationsTabNavigator() {
|
||||||
return (
|
return (
|
||||||
<NotificationsTab.Navigator
|
<NotificationsTab.Navigator
|
||||||
@@ -245,7 +198,7 @@ function NotificationsTabNavigator() {
|
|||||||
}}>
|
}}>
|
||||||
<NotificationsTab.Screen
|
<NotificationsTab.Screen
|
||||||
name="Notifications"
|
name="Notifications"
|
||||||
component={NotificationsDrawerNavigator}
|
component={NotificationsScreen}
|
||||||
/>
|
/>
|
||||||
{commonScreens(NotificationsTab as typeof HomeTab)}
|
{commonScreens(NotificationsTab as typeof HomeTab)}
|
||||||
</NotificationsTab.Navigator>
|
</NotificationsTab.Navigator>
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ export interface ComposerOpts {
|
|||||||
export class ShellUiModel {
|
export class ShellUiModel {
|
||||||
darkMode = false
|
darkMode = false
|
||||||
minimalShellMode = false
|
minimalShellMode = false
|
||||||
isMainMenuOpen = false
|
isDrawerOpen = false
|
||||||
isModalActive = false
|
isModalActive = false
|
||||||
activeModals: Modal[] = []
|
activeModals: Modal[] = []
|
||||||
isLightboxActive = false
|
isLightboxActive = false
|
||||||
@@ -156,8 +156,12 @@ export class ShellUiModel {
|
|||||||
this.minimalShellMode = v
|
this.minimalShellMode = v
|
||||||
}
|
}
|
||||||
|
|
||||||
setMainMenuOpen(v: boolean) {
|
openDrawer() {
|
||||||
this.isMainMenuOpen = v
|
this.isDrawerOpen = true
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDrawer() {
|
||||||
|
this.isDrawerOpen = false
|
||||||
}
|
}
|
||||||
|
|
||||||
openModal(modal: Modal) {
|
openModal(modal: Modal) {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export const Link = observer(function Link({
|
|||||||
|
|
||||||
if (noFeedback) {
|
if (noFeedback) {
|
||||||
return (
|
return (
|
||||||
<TouchableWithoutFeedback delayPressIn={50} {...props}>
|
<TouchableWithoutFeedback {...props}>
|
||||||
<View style={style} {...props}>
|
<View style={style} {...props}>
|
||||||
{children ? children : <Text>{title || 'link'}</Text>}
|
{children ? children : <Text>{title || 'link'}</Text>}
|
||||||
</View>
|
</View>
|
||||||
@@ -59,7 +59,7 @@ export const Link = observer(function Link({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity delayPressIn={50} style={style} {...props}>
|
<TouchableOpacity style={style} {...props}>
|
||||||
{children ? children : <Text>{title || 'link'}</Text>}
|
{children ? children : <Text>{title || 'link'}</Text>}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ export const ViewHeader = observer(function ViewHeader({
|
|||||||
|
|
||||||
const onPressMenu = React.useCallback(() => {
|
const onPressMenu = React.useCallback(() => {
|
||||||
track('ViewHeader:MenuButtonClicked')
|
track('ViewHeader:MenuButtonClicked')
|
||||||
navigation.dispatch(DrawerActions.openDrawer())
|
store.shell.openDrawer()
|
||||||
}, [track, navigation])
|
}, [track, store])
|
||||||
|
|
||||||
if (typeof canGoBack === 'undefined') {
|
if (typeof canGoBack === 'undefined') {
|
||||||
canGoBack = navigation.canGoBack()
|
canGoBack = navigation.canGoBack()
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import {FlatList, View} from 'react-native'
|
|||||||
import {useFocusEffect, useIsFocused} from '@react-navigation/native'
|
import {useFocusEffect, useIsFocused} from '@react-navigation/native'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import useAppState from 'react-native-appstate-hook'
|
import useAppState from 'react-native-appstate-hook'
|
||||||
import {
|
import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types'
|
||||||
NativeStackScreenProps,
|
|
||||||
HomeDrawerNavigatorParams,
|
|
||||||
} from 'lib/routes/types'
|
|
||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import {Feed} from '../com/posts/Feed'
|
import {Feed} from '../com/posts/Feed'
|
||||||
import {LoadLatestBtn} from '../com/util/LoadLatestBtn'
|
import {LoadLatestBtn} from '../com/util/LoadLatestBtn'
|
||||||
@@ -20,7 +17,7 @@ import {ComposeIcon2} from 'lib/icons'
|
|||||||
|
|
||||||
const HEADER_HEIGHT = 42
|
const HEADER_HEIGHT = 42
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<HomeDrawerNavigatorParams, 'HomeInner'>
|
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||||
export const HomeScreen = observer(function Home(_opts: Props) {
|
export const HomeScreen = observer(function Home(_opts: Props) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const onMainScroll = useOnMainScroll(store)
|
const onMainScroll = useOnMainScroll(store)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {useFocusEffect} from '@react-navigation/native'
|
|||||||
import useAppState from 'react-native-appstate-hook'
|
import useAppState from 'react-native-appstate-hook'
|
||||||
import {
|
import {
|
||||||
NativeStackScreenProps,
|
NativeStackScreenProps,
|
||||||
NotificationsDrawerNavigatorParams,
|
NotificationsTabNavigatorParams,
|
||||||
} from 'lib/routes/types'
|
} from 'lib/routes/types'
|
||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import {Feed} from '../com/notifications/Feed'
|
import {Feed} from '../com/notifications/Feed'
|
||||||
@@ -16,8 +16,8 @@ import {useAnalytics} from 'lib/analytics'
|
|||||||
const NOTIFICATIONS_POLL_INTERVAL = 15e3
|
const NOTIFICATIONS_POLL_INTERVAL = 15e3
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<
|
type Props = NativeStackScreenProps<
|
||||||
NotificationsDrawerNavigatorParams,
|
NotificationsTabNavigatorParams,
|
||||||
'NotificationsInner'
|
'Notifications'
|
||||||
>
|
>
|
||||||
export const NotificationsScreen = ({}: Props) => {
|
export const NotificationsScreen = ({}: Props) => {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
import {ScrollView} from '../com/util/Views'
|
import {ScrollView} from '../com/util/Views'
|
||||||
import {
|
import {
|
||||||
NativeStackScreenProps,
|
NativeStackScreenProps,
|
||||||
SearchDrawerNavigatorParams,
|
SearchTabNavigatorParams,
|
||||||
} from 'lib/routes/types'
|
} from 'lib/routes/types'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {UserAvatar} from '../com/util/UserAvatar'
|
import {UserAvatar} from '../com/util/UserAvatar'
|
||||||
@@ -34,7 +34,7 @@ import {useAnalytics} from 'lib/analytics'
|
|||||||
const MENU_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10}
|
const MENU_HITSLOP = {left: 10, top: 10, right: 30, bottom: 10}
|
||||||
const FIVE_MIN = 5 * 60 * 1e3
|
const FIVE_MIN = 5 * 60 * 1e3
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<SearchDrawerNavigatorParams, 'SearchInner'>
|
type Props = NativeStackScreenProps<SearchTabNavigatorParams, 'Search'>
|
||||||
export const SearchScreen = observer<Props>(({}: Props) => {
|
export const SearchScreen = observer<Props>(({}: Props) => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
} from 'lib/icons'
|
} from 'lib/icons'
|
||||||
import {colors} from 'lib/styles'
|
import {colors} from 'lib/styles'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {getCurrentRoute, isTab} from 'lib/routes/helpers'
|
import {getCurrentRoute, isTab, getTabState, TabState} from 'lib/routes/helpers'
|
||||||
|
|
||||||
export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
|
export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
@@ -60,10 +60,10 @@ export const BottomBar = observer(({navigation}: BottomTabBarProps) => {
|
|||||||
(tab: string) => {
|
(tab: string) => {
|
||||||
track(`MobileShell:${tab}ButtonPressed`)
|
track(`MobileShell:${tab}ButtonPressed`)
|
||||||
const state = navigation.getState()
|
const state = navigation.getState()
|
||||||
const currentRoute = getCurrentRoute(state)
|
const tabState = getTabState(state, tab)
|
||||||
if (isTab(currentRoute.name, tab)) {
|
if (tabState === TabState.InsideAtRoot) {
|
||||||
store.emitScreenSoftReset()
|
store.emitScreenSoftReset()
|
||||||
} else if (isTab(state.routes[state.index].name, tab)) {
|
} else if (tabState === TabState.Inside) {
|
||||||
navigation.dispatch(StackActions.popToTop())
|
navigation.dispatch(StackActions.popToTop())
|
||||||
} else {
|
} else {
|
||||||
navigation.navigate(`${tab}Tab`)
|
navigation.navigate(`${tab}Tab`)
|
||||||
|
|||||||
+30
-29
@@ -9,10 +9,10 @@ import {
|
|||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {
|
import {
|
||||||
DrawerContentComponentProps,
|
useNavigation,
|
||||||
useDrawerStatus,
|
useNavigationState,
|
||||||
} from '@react-navigation/drawer'
|
StackActions,
|
||||||
import {StackActions} from '@react-navigation/native'
|
} from '@react-navigation/native'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {
|
import {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
@@ -38,38 +38,44 @@ import {useTheme} from 'lib/ThemeContext'
|
|||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useAnalytics} from 'lib/analytics'
|
import {useAnalytics} from 'lib/analytics'
|
||||||
import {pluralize} from 'lib/strings/helpers'
|
import {pluralize} from 'lib/strings/helpers'
|
||||||
import {getCurrentRoute, isTab} from 'lib/routes/helpers'
|
import {getCurrentRoute, isTab, getTabState, TabState} from 'lib/routes/helpers'
|
||||||
|
import {NavigationProp} from 'lib/routes/types'
|
||||||
|
|
||||||
export const Drawer = observer(({navigation}: DrawerContentComponentProps) => {
|
export const DrawerContent = observer(() => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const navigation = useNavigation<NavigationProp>()
|
||||||
const {track} = useAnalytics()
|
const {track} = useAnalytics()
|
||||||
const isDrawerOpen = useDrawerStatus() === 'open'
|
const {isAtHome, isAtSearch, isAtNotifications} = useNavigationState(
|
||||||
|
state => {
|
||||||
|
const currentRoute = state ? getCurrentRoute(state) : false
|
||||||
|
return {
|
||||||
|
isAtHome: currentRoute ? isTab(currentRoute.name, 'Home') : true,
|
||||||
|
isAtSearch: currentRoute ? isTab(currentRoute.name, 'Search') : false,
|
||||||
|
isAtNotifications: currentRoute
|
||||||
|
? isTab(currentRoute.name, 'Notifications')
|
||||||
|
: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// events
|
// events
|
||||||
// =
|
// =
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
console.log('Drawer', isDrawerOpen ? 'minimizing' : 'unminimizing', 'shell')
|
|
||||||
store.shell.setMinimalShellMode(isDrawerOpen)
|
|
||||||
}, [isDrawerOpen, store])
|
|
||||||
|
|
||||||
const onPressTab = React.useCallback(
|
const onPressTab = React.useCallback(
|
||||||
(tab: string) => {
|
(tab: string) => {
|
||||||
track('Menu:ItemClicked', {url: tab})
|
track('Menu:ItemClicked', {url: tab})
|
||||||
const state = navigation.getState()
|
const state = navigation.getState()
|
||||||
navigation.closeDrawer()
|
store.shell.closeDrawer()
|
||||||
const currentRoute = getCurrentRoute(state)
|
const tabState = getTabState(state, tab)
|
||||||
if (isTab(currentRoute.name, tab)) {
|
if (tabState === TabState.InsideAtRoot) {
|
||||||
store.emitScreenSoftReset()
|
store.emitScreenSoftReset()
|
||||||
} else if (isTab(state.routes[state.index].name, tab)) {
|
} else if (tabState === TabState.Inside) {
|
||||||
navigation.dispatch(StackActions.popToTop())
|
navigation.dispatch(StackActions.popToTop())
|
||||||
} else {
|
} else {
|
||||||
// wait for drawer anim to finish
|
// @ts-ignore must be Home, Search, or Notifications
|
||||||
setTimeout(() => {
|
navigation.navigate(`${tab}Tab`)
|
||||||
navigation.navigate(`${tab}Tab`)
|
|
||||||
}, 250)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[store, track, navigation],
|
[store, track, navigation],
|
||||||
@@ -90,14 +96,14 @@ export const Drawer = observer(({navigation}: DrawerContentComponentProps) => {
|
|||||||
const onPressProfile = React.useCallback(() => {
|
const onPressProfile = React.useCallback(() => {
|
||||||
track('Menu:ItemClicked', {url: 'Profile'})
|
track('Menu:ItemClicked', {url: 'Profile'})
|
||||||
navigation.navigate('Profile', {name: store.me.handle})
|
navigation.navigate('Profile', {name: store.me.handle})
|
||||||
navigation.closeDrawer()
|
store.shell.closeDrawer()
|
||||||
}, [navigation, track, store.me.handle])
|
}, [navigation, track, store.me.handle, store.shell])
|
||||||
|
|
||||||
const onPressSettings = React.useCallback(() => {
|
const onPressSettings = React.useCallback(() => {
|
||||||
track('Menu:ItemClicked', {url: 'Settings'})
|
track('Menu:ItemClicked', {url: 'Settings'})
|
||||||
navigation.navigate('Settings')
|
navigation.navigate('Settings')
|
||||||
navigation.closeDrawer()
|
store.shell.closeDrawer()
|
||||||
}, [navigation, track])
|
}, [navigation, track, store.shell])
|
||||||
|
|
||||||
const onPressFeedback = () => {
|
const onPressFeedback = () => {
|
||||||
track('Menu:FeedbackClicked')
|
track('Menu:FeedbackClicked')
|
||||||
@@ -146,11 +152,6 @@ export const Drawer = observer(({navigation}: DrawerContentComponentProps) => {
|
|||||||
store.shell.setDarkMode(!store.shell.darkMode)
|
store.shell.setDarkMode(!store.shell.darkMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentRoute = getCurrentRoute(navigation.getState())
|
|
||||||
const isAtHome = isTab(currentRoute.name, 'Home')
|
|
||||||
const isAtSearch = isTab(currentRoute.name, 'Search')
|
|
||||||
const isAtNotifications = isTab(currentRoute.name, 'Notifications')
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
testID="menuView"
|
testID="menuView"
|
||||||
|
|||||||
+51
-19
@@ -2,21 +2,23 @@ import React from 'react'
|
|||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {StatusBar, StyleSheet, useWindowDimensions, View} from 'react-native'
|
import {StatusBar, StyleSheet, useWindowDimensions, View} from 'react-native'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
|
import {Drawer} from 'react-native-drawer-layout'
|
||||||
|
import {useNavigationState} from '@react-navigation/native'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {Login} from 'view/screens/Login'
|
import {Login} from 'view/screens/Login'
|
||||||
import {ModalsContainer} from 'view/com/modals/Modal'
|
import {ModalsContainer} from 'view/com/modals/Modal'
|
||||||
import {Lightbox} from 'view/com/lightbox/Lightbox'
|
import {Lightbox} from 'view/com/lightbox/Lightbox'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||||
|
import {DrawerContent} from './Drawer'
|
||||||
import {Composer} from './Composer'
|
import {Composer} from './Composer'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {RoutesContainer, TabsNavigator} from '../../Routes'
|
import {RoutesContainer, TabsNavigator} from '../../Routes'
|
||||||
|
import {isStateAtTabRoot} from 'lib/routes/helpers'
|
||||||
|
|
||||||
export const Shell: React.FC = observer(() => {
|
const ShellInner = observer(() => {
|
||||||
const theme = useTheme()
|
|
||||||
const pal = usePalette('default')
|
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const winDim = useWindowDimensions()
|
const winDim = useWindowDimensions()
|
||||||
const safeAreaInsets = useSafeAreaInsets()
|
const safeAreaInsets = useSafeAreaInsets()
|
||||||
@@ -24,6 +26,51 @@ export const Shell: React.FC = observer(() => {
|
|||||||
() => ({height: '100%', paddingTop: safeAreaInsets.top}),
|
() => ({height: '100%', paddingTop: safeAreaInsets.top}),
|
||||||
[safeAreaInsets],
|
[safeAreaInsets],
|
||||||
)
|
)
|
||||||
|
const renderDrawerContent = React.useCallback(() => <DrawerContent />, [])
|
||||||
|
const onOpenDrawer = React.useCallback(
|
||||||
|
() => store.shell.openDrawer(),
|
||||||
|
[store],
|
||||||
|
)
|
||||||
|
const onCloseDrawer = React.useCallback(
|
||||||
|
() => store.shell.closeDrawer(),
|
||||||
|
[store],
|
||||||
|
)
|
||||||
|
const canGoBack = useNavigationState(state => !isStateAtTabRoot(state))
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<View style={containerPadding}>
|
||||||
|
<ErrorBoundary>
|
||||||
|
<Drawer
|
||||||
|
renderDrawerContent={renderDrawerContent}
|
||||||
|
open={store.shell.isDrawerOpen}
|
||||||
|
onOpen={onOpenDrawer}
|
||||||
|
onClose={onCloseDrawer}
|
||||||
|
swipeEdgeWidth={winDim.width}
|
||||||
|
swipeEnabled={!canGoBack}>
|
||||||
|
<TabsNavigator />
|
||||||
|
</Drawer>
|
||||||
|
</ErrorBoundary>
|
||||||
|
</View>
|
||||||
|
<ModalsContainer />
|
||||||
|
<Lightbox />
|
||||||
|
<Composer
|
||||||
|
active={store.shell.isComposerActive}
|
||||||
|
onClose={() => store.shell.closeComposer()}
|
||||||
|
winHeight={winDim.height}
|
||||||
|
replyTo={store.shell.composerOpts?.replyTo}
|
||||||
|
imagesOpen={store.shell.composerOpts?.imagesOpen}
|
||||||
|
onPost={store.shell.composerOpts?.onPost}
|
||||||
|
quote={store.shell.composerOpts?.quote}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Shell: React.FC = observer(() => {
|
||||||
|
const theme = useTheme()
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const store = useStores()
|
||||||
|
|
||||||
if (store.hackUpgradeNeeded) {
|
if (store.hackUpgradeNeeded) {
|
||||||
return (
|
return (
|
||||||
@@ -80,22 +127,7 @@ export const Shell: React.FC = observer(() => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<RoutesContainer>
|
<RoutesContainer>
|
||||||
<View style={containerPadding}>
|
<ShellInner />
|
||||||
<ErrorBoundary>
|
|
||||||
<TabsNavigator />
|
|
||||||
</ErrorBoundary>
|
|
||||||
</View>
|
|
||||||
<ModalsContainer />
|
|
||||||
<Lightbox />
|
|
||||||
<Composer
|
|
||||||
active={store.shell.isComposerActive}
|
|
||||||
onClose={() => store.shell.closeComposer()}
|
|
||||||
winHeight={winDim.height}
|
|
||||||
replyTo={store.shell.composerOpts?.replyTo}
|
|
||||||
imagesOpen={store.shell.composerOpts?.imagesOpen}
|
|
||||||
onPost={store.shell.composerOpts?.onPost}
|
|
||||||
quote={store.shell.composerOpts?.quote}
|
|
||||||
/>
|
|
||||||
</RoutesContainer>
|
</RoutesContainer>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13184,6 +13184,13 @@ react-native-dotenv@^3.3.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
dotenv "^16.0.3"
|
dotenv "^16.0.3"
|
||||||
|
|
||||||
|
react-native-drawer-layout@^3.2.0:
|
||||||
|
version "3.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-3.2.0.tgz#1ab05d0bed6bb684353c17c96e1d3e6c1a4e225d"
|
||||||
|
integrity sha512-d/kvzeBhXjqcRGlfkTSB96ZRKH6g6YxJK+gPtUOCOCH5piHpsupgX+tLAHdM8r8NUzN6Tl9656xfJTuVb8Zrgw==
|
||||||
|
dependencies:
|
||||||
|
use-latest-callback "^0.1.5"
|
||||||
|
|
||||||
react-native-fast-image@^8.6.3:
|
react-native-fast-image@^8.6.3:
|
||||||
version "8.6.3"
|
version "8.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz#6edc3f9190092a909d636d93eecbcc54a8822255"
|
resolved "https://registry.yarnpkg.com/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz#6edc3f9190092a909d636d93eecbcc54a8822255"
|
||||||
@@ -13197,7 +13204,7 @@ react-native-fs@^2.20.0:
|
|||||||
base-64 "^0.1.0"
|
base-64 "^0.1.0"
|
||||||
utf8 "^3.0.0"
|
utf8 "^3.0.0"
|
||||||
|
|
||||||
react-native-gesture-handler@^2.5.0:
|
react-native-gesture-handler@~2.9.0:
|
||||||
version "2.9.0"
|
version "2.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz#2f63812e523c646f25b9ad660fc6f75948e51241"
|
resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-2.9.0.tgz#2f63812e523c646f25b9ad660fc6f75948e51241"
|
||||||
integrity sha512-a0BcH3Qb1tgVqUutc6d3VuWQkI1AM3+fJx8dkxzZs9t06qA27QgURYFoklpabuWpsUTzuKRpxleykp25E8m7tg==
|
integrity sha512-a0BcH3Qb1tgVqUutc6d3VuWQkI1AM3+fJx8dkxzZs9t06qA27QgURYFoklpabuWpsUTzuKRpxleykp25E8m7tg==
|
||||||
@@ -13243,7 +13250,7 @@ react-native-progress@^5.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
|
|
||||||
react-native-reanimated@^2.9.1:
|
react-native-reanimated@~2.14.4:
|
||||||
version "2.14.4"
|
version "2.14.4"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.14.4.tgz#3fa3da4e7b99f5dfb28f86bcf24d9d1024d38836"
|
resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.14.4.tgz#3fa3da4e7b99f5dfb28f86bcf24d9d1024d38836"
|
||||||
integrity sha512-DquSbl7P8j4SAmc+kRdd75Ianm8G+IYQ9T4AQ6lrpLVeDkhZmjWI0wkutKWnp6L7c5XNVUrFDUf69dwETLCItQ==
|
integrity sha512-DquSbl7P8j4SAmc+kRdd75Ianm8G+IYQ9T4AQ6lrpLVeDkhZmjWI0wkutKWnp6L7c5XNVUrFDUf69dwETLCItQ==
|
||||||
|
|||||||
Reference in New Issue
Block a user