tooot/src/Index.tsx

325 lines
9.8 KiB
TypeScript
Raw Normal View History

2020-12-29 16:19:04 +01:00
import client from '@api/client'
import haptics from '@components/haptics'
import Icon from '@components/Icon'
import { toast, toastConfig } from '@components/toast'
2021-01-07 22:18:14 +01:00
import {
BottomTabNavigationOptions,
createBottomTabNavigator
} from '@react-navigation/bottom-tabs'
2020-12-23 01:31:11 +01:00
import {
2021-01-14 00:43:35 +01:00
getFocusedRouteNameFromRoute,
2020-12-23 01:31:11 +01:00
NavigationContainer,
NavigationContainerRef
} from '@react-navigation/native'
2020-12-13 14:04:25 +01:00
import ScreenLocal from '@screens/Local'
import ScreenMe from '@screens/Me'
import ScreenNotifications from '@screens/Notifications'
import ScreenPublic from '@screens/Public'
2021-01-11 21:36:57 +01:00
import { useTimelineQuery } from '@utils/queryHooks/timeline'
import {
2021-01-23 02:41:50 +01:00
getLocalAccount,
2021-01-07 19:13:09 +01:00
getLocalActiveIndex,
2020-12-24 10:28:51 +01:00
getLocalNotification,
2021-01-07 19:13:09 +01:00
localUpdateAccountPreferences,
localUpdateNotification
} from '@utils/slices/instancesSlice'
2020-12-29 16:19:04 +01:00
import { useTheme } from '@utils/styles/ThemeManager'
import { themes } from '@utils/styles/themes'
import * as Analytics from 'expo-firebase-analytics'
2021-01-07 19:13:09 +01:00
import React, {
createRef,
useCallback,
useEffect,
useMemo,
useRef
} from 'react'
2021-01-24 02:25:43 +01:00
import { useTranslation } from 'react-i18next'
2021-01-23 02:41:50 +01:00
import { Image, Platform, StatusBar } from 'react-native'
2020-12-29 16:19:04 +01:00
import Toast from 'react-native-toast-message'
import { useDispatch, useSelector } from 'react-redux'
2020-11-23 00:07:32 +01:00
2021-01-07 22:18:14 +01:00
const Tab = createBottomTabNavigator<Nav.RootStackParamList>()
2020-10-23 09:22:17 +02:00
export interface Props {
localCorrupt?: string
}
2021-01-07 19:13:09 +01:00
export const navigationRef = createRef<NavigationContainerRef>()
2020-12-29 01:09:22 +01:00
const Index: React.FC<Props> = ({ localCorrupt }) => {
const dispatch = useDispatch()
2021-01-07 19:13:09 +01:00
const localActiveIndex = useSelector(getLocalActiveIndex)
2020-11-23 00:07:32 +01:00
const { mode, theme } = useTheme()
2020-11-29 18:08:31 +01:00
enum barStyle {
light = 'dark-content',
dark = 'light-content'
}
2020-11-23 00:07:32 +01:00
2020-12-29 16:19:04 +01:00
const routeNameRef = useRef<string | undefined>()
// const isConnected = useNetInfo().isConnected
// const [firstRender, setFirstRender] = useState(false)
// useEffect(() => {
// if (firstRender) {
// // bug in netInfo on first render as false
// if (isConnected !== false) {
// toast({ type: 'error', content: '手机🈚️网络', autoHide: false })
// }
// } else {
// setFirstRender(true)
// }
// }, [isConnected, firstRender])
2020-12-28 23:20:18 +01:00
2020-12-24 10:28:51 +01:00
// On launch display login credentials corrupt information
2021-01-24 02:25:43 +01:00
const { t } = useTranslation('common')
useEffect(() => {
const showLocalCorrect = localCorrupt
? toast({
type: 'error',
2021-01-24 02:25:43 +01:00
message: t('index.localCorrupt'),
description: localCorrupt.length ? localCorrupt : undefined,
autoHide: false
})
: undefined
return showLocalCorrect
}, [localCorrupt])
2020-12-24 10:28:51 +01:00
// On launch check if there is any unread announcements
useEffect(() => {
2020-12-29 16:19:04 +01:00
console.log('Checking announcements')
2021-01-07 19:13:09 +01:00
localActiveIndex !== null &&
client<Mastodon.Announcement[]>({
2020-12-24 10:28:51 +01:00
method: 'get',
instance: 'local',
url: `announcements`
})
2021-01-07 19:13:09 +01:00
.then(res => {
if (res?.filter(announcement => !announcement.read).length) {
2020-12-25 21:51:46 +01:00
navigationRef.current?.navigate('Screen-Shared-Announcements', {
showAll: false
})
2020-12-24 10:28:51 +01:00
}
})
2020-12-29 16:19:04 +01:00
.catch(() => {})
}, [])
2020-12-24 10:28:51 +01:00
// On launch check if there is any unread noficiations
2021-01-11 21:36:57 +01:00
const queryNotification = useTimelineQuery({
2021-01-07 19:13:09 +01:00
page: 'Notifications',
options: {
enabled: localActiveIndex !== null ? true : false,
2021-01-04 14:55:34 +01:00
refetchInterval: 1000 * 60,
refetchIntervalInBackground: true
}
2021-01-07 19:13:09 +01:00
})
2020-12-24 10:28:51 +01:00
const prevNotification = useSelector(getLocalNotification)
2020-12-23 01:31:11 +01:00
useEffect(() => {
2020-12-24 10:28:51 +01:00
if (queryNotification.data?.pages) {
2021-01-11 21:36:57 +01:00
const flattenData = queryNotification.data.pages.flatMap(d => [...d])
2020-12-24 10:28:51 +01:00
const latestNotificationTime = flattenData.length
2021-01-07 22:18:14 +01:00
? (flattenData[0] as Mastodon.Notification).created_at
2020-12-24 10:28:51 +01:00
: undefined
if (!prevNotification || !prevNotification.latestTime) {
dispatch(
2021-01-07 19:13:09 +01:00
localUpdateNotification({
2021-01-23 02:41:50 +01:00
unread: false
2020-12-24 10:28:51 +01:00
})
)
} else if (
latestNotificationTime &&
new Date(prevNotification.latestTime) < new Date(latestNotificationTime)
) {
dispatch(
2021-01-07 19:13:09 +01:00
localUpdateNotification({
2020-12-24 10:28:51 +01:00
unread: true,
latestTime: latestNotificationTime
})
)
}
}
}, [queryNotification.data?.pages])
// Lazily update users's preferences, for e.g. composing default visibility
useEffect(() => {
2021-01-07 19:13:09 +01:00
if (localActiveIndex !== null) {
dispatch(localUpdateAccountPreferences())
2020-12-24 10:28:51 +01:00
}
2020-12-23 01:31:11 +01:00
}, [])
2020-12-29 16:19:04 +01:00
// Callbacks
const navigationContainerOnReady = useCallback(
() =>
(routeNameRef.current = navigationRef.current?.getCurrentRoute()?.name),
[]
)
const navigationContainerOnStateChange = useCallback(() => {
const previousRouteName = routeNameRef.current
const currentRouteName = navigationRef.current?.getCurrentRoute()?.name
if (previousRouteName !== currentRouteName) {
Analytics.setCurrentScreen(currentRouteName)
}
routeNameRef.current = currentRouteName
}, [])
2021-01-23 02:41:50 +01:00
const localAccount = useSelector(getLocalAccount)
2020-12-29 16:19:04 +01:00
const tabNavigatorScreenOptions = useCallback(
2021-01-07 22:18:14 +01:00
({ route }): BottomTabNavigationOptions => ({
2020-12-29 16:19:04 +01:00
tabBarIcon: ({
focused,
color,
size
}: {
focused: boolean
color: string
size: number
}) => {
switch (route.name) {
case 'Screen-Local':
2021-01-23 02:41:50 +01:00
return <Icon name='Home' size={size} color={color} />
2020-12-29 16:19:04 +01:00
case 'Screen-Public':
2021-01-26 12:17:25 +01:00
return <Icon name='Globe' size={size} color={color} />
2020-12-29 16:19:04 +01:00
case 'Screen-Post':
2021-01-23 02:41:50 +01:00
return <Icon name='Plus' size={size} color={color} />
2020-12-29 16:19:04 +01:00
case 'Screen-Notifications':
2021-01-23 02:41:50 +01:00
return <Icon name='Bell' size={size} color={color} />
2020-12-29 16:19:04 +01:00
case 'Screen-Me':
2021-01-23 02:41:50 +01:00
return localActiveIndex !== null ? (
<Image
source={{ uri: localAccount?.avatarStatic }}
style={{
2021-01-24 02:25:43 +01:00
width: size,
height: size,
2021-01-23 02:41:50 +01:00
borderRadius: size,
borderWidth: focused ? 2 : 0,
borderColor: focused ? theme.secondary : color
}}
/>
) : (
<Icon
name={focused ? 'Meh' : 'Smile'}
size={size}
color={!focused ? theme.secondary : color}
/>
)
2020-12-29 16:19:04 +01:00
default:
2021-01-23 02:41:50 +01:00
return <Icon name='AlertOctagon' size={size} color={color} />
2020-12-29 16:19:04 +01:00
}
2021-01-14 00:43:35 +01:00
},
...(Platform.OS === 'android' && {
tabBarVisible:
getFocusedRouteNameFromRoute(route) !== 'Screen-Shared-Compose' &&
getFocusedRouteNameFromRoute(route) !==
'Screen-Shared-Announcements' &&
getFocusedRouteNameFromRoute(route) !==
'Screen-Shared-ImagesViewer' &&
getFocusedRouteNameFromRoute(route) !== 'Screen-Me-Switch'
})
2020-12-29 16:19:04 +01:00
}),
2021-01-23 02:41:50 +01:00
[localActiveIndex, localAccount]
2020-12-29 16:19:04 +01:00
)
const tabNavigatorTabBarOptions = useMemo(
() => ({
activeTintColor: theme.primary,
2021-01-07 19:13:09 +01:00
inactiveTintColor:
localActiveIndex !== null ? theme.secondary : theme.disabled,
2021-01-14 00:43:35 +01:00
showLabel: false,
...(Platform.OS === 'android' && { keyboardHidesTabBar: true })
2020-12-29 16:19:04 +01:00
}),
2021-01-07 19:13:09 +01:00
[theme, localActiveIndex]
2020-12-29 16:19:04 +01:00
)
const tabScreenLocalListeners = useCallback(
() => ({
tabPress: (e: any) => {
2021-01-07 19:13:09 +01:00
if (!(localActiveIndex !== null)) {
2020-12-29 16:19:04 +01:00
e.preventDefault()
}
}
}),
2021-01-07 19:13:09 +01:00
[localActiveIndex]
2020-12-29 16:19:04 +01:00
)
const tabScreenComposeListeners = useMemo(
() => ({
2020-12-29 16:19:04 +01:00
tabPress: (e: any) => {
e.preventDefault()
2021-01-07 19:13:09 +01:00
if (localActiveIndex !== null) {
haptics('Medium')
navigationRef.current?.navigate('Screen-Shared-Compose')
2020-12-29 16:19:04 +01:00
}
}
}),
2021-01-07 19:13:09 +01:00
[localActiveIndex]
2020-12-29 16:19:04 +01:00
)
const tabScreenComposeComponent = useCallback(() => null, [])
const tabScreenNotificationsListeners = useCallback(
() => ({
tabPress: (e: any) => {
2021-01-07 19:13:09 +01:00
if (!(localActiveIndex !== null)) {
2020-12-29 16:19:04 +01:00
e.preventDefault()
}
}
}),
2021-01-07 19:13:09 +01:00
[localActiveIndex]
2020-12-29 16:19:04 +01:00
)
2020-10-23 09:22:17 +02:00
return (
2020-11-29 18:08:31 +01:00
<>
2021-01-13 01:03:46 +01:00
<StatusBar barStyle={barStyle[mode]} backgroundColor={theme.background} />
2020-12-23 01:31:11 +01:00
<NavigationContainer
ref={navigationRef}
theme={themes[mode]}
2020-12-29 16:19:04 +01:00
onReady={navigationContainerOnReady}
onStateChange={navigationContainerOnStateChange}
2020-12-23 01:31:11 +01:00
>
2020-11-29 18:08:31 +01:00
<Tab.Navigator
2021-01-07 19:13:09 +01:00
initialRouteName={
2021-01-26 12:17:25 +01:00
localActiveIndex !== null ? 'Screen-Local' : 'Screen-Me'
2021-01-07 19:13:09 +01:00
}
2020-12-29 16:19:04 +01:00
screenOptions={tabNavigatorScreenOptions}
tabBarOptions={tabNavigatorTabBarOptions}
2020-11-22 00:46:23 +01:00
>
2020-12-13 21:09:21 +01:00
<Tab.Screen
name='Screen-Local'
component={ScreenLocal}
2020-12-29 16:19:04 +01:00
listeners={tabScreenLocalListeners}
2020-12-13 21:09:21 +01:00
/>
2020-11-29 18:08:31 +01:00
<Tab.Screen name='Screen-Public' component={ScreenPublic} />
<Tab.Screen
name='Screen-Post'
2020-12-29 16:19:04 +01:00
component={tabScreenComposeComponent}
listeners={tabScreenComposeListeners}
/>
2020-11-29 18:08:31 +01:00
<Tab.Screen
name='Screen-Notifications'
component={ScreenNotifications}
2020-12-29 16:19:04 +01:00
listeners={tabScreenNotificationsListeners}
2021-01-12 00:12:44 +01:00
options={
prevNotification && prevNotification.unread
? {
tabBarBadge: '',
tabBarBadgeStyle: {
transform: [{ scale: 0.5 }],
backgroundColor: theme.red
}
}
: {
tabBarBadgeStyle: {
transform: [{ scale: 0.5 }],
backgroundColor: theme.red
}
}
}
2020-11-29 18:08:31 +01:00
/>
<Tab.Screen name='Screen-Me' component={ScreenMe} />
</Tab.Navigator>
2021-01-14 00:43:35 +01:00
{Platform.OS === 'ios' ? (
<Toast ref={Toast.setRef} config={toastConfig} />
) : null}
2020-11-29 18:08:31 +01:00
</NavigationContainer>
</>
2020-10-23 09:22:17 +02:00
)
}
2020-12-29 01:09:22 +01:00
export default React.memo(Index, () => true)