WIP Switch to react-navigation

This commit is contained in:
Paul Frazee
2023-03-09 13:45:20 -06:00
parent ce7817d2fb
commit 34050e05be
5 changed files with 389 additions and 68 deletions
+290
View File
@@ -0,0 +1,290 @@
import * as React from 'react'
import {View, Text, Button} from 'react-native'
import {NavigationContainer} from '@react-navigation/native'
import {createNativeStackNavigator} from '@react-navigation/native-stack'
import {createDrawerNavigator} from '@react-navigation/drawer'
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs'
import {
getStateFromPath,
NavigationState,
PartialState,
} from '@react-navigation/native'
type StackNavigatorParamlist = {
FeedList: undefined
Details: {
id: number
name: string
handle: string
date: string
content: string
image: string
avatar: string
comments: number
retweets: number
hearts: number
}
}
type State = NavigationState | Omit<PartialState<NavigationState>, 'stale'>
const PATHS = {
Home: '/',
Notifications: '/notifications',
Search: '/search',
Details: '/details',
Profile: '/profile',
}
const LINKING = {
prefixes: ['bsky://', 'https://bsky.app'],
getPathFromState(state: State, options?: any) {
// TODO add parameterization
let node = state.routes[state.index]
while (node.state?.routes && typeof node.state?.index === 'number') {
node = node.state?.routes[node.state?.index]
}
return PATHS[node.name] || '/'
},
getStateFromPath(path: string, options?: any) {
// TODO add parameterization
let match = 'Home' // TODO should be not found
for (const [name, matcher] of Object.entries(PATHS)) {
if (path === matcher) {
match = name
break
}
}
let container = 'HomeStack'
if (match === 'Notifications') {
container = 'NotificationsStack'
} else if (match === 'Search') {
container = 'SearchStack'
}
return {
routes: [
{
name: container,
state: {
routes: [{name: match}],
},
},
],
}
},
}
const Drawer = createDrawerNavigator()
const HomeStack = createNativeStackNavigator<StackNavigatorParamlist>()
const NotificationsStack = createNativeStackNavigator<StackNavigatorParamlist>()
const SearchStack = createNativeStackNavigator<StackNavigatorParamlist>()
const Tab = createBottomTabNavigator()
function HomeScreen({navigation}) {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.push('Details')}
/>
<Button
title="Go to profile"
onPress={() => navigation.push('Profile')}
/>
</View>
)
}
function NotificationsScreen({navigation}) {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Notifications Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.push('Details')}
/>
<Button
title="Go to profile"
onPress={() => navigation.push('Profile')}
/>
</View>
)
}
function SearchScreen({navigation}) {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Search Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.push('Details')}
/>
<Button
title="Go to profile"
onPress={() => navigation.push('Profile')}
/>
</View>
)
}
function DetailsScreen({navigation}) {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
<Button
title="Go back to first screen in stack"
onPress={() => navigation.popToTop()}
/>
</View>
)
}
function ProfileScreen({navigation}) {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Profile Screen</Text>
<Button
title="Go to Details... again"
onPress={() => navigation.push('Details')}
/>
<Button title="Go to Home" onPress={() => navigation.navigate('Home')} />
<Button title="Go back" onPress={() => navigation.goBack()} />
<Button
title="Go back to first screen in stack"
onPress={() => navigation.popToTop()}
/>
</View>
)
}
function DrawerContent() {
return (
<View>
<Text>Drawer</Text>
</View>
)
}
function commonScreens(Stack: ReturnType<typeof createNativeStackNavigator>) {
return (
<>
<Stack.Screen name="Details" component={DetailsScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</>
)
}
function HomeDrawer() {
return (
<Drawer.Navigator
drawerContent={DrawerContent}
screenOptions={{swipeEdgeWidth: 300}}>
<Drawer.Screen name="HomeInner" component={HomeScreen} />
</Drawer.Navigator>
)
}
function HomeStackNavigator() {
return (
<HomeStack.Navigator
screenOptions={{gestureEnabled: true, fullScreenGestureEnabled: true}}>
<HomeStack.Screen name="Home" component={HomeDrawer} />
{commonScreens(HomeStack)}
</HomeStack.Navigator>
)
}
function NotificationsStackNavigator() {
return (
<NotificationsStack.Navigator
screenOptions={{gestureEnabled: true, fullScreenGestureEnabled: true}}>
<NotificationsStack.Screen
name="Notifications"
component={NotificationsScreen}
/>
{commonScreens(NotificationsStack)}
</NotificationsStack.Navigator>
)
}
function SearchStackNavigator() {
return (
<SearchStack.Navigator
screenOptions={{gestureEnabled: true, fullScreenGestureEnabled: true}}>
<SearchStack.Screen name="Search" component={SearchScreen} />
{commonScreens(SearchStack)}
</SearchStack.Navigator>
)
}
function TabsNavigator() {
return (
<React.Fragment>
<Tab.Navigator initialRouteName="HomeStack" backBehavior="initialRoute">
<Tab.Screen name="HomeStack" component={HomeStackNavigator} />
<Tab.Screen
name="NotificationsStack"
component={NotificationsStackNavigator}
/>
<Tab.Screen name="SearchStack" component={SearchStackNavigator} />
</Tab.Navigator>
</React.Fragment>
)
}
export function Screens() {
return (
<NavigationContainer linking={LINKING}>
<TabsNavigator />
</NavigationContainer>
)
}
/*function TabsNavigator() {
return (
<React.Fragment>
<Tab.Navigator initialRouteName="Feed" backBehavior="initialRoute">
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Notifications" component={NotificationsScreen} />
<Tab.Screen name="Search" component={SearchScreen} />
</Tab.Navigator>
</React.Fragment>
)
}
function DrawerNavigator() {
return (
<Drawer.Navigator drawerContent={DrawerContent}>
<Drawer.Screen name="Root" component={TabsNavigator} />
</Drawer.Navigator>
)
}
function StackNavigator() {
return (
<Stack.Navigator initialRouteName="FeedList">
<Stack.Screen name="FeedList" component={DrawerNavigator} />
<Stack.Screen
name="Details"
component={DetailsScreen}
options={{headerTitle: 'Tweet'}}
/>
</Stack.Navigator>
)
}
export function Screens() {
return (
<NavigationContainer>
<StackNavigator />
</NavigationContainer>
)
}
*/
+3 -65
View File
@@ -28,6 +28,8 @@ import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
import {useTheme} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette'
import {Screens} from '../../screens'
export const MobileShell: React.FC = observer(() => {
const theme = useTheme()
const pal = usePalette('default')
@@ -166,71 +168,7 @@ export const MobileShell: React.FC = observer(() => {
theme.colorScheme === 'dark' ? 'light-content' : 'dark-content'
}
/>
<View style={[styles.innerContainer, {paddingTop: safeAreaInsets.top}]}>
<HorzSwipe
distThresholdDivisor={2.5}
useNativeDriver
panX={swipeGestureInterp}
swipeEnabled
canSwipeLeft={canSwipeLeft}
canSwipeRight={canSwipeRight}
onSwipeStartDirection={onNavSwipeStartDirection}
onSwipeEnd={onNavSwipeEnd}>
<ScreenContainer style={styles.screenContainer}>
{screenRenderDesc.screens.map(
({Com, navIdx, params, key, current, previous}) => {
if (isMenuActive) {
// HACK menu is active, treat current as previous
if (previous) {
previous = false
} else if (current) {
current = false
previous = true
}
}
return (
<Screen
key={key}
style={[StyleSheet.absoluteFill]}
activityState={current ? 2 : previous ? 1 : 0}>
<Animated.View
style={
current ? [styles.screenMask, swipeOpacity] : undefined
}
/>
<Animated.View
style={[
s.h100pct,
screenBg,
current ? [swipeTransform] : undefined,
]}>
<ErrorBoundary>
<Com
params={params}
navIdx={navIdx}
visible={current}
/>
</ErrorBoundary>
</Animated.View>
</Screen>
)
},
)}
</ScreenContainer>
<BottomBar />
{isMenuActive || menuSwipingDirection !== 0 ? (
<TouchableWithoutFeedback
onPress={() => store.shell.setMainMenuOpen(false)}>
<Animated.View style={[styles.screenMask, menuSwipeOpacity]} />
</TouchableWithoutFeedback>
) : undefined}
{shouldRenderMenu && (
<Animated.View style={[styles.menuDrawer, menuSwipeTransform]}>
<Menu onClose={() => store.shell.setMainMenuOpen(false)} />
</Animated.View>
)}
</HorzSwipe>
</View>
<Screens />
<ModalsContainer />
<Lightbox />
<Composer
+4
View File
@@ -17,6 +17,8 @@ import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
import {s, colors} from 'lib/styles'
import {isMobileWeb} from 'platform/detection'
import {Screens} from '../../screens'
export const WebShell: React.FC = observer(() => {
const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
const store = useStores()
@@ -26,6 +28,8 @@ export const WebShell: React.FC = observer(() => {
return <NoMobileWeb />
}
return <Screens />
if (!store.session.hasSession) {
return (
<View style={styles.outerContainer}>