2023-03-13 22:01:43 +01:00
import * as React from 'react'
import { StyleSheet } from 'react-native'
2023-10-27 05:06:40 +02:00
import * as SplashScreen from 'expo-splash-screen'
2023-03-13 22:01:43 +01:00
import {
NavigationContainer ,
createNavigationContainerRef ,
2023-04-21 19:21:38 +02:00
CommonActions ,
2023-03-13 22:01:43 +01:00
StackActions ,
2023-04-24 23:36:05 +02:00
DefaultTheme ,
DarkTheme ,
2023-03-13 22:01:43 +01:00
} from '@react-navigation/native'
2023-06-22 18:40:32 +02:00
import {
BottomTabBarProps ,
createBottomTabNavigator ,
} from '@react-navigation/bottom-tabs'
2023-03-13 22:01:43 +01:00
import {
HomeTabNavigatorParams ,
SearchTabNavigatorParams ,
2023-05-26 03:02:37 +02:00
FeedsTabNavigatorParams ,
2023-03-13 22:01:43 +01:00
NotificationsTabNavigatorParams ,
FlatNavigatorParams ,
AllNavigatorParams ,
2023-04-18 18:19:37 +02:00
MyProfileTabNavigatorParams ,
BottomTabNavigatorParams ,
2023-03-13 22:01:43 +01:00
} from 'lib/routes/types'
2023-04-13 03:27:55 +02:00
import { BottomBar } from './view/shell/bottom-bar/BottomBar'
2023-03-13 22:01:43 +01:00
import { buildStateObject } from 'lib/routes/helpers'
import { State , RouteParams } from 'lib/routes/types'
import { colors } from 'lib/styles'
import { isNative } from 'platform/detection'
import { useColorSchemeStyle } from 'lib/hooks/useColorSchemeStyle'
import { router } from './routes'
2023-04-29 03:03:13 +02:00
import { usePalette } from 'lib/hooks/usePalette'
2023-09-19 21:24:58 +02:00
import { bskyTitle } from 'lib/strings/headings'
import { JSX } from 'react/jsx-runtime'
import { timeout } from 'lib/async/timeout'
2023-11-13 03:13:11 +01:00
import { useUnreadNotifications } from './state/queries/notifications/unread'
2023-03-13 22:01:43 +01:00
import { HomeScreen } from './view/screens/Home'
import { SearchScreen } from './view/screens/Search'
2023-05-26 03:02:37 +02:00
import { FeedsScreen } from './view/screens/Feeds'
2023-03-13 22:01:43 +01:00
import { NotificationsScreen } from './view/screens/Notifications'
2023-11-02 00:15:40 +01:00
import { ListsScreen } from './view/screens/Lists'
2023-05-11 23:08:21 +02:00
import { ModerationScreen } from './view/screens/Moderation'
2023-11-02 00:15:40 +01:00
import { ModerationModlistsScreen } from './view/screens/ModerationModlists'
2023-03-13 22:01:43 +01:00
import { NotFoundScreen } from './view/screens/NotFound'
import { SettingsScreen } from './view/screens/Settings'
2023-09-21 20:33:19 +02:00
import { LanguageSettingsScreen } from './view/screens/LanguageSettings'
2023-03-13 22:01:43 +01:00
import { ProfileScreen } from './view/screens/Profile'
import { ProfileFollowersScreen } from './view/screens/ProfileFollowers'
import { ProfileFollowsScreen } from './view/screens/ProfileFollows'
2023-11-02 00:15:40 +01:00
import { ProfileFeedScreen } from './view/screens/ProfileFeed'
import { ProfileFeedLikedByScreen } from './view/screens/ProfileFeedLikedBy'
2023-05-11 23:08:21 +02:00
import { ProfileListScreen } from './view/screens/ProfileList'
2023-03-13 22:01:43 +01:00
import { PostThreadScreen } from './view/screens/PostThread'
2023-03-31 20:17:26 +02:00
import { PostLikedByScreen } from './view/screens/PostLikedBy'
2023-03-13 22:01:43 +01:00
import { PostRepostedByScreen } from './view/screens/PostRepostedBy'
import { DebugScreen } from './view/screens/Debug'
import { LogScreen } from './view/screens/Log'
2023-03-14 02:34:01 +01:00
import { SupportScreen } from './view/screens/Support'
import { PrivacyPolicyScreen } from './view/screens/PrivacyPolicy'
2023-04-07 05:53:58 +02:00
import { TermsOfServiceScreen } from './view/screens/TermsOfService'
import { CommunityGuidelinesScreen } from './view/screens/CommunityGuidelines'
import { CopyrightPolicyScreen } from './view/screens/CopyrightPolicy'
2023-04-22 01:55:29 +02:00
import { AppPasswords } from 'view/screens/AppPasswords'
2023-05-11 23:08:21 +02:00
import { ModerationMutedAccounts } from 'view/screens/ModerationMutedAccounts'
import { ModerationBlockedAccounts } from 'view/screens/ModerationBlockedAccounts'
2023-05-18 05:04:01 +02:00
import { SavedFeeds } from 'view/screens/SavedFeeds'
2023-08-31 00:21:12 +02:00
import { PreferencesHomeFeed } from 'view/screens/PreferencesHomeFeed'
2023-09-19 21:24:58 +02:00
import { PreferencesThreads } from 'view/screens/PreferencesThreads'
2023-11-24 23:31:33 +01:00
import { createNativeStackNavigatorWithAuth } from './view/shell/createNativeStackNavigatorWithAuth'
2023-03-13 22:01:43 +01:00
const navigationRef = createNavigationContainerRef < AllNavigatorParams > ( )
2023-11-24 23:31:33 +01:00
const HomeTab = createNativeStackNavigatorWithAuth < HomeTabNavigatorParams > ( )
const SearchTab = createNativeStackNavigatorWithAuth < SearchTabNavigatorParams > ( )
const FeedsTab = createNativeStackNavigatorWithAuth < FeedsTabNavigatorParams > ( )
2023-03-13 22:01:43 +01:00
const NotificationsTab =
2023-11-24 23:31:33 +01:00
createNativeStackNavigatorWithAuth < NotificationsTabNavigatorParams > ( )
const MyProfileTab =
createNativeStackNavigatorWithAuth < MyProfileTabNavigatorParams > ( )
const Flat = createNativeStackNavigatorWithAuth < FlatNavigatorParams > ( )
2023-04-18 18:19:37 +02:00
const Tab = createBottomTabNavigator < BottomTabNavigatorParams > ( )
2023-03-13 22:01:43 +01:00
/ * *
* These "common screens" are reused across stacks .
* /
2023-05-16 20:13:05 +02:00
function commonScreens ( Stack : typeof HomeTab , unreadCountLabel? : string ) {
const title = ( page : string ) = > bskyTitle ( page , unreadCountLabel )
2023-03-13 22:01:43 +01:00
return (
< >
2023-05-16 20:13:05 +02:00
< Stack.Screen
name = "NotFound"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > NotFoundScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Not Found' ) } }
/ >
2023-11-02 00:15:40 +01:00
< Stack.Screen
name = "Lists"
component = { ListsScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Lists' ) , requireAuth : true } }
2023-11-02 00:15:40 +01:00
/ >
2023-05-16 20:13:05 +02:00
< Stack.Screen
name = "Moderation"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ModerationScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Moderation' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
2023-05-11 23:08:21 +02:00
< Stack.Screen
2023-11-02 00:15:40 +01:00
name = "ModerationModlists"
getComponent = { ( ) = > ModerationModlistsScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Moderation Lists' ) , requireAuth : true } }
2023-05-11 23:08:21 +02:00
/ >
< Stack.Screen
name = "ModerationMutedAccounts"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ModerationMutedAccounts }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Muted Accounts' ) , requireAuth : true } }
2023-05-11 23:08:21 +02:00
/ >
< Stack.Screen
name = "ModerationBlockedAccounts"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ModerationBlockedAccounts }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Blocked Accounts' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
< Stack.Screen
name = "Settings"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > SettingsScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Settings' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
2023-09-21 20:33:19 +02:00
< Stack.Screen
name = "LanguageSettings"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > LanguageSettingsScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Language Settings' ) , requireAuth : true } }
2023-09-21 20:33:19 +02:00
/ >
2023-05-16 20:13:05 +02:00
< Stack.Screen
name = "Profile"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ProfileScreen }
2023-08-03 19:25:17 +02:00
options = { ( { route } ) = > ( {
title : title ( ` @ ${ route . params . name } ` ) ,
animation : 'none' ,
} ) }
2023-05-11 23:08:21 +02:00
/ >
2023-03-13 22:01:43 +01:00
< Stack.Screen
name = "ProfileFollowers"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ProfileFollowersScreen }
2023-05-16 20:13:05 +02:00
options = { ( { route } ) = > ( {
title : title ( ` People following @ ${ route . params . name } ` ) ,
} ) }
/ >
< Stack.Screen
name = "ProfileFollows"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ProfileFollowsScreen }
2023-05-16 20:13:05 +02:00
options = { ( { route } ) = > ( {
title : title ( ` People followed by @ ${ route . params . name } ` ) ,
} ) }
/ >
< Stack.Screen
name = "ProfileList"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ProfileListScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'List' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
< Stack.Screen
name = "PostThread"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > PostThreadScreen }
2023-05-16 20:13:05 +02:00
options = { ( { route } ) = > ( { title : title ( ` Post by @ ${ route . params . name } ` ) } ) }
/ >
< Stack.Screen
name = "PostLikedBy"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > PostLikedByScreen }
2023-05-16 20:13:05 +02:00
options = { ( { route } ) = > ( { title : title ( ` Post by @ ${ route . params . name } ` ) } ) }
/ >
< Stack.Screen
name = "PostRepostedBy"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > PostRepostedByScreen }
2023-05-16 20:13:05 +02:00
options = { ( { route } ) = > ( { title : title ( ` Post by @ ${ route . params . name } ` ) } ) }
/ >
2023-05-18 06:33:59 +02:00
< Stack.Screen
2023-11-02 00:15:40 +01:00
name = "ProfileFeed"
getComponent = { ( ) = > ProfileFeedScreen }
2023-05-18 06:36:36 +02:00
options = { { title : title ( 'Feed' ) } }
2023-05-18 06:33:59 +02:00
/ >
2023-05-18 05:12:14 +02:00
< Stack.Screen
2023-11-02 00:15:40 +01:00
name = "ProfileFeedLikedBy"
getComponent = { ( ) = > ProfileFeedLikedByScreen }
2023-05-18 06:36:36 +02:00
options = { { title : title ( 'Liked by' ) } }
2023-05-18 05:12:14 +02:00
/ >
2023-05-16 20:13:05 +02:00
< Stack.Screen
name = "Debug"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > DebugScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Debug' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
< Stack.Screen
name = "Log"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > LogScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Log' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
< Stack.Screen
name = "Support"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > SupportScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Support' ) } }
/ >
< Stack.Screen
name = "PrivacyPolicy"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > PrivacyPolicyScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Privacy Policy' ) } }
/ >
< Stack.Screen
name = "TermsOfService"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > TermsOfServiceScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Terms of Service' ) } }
2023-03-13 22:01:43 +01:00
/ >
2023-04-07 05:53:58 +02:00
< Stack.Screen
name = "CommunityGuidelines"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > CommunityGuidelinesScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Community Guidelines' ) } }
/ >
< Stack.Screen
name = "CopyrightPolicy"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > CopyrightPolicyScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Copyright Policy' ) } }
/ >
< Stack.Screen
name = "AppPasswords"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > AppPasswords }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'App Passwords' ) , requireAuth : true } }
2023-04-07 05:53:58 +02:00
/ >
2023-05-18 06:33:59 +02:00
< Stack.Screen
name = "SavedFeeds"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > SavedFeeds }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Edit My Feeds' ) , requireAuth : true } }
2023-05-18 06:33:59 +02:00
/ >
2023-08-31 00:21:12 +02:00
< Stack.Screen
name = "PreferencesHomeFeed"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > PreferencesHomeFeed }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Home Feed Preferences' ) , requireAuth : true } }
2023-08-31 00:21:12 +02:00
/ >
2023-09-19 21:24:58 +02:00
< Stack.Screen
name = "PreferencesThreads"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > PreferencesThreads }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Threads Preferences' ) , requireAuth : true } }
2023-09-19 21:24:58 +02:00
/ >
2023-03-13 22:01:43 +01:00
< / >
)
}
/ * *
* The TabsNavigator is used by native mobile to represent the routes
* in 3 distinct tab - stacks with a different root screen on each .
* /
function TabsNavigator() {
2023-06-22 18:40:32 +02:00
const tabBar = React . useCallback (
( props : JSX.IntrinsicAttributes & BottomTabBarProps ) = > (
< BottomBar { ...props } / >
) ,
[ ] ,
)
2023-09-28 21:41:44 +02:00
2023-03-13 22:01:43 +01:00
return (
< Tab.Navigator
initialRouteName = "HomeTab"
backBehavior = "initialRoute"
2023-05-31 03:16:30 +02:00
screenOptions = { { headerShown : false , lazy : true } }
2023-03-13 22:01:43 +01:00
tabBar = { tabBar } >
2023-10-27 20:06:28 +02:00
< Tab.Screen name = "HomeTab" getComponent = { ( ) = > HomeTabNavigator } / >
< Tab.Screen name = "SearchTab" getComponent = { ( ) = > SearchTabNavigator } / >
< Tab.Screen name = "FeedsTab" getComponent = { ( ) = > FeedsTabNavigator } / >
2023-03-13 22:01:43 +01:00
< Tab.Screen
name = "NotificationsTab"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > NotificationsTabNavigator }
/ >
< Tab.Screen
name = "MyProfileTab"
getComponent = { ( ) = > MyProfileTabNavigator }
2023-03-13 22:01:43 +01:00
/ >
< / Tab.Navigator >
)
}
function HomeTabNavigator() {
const contentStyle = useColorSchemeStyle ( styles . bgLight , styles . bgDark )
2023-08-28 22:37:44 +02:00
2023-03-13 22:01:43 +01:00
return (
< HomeTab.Navigator
screenOptions = { {
gestureEnabled : true ,
fullScreenGestureEnabled : true ,
headerShown : false ,
animationDuration : 250 ,
contentStyle ,
} } >
2023-10-27 20:06:28 +02:00
< HomeTab.Screen name = "Home" getComponent = { ( ) = > HomeScreen } / >
2023-03-13 22:01:43 +01:00
{ commonScreens ( HomeTab ) }
< / HomeTab.Navigator >
)
}
function SearchTabNavigator() {
const contentStyle = useColorSchemeStyle ( styles . bgLight , styles . bgDark )
return (
< SearchTab.Navigator
screenOptions = { {
gestureEnabled : true ,
fullScreenGestureEnabled : true ,
headerShown : false ,
animationDuration : 250 ,
contentStyle ,
} } >
2023-10-27 20:06:28 +02:00
< SearchTab.Screen name = "Search" getComponent = { ( ) = > SearchScreen } / >
2023-03-13 22:01:43 +01:00
{ commonScreens ( SearchTab as typeof HomeTab ) }
< / SearchTab.Navigator >
)
}
2023-05-26 03:02:37 +02:00
function FeedsTabNavigator() {
const contentStyle = useColorSchemeStyle ( styles . bgLight , styles . bgDark )
return (
< FeedsTab.Navigator
screenOptions = { {
gestureEnabled : true ,
fullScreenGestureEnabled : true ,
headerShown : false ,
animationDuration : 250 ,
contentStyle ,
} } >
2023-10-27 20:06:28 +02:00
< FeedsTab.Screen name = "Feeds" getComponent = { ( ) = > FeedsScreen } / >
2023-05-26 03:02:37 +02:00
{ commonScreens ( FeedsTab as typeof HomeTab ) }
< / FeedsTab.Navigator >
)
}
2023-03-13 22:01:43 +01:00
function NotificationsTabNavigator() {
const contentStyle = useColorSchemeStyle ( styles . bgLight , styles . bgDark )
return (
< NotificationsTab.Navigator
screenOptions = { {
gestureEnabled : true ,
fullScreenGestureEnabled : true ,
headerShown : false ,
animationDuration : 250 ,
contentStyle ,
} } >
< NotificationsTab.Screen
name = "Notifications"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > NotificationsScreen }
2023-11-24 23:31:33 +01:00
options = { { requireAuth : true } }
2023-03-13 22:01:43 +01:00
/ >
{ commonScreens ( NotificationsTab as typeof HomeTab ) }
< / NotificationsTab.Navigator >
)
}
2023-11-13 03:13:11 +01:00
function MyProfileTabNavigator() {
2023-04-18 18:19:37 +02:00
const contentStyle = useColorSchemeStyle ( styles . bgLight , styles . bgDark )
return (
< MyProfileTab.Navigator
screenOptions = { {
gestureEnabled : true ,
fullScreenGestureEnabled : true ,
headerShown : false ,
animationDuration : 250 ,
contentStyle ,
} } >
< MyProfileTab.Screen
// @ts-ignore // TODO: fix this broken type in ProfileScreen
2023-11-24 23:31:33 +01:00
name = "MyProfile"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > ProfileScreen }
2023-04-18 18:19:37 +02:00
initialParams = { {
2023-11-03 03:54:43 +01:00
name : 'me' ,
2023-04-18 18:19:37 +02:00
} }
/ >
{ commonScreens ( MyProfileTab as typeof HomeTab ) }
< / MyProfileTab.Navigator >
)
2023-11-13 03:13:11 +01:00
}
2023-04-18 18:19:37 +02:00
2023-03-13 22:01:43 +01:00
/ * *
* The FlatNavigator is used by Web to represent the routes
* in a single ( "flat" ) stack .
* /
2023-11-13 03:13:11 +01:00
const FlatNavigator = ( ) = > {
2023-04-13 03:49:40 +02:00
const pal = usePalette ( 'default' )
2023-11-13 03:13:11 +01:00
const numUnread = useUnreadNotifications ( )
2023-09-15 01:10:59 +02:00
2023-11-13 03:13:11 +01:00
const title = ( page : string ) = > bskyTitle ( page , numUnread )
2023-03-13 22:01:43 +01:00
return (
< Flat.Navigator
screenOptions = { {
gestureEnabled : true ,
fullScreenGestureEnabled : true ,
headerShown : false ,
animationDuration : 250 ,
2023-04-13 03:49:40 +02:00
contentStyle : [ pal . view ] ,
2023-03-13 22:01:43 +01:00
} } >
2023-05-16 20:13:05 +02:00
< Flat.Screen
name = "Home"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > HomeScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Home' ) } }
/ >
< Flat.Screen
name = "Search"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > SearchScreen }
2023-05-16 20:13:05 +02:00
options = { { title : title ( 'Search' ) } }
/ >
2023-05-26 03:02:37 +02:00
< Flat.Screen
name = "Feeds"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > FeedsScreen }
2023-05-26 03:02:37 +02:00
options = { { title : title ( 'Feeds' ) } }
/ >
2023-05-16 20:13:05 +02:00
< Flat.Screen
name = "Notifications"
2023-10-27 20:06:28 +02:00
getComponent = { ( ) = > NotificationsScreen }
2023-11-24 23:31:33 +01:00
options = { { title : title ( 'Notifications' ) , requireAuth : true } }
2023-05-16 20:13:05 +02:00
/ >
2023-11-13 03:13:11 +01:00
{ commonScreens ( Flat as typeof HomeTab , numUnread ) }
2023-03-13 22:01:43 +01:00
< / Flat.Navigator >
)
2023-11-13 03:13:11 +01:00
}
2023-03-13 22:01:43 +01:00
/ * *
* The RoutesContainer should wrap all components which need access
* to the navigation context .
* /
const LINKING = {
prefixes : [ 'bsky://' , 'https://bsky.app' ] ,
getPathFromState ( state : State ) {
// find the current node in the navigation tree
let node = state . routes [ state . index || 0 ]
while ( node . state ? . routes && typeof node . state ? . index === 'number' ) {
node = node . state ? . routes [ node . state ? . index ]
}
// build the path
const route = router . matchName ( node . name )
if ( typeof route === 'undefined' ) {
return '/' // default to home
}
return route . build ( ( node . params || { } ) as RouteParams )
} ,
getStateFromPath ( path : string ) {
const [ name , params ] = router . matchPath ( path )
if ( isNative ) {
if ( name === 'Search' ) {
return buildStateObject ( 'SearchTab' , 'Search' , params )
}
if ( name === 'Notifications' ) {
return buildStateObject ( 'NotificationsTab' , 'Notifications' , params )
}
2023-05-31 04:16:29 +02:00
if ( name === 'Home' ) {
return buildStateObject ( 'HomeTab' , 'Home' , params )
}
// if the path is something else, like a post, profile, or even settings, we need to initialize the home tab as pre-existing state otherwise the back button will not work
return buildStateObject ( 'HomeTab' , name , params , [
{
name : 'Home' ,
params : { } ,
} ,
] )
2023-03-13 22:01:43 +01:00
} else {
return buildStateObject ( 'Flat' , name , params )
}
} ,
}
function RoutesContainer ( { children } : React . PropsWithChildren < { } > ) {
2023-04-24 23:36:05 +02:00
const theme = useColorSchemeStyle ( DefaultTheme , DarkTheme )
2023-03-13 22:01:43 +01:00
return (
2023-05-01 21:42:31 +02:00
< NavigationContainer
ref = { navigationRef }
linking = { LINKING }
theme = { theme }
onReady = { ( ) = > {
2023-10-27 05:06:40 +02:00
SplashScreen . hideAsync ( )
2023-10-31 03:07:14 +01:00
const initMs = Math . round (
// @ts-ignore Emitted by Metro in the bundle prelude
performance . now ( ) - global . __BUNDLE_START_TIME__ ,
)
console . log ( ` Time to first paint: ${ initMs } ms ` )
2023-11-01 16:31:33 +01:00
logModuleInitTrace ( )
2023-05-01 21:42:31 +02:00
} } >
2023-03-13 22:01:43 +01:00
{ children }
< / NavigationContainer >
)
}
/ * *
* These helpers can be used from outside of the RoutesContainer
* ( eg in the state models ) .
* /
function navigate < K extends keyof AllNavigatorParams > (
name : K ,
params? : AllNavigatorParams [ K ] ,
) {
if ( navigationRef . isReady ( ) ) {
2023-10-13 21:10:15 +02:00
return Promise . race ( [
new Promise < void > ( resolve = > {
const handler = ( ) = > {
resolve ( )
navigationRef . removeListener ( 'state' , handler )
}
navigationRef . addListener ( 'state' , handler )
// @ts-ignore I dont know what would make typescript happy but I have a life -prf
navigationRef . navigate ( name , params )
} ) ,
timeout ( 1 e3 ) ,
] )
2023-03-13 22:01:43 +01:00
}
2023-10-13 21:10:15 +02:00
return Promise . resolve ( )
2023-03-13 22:01:43 +01:00
}
function resetToTab ( tabName : 'HomeTab' | 'SearchTab' | 'NotificationsTab' ) {
if ( navigationRef . isReady ( ) ) {
navigate ( tabName )
2023-05-04 23:18:27 +02:00
if ( navigationRef . canGoBack ( ) ) {
navigationRef . dispatch ( StackActions . popToTop ( ) ) //we need to check .canGoBack() before calling it
}
2023-03-13 22:01:43 +01:00
}
}
2023-07-20 08:50:42 +02:00
// returns a promise that resolves after the state reset is complete
function reset ( ) : Promise < void > {
2023-04-21 19:21:38 +02:00
if ( navigationRef . isReady ( ) ) {
navigationRef . dispatch (
CommonActions . reset ( {
index : 0 ,
routes : [ { name : isNative ? 'HomeTab' : 'Home' } ] ,
} ) ,
)
2023-07-20 08:50:42 +02:00
return Promise . race ( [
timeout ( 1 e3 ) ,
new Promise < void > ( resolve = > {
const handler = ( ) = > {
resolve ( )
navigationRef . removeListener ( 'state' , handler )
}
navigationRef . addListener ( 'state' , handler )
} ) ,
] )
} else {
return Promise . resolve ( )
2023-04-21 19:21:38 +02:00
}
}
2023-03-13 22:01:43 +01:00
function handleLink ( url : string ) {
let path
if ( url . startsWith ( '/' ) ) {
path = url
} else if ( url . startsWith ( 'http' ) ) {
try {
path = new URL ( url ) . pathname
} catch ( e ) {
console . error ( 'Invalid url' , url , e )
return
}
} else {
console . error ( 'Invalid url' , url )
return
}
const [ name , params ] = router . matchPath ( path )
if ( isNative ) {
if ( name === 'Search' ) {
resetToTab ( 'SearchTab' )
} else if ( name === 'Notifications' ) {
resetToTab ( 'NotificationsTab' )
} else {
resetToTab ( 'HomeTab' )
// @ts-ignore matchPath doesnt give us type-checked output -prf
navigate ( name , params )
}
} else {
// @ts-ignore matchPath doesnt give us type-checked output -prf
navigate ( name , params )
}
}
const styles = StyleSheet . create ( {
bgDark : {
backgroundColor : colors.black ,
} ,
bgLight : {
2023-04-24 23:36:05 +02:00
backgroundColor : colors.white ,
2023-03-13 22:01:43 +01:00
} ,
} )
2023-11-01 16:31:33 +01:00
function logModuleInitTrace() {
if ( __DEV__ ) {
// This log is noisy, so keep false committed
const shouldLog = false
// Relies on our patch to polyfill.js in metro-runtime
const initLogs = ( global as any ) . __INIT_LOGS__
if ( shouldLog && Array . isArray ( initLogs ) ) {
console . log ( initLogs . join ( '\n' ) )
}
}
}
2023-03-13 22:01:43 +01:00
export {
navigate ,
resetToTab ,
2023-04-21 19:21:38 +02:00
reset ,
2023-03-13 22:01:43 +01:00
handleLink ,
TabsNavigator ,
FlatNavigator ,
RoutesContainer ,
}