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
+4
View File
@@ -33,6 +33,10 @@
"@react-native-camera-roll/camera-roll": "^5.2.2",
"@react-native-clipboard/clipboard": "^1.10.0",
"@react-native-community/blur": "^4.3.0",
"@react-navigation/bottom-tabs": "^6.5.7",
"@react-navigation/drawer": "^6.6.2",
"@react-navigation/native": "^6.1.6",
"@react-navigation/native-stack": "^6.9.12",
"@segment/analytics-react-native": "^2.10.1",
"@segment/sovran-react-native": "^0.4.5",
"@zxing/text-encoding": "^0.9.0",
+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}>
+88 -3
View File
@@ -2815,6 +2815,66 @@
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
"@react-navigation/bottom-tabs@^6.5.7":
version "6.5.7"
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-6.5.7.tgz#08470c96e0d11481422214bb98f0ff034038856c"
integrity sha512-9oZYyRu2z7+1pr2dX5V54rHFPmlj4ztwQxFe85zwpnGcPtGIsXj7VCIdlHnjRHJBBFCszvJGQpYY6/G2+DfD+A==
dependencies:
"@react-navigation/elements" "^1.3.17"
color "^4.2.3"
warn-once "^0.1.0"
"@react-navigation/core@^6.4.8":
version "6.4.8"
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.8.tgz#a18e106d3c59cdcfc4ce53f7344e219ed35c88ed"
integrity sha512-klZ9Mcf/P2j+5cHMoGyIeurEzyBM2Uq9+NoSFrF6sdV5iCWHLFhrCXuhbBiQ5wVLCKf4lavlkd/DDs47PXs9RQ==
dependencies:
"@react-navigation/routers" "^6.1.8"
escape-string-regexp "^4.0.0"
nanoid "^3.1.23"
query-string "^7.1.3"
react-is "^16.13.0"
use-latest-callback "^0.1.5"
"@react-navigation/drawer@^6.6.2":
version "6.6.2"
resolved "https://registry.yarnpkg.com/@react-navigation/drawer/-/drawer-6.6.2.tgz#8206d00a4b89f1f30640147e0c230267bb83d9ed"
integrity sha512-6qt4guBdz7bkdo/8BLSCcFNdQdSPYyNn05D9cD+VCY3mGThSiD8bRiP9ju+64im7LsSU+bNWXaP8RxA/FtTVQg==
dependencies:
"@react-navigation/elements" "^1.3.17"
color "^4.2.3"
warn-once "^0.1.0"
"@react-navigation/elements@^1.3.17":
version "1.3.17"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.17.tgz#9cb95765940f2841916fc71686598c22a3e4067e"
integrity sha512-sui8AzHm6TxeEvWT/NEXlz3egYvCUog4tlXA4Xlb2Vxvy3purVXDq/XsM56lJl344U5Aj/jDzkVanOTMWyk4UA==
"@react-navigation/native-stack@^6.9.12":
version "6.9.12"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.12.tgz#a09fe43ab2fc4c82a1809e3953021d1da4ead85c"
integrity sha512-kS2zXCWP0Rgt7uWaCUKrRl7U2U1Gp19rM1kyRY2YzBPXhWGVPjQ2ygBp88CTQzjgy8M07H/79jvGiZ0mlEJI+g==
dependencies:
"@react-navigation/elements" "^1.3.17"
warn-once "^0.1.0"
"@react-navigation/native@^6.1.6":
version "6.1.6"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.1.6.tgz#84ff5cf85b91f660470fa9407c06c8ee393d5792"
integrity sha512-14PmSy4JR8HHEk04QkxQ0ZLuqtiQfb4BV9kkMXD2/jI4TZ+yc43OnO6fQ2o9wm+Bq8pY3DxyerC2AjNUz+oH7Q==
dependencies:
"@react-navigation/core" "^6.4.8"
escape-string-regexp "^4.0.0"
fast-deep-equal "^3.1.3"
nanoid "^3.1.23"
"@react-navigation/routers@^6.1.8":
version "6.1.8"
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.8.tgz#ae56b2678dbb5abca5bd7c95d6a8d1abc767cba2"
integrity sha512-CEge+ZLhb1HBrSvv4RwOol7EKLW1QoqVIQlE9TN5MpxS/+VoQvP+cLbuz0Op53/iJfYhtXRFd1ZAd3RTRqto9w==
dependencies:
nanoid "^3.1.23"
"@rollup/plugin-babel@^5.2.0":
version "5.3.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
@@ -5837,7 +5897,7 @@ decimal.js@^10.2.1, decimal.js@^10.4.2:
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
decode-uri-component@^0.2.0:
decode-uri-component@^0.2.0, decode-uri-component@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
@@ -7418,6 +7478,11 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
filter-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
finalhandler@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
@@ -11218,7 +11283,7 @@ nan@^2.14.0:
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
nanoid@^3.3.1, nanoid@^3.3.4:
nanoid@^3.1.23, nanoid@^3.3.1, nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
@@ -12916,6 +12981,16 @@ qs@^6.5.1:
dependencies:
side-channel "^1.0.4"
query-string@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==
dependencies:
decode-uri-component "^0.2.2"
filter-obj "^1.1.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"
querystringify@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
@@ -13072,7 +13147,7 @@ react-freeze@^1.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-is@^16.13.1, react-is@^16.7.0:
react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -14401,6 +14476,11 @@ spdy@^4.0.2:
select-hose "^2.0.0"
spdy-transport "^3.0.0"
split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@@ -14498,6 +14578,11 @@ stream-json@^1.7.4:
dependencies:
stream-chain "^2.2.5"
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
string-hash-64@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/string-hash-64/-/string-hash-64-1.0.3.tgz#0deb56df58678640db5c479ccbbb597aaa0de322"