import 'react-native-gesture-handler' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native' import { enableScreens } from 'react-native-screens' import React, { useEffect, useMemo, useRef } from 'react' import { StatusBar } from 'react-native' import Toast from 'react-native-toast-message' import { Feather } from '@expo/vector-icons' import ScreenLocal from '@screens/Local' import ScreenPublic from '@screens/Public' import ScreenNotifications from '@screens/Notifications' import ScreenMe from '@screens/Me' import { themes } from '@utils/styles/themes' import { useTheme } from '@utils/styles/ThemeManager' import getCurrentTab from '@utils/getCurrentTab' import { toast, toastConfig } from '@components/toast' import { useTranslation } from 'react-i18next' import { useDispatch, useSelector } from 'react-redux' import { getLocalNotification, getLocalUrl, updateLocalAccountPreferences, updateNotification } from '@utils/slices/instancesSlice' import { useInfiniteQuery, useQuery } from 'react-query' import { announcementFetch } from './utils/fetches/announcementsFetch' import client from './api/client' import { timelineFetch } from './utils/fetches/timelineFetch' enableScreens() const Tab = createBottomTabNavigator() export type RootStackParamList = { 'Screen-Local': undefined 'Screen-Public': { publicTab: boolean } 'Screen-Post': undefined 'Screen-Notifications': undefined 'Screen-Me': undefined } export interface Props { localCorrupt: boolean } export const Index: React.FC = ({ localCorrupt }) => { const dispatch = useDispatch() const localInstance = useSelector(getLocalUrl) const { i18n } = useTranslation() const { mode, theme } = useTheme() enum barStyle { light = 'dark-content', dark = 'light-content' } // On launch display login credentials corrupt information useEffect(() => { const showLocalCorrect = localCorrupt ? toast({ type: 'error', content: '登录已过期', description: '请重新登录', autoHide: false }) : undefined return showLocalCorrect }, [localCorrupt]) // On launch check if there is any unread announcements const navigationRef = useRef(null) useEffect(() => { localInstance && client({ method: 'get', instance: 'local', url: `announcements` }) .then(({ body }: { body?: Mastodon.Announcement[] }) => { if (body?.filter(announcement => !announcement.read).length) { navigationRef.current?.navigate('Screen-Shared-Announcements') } }) .catch(() => {}) }, []) // On launch check if there is any unread noficiations const queryNotification = useInfiniteQuery( ['Notifications', {}] as QueryKey.Timeline, timelineFetch, { enabled: localInstance ? true : false, cacheTime: 1000 * 30 } ) const prevNotification = useSelector(getLocalNotification) useEffect(() => { if (queryNotification.data?.pages) { const flattenData = queryNotification.data.pages.flatMap(d => [ ...d?.toots ]) const latestNotificationTime = flattenData.length ? flattenData[0].created_at : undefined if (!prevNotification || !prevNotification.latestTime) { dispatch( updateNotification({ unread: true }) ) } else if ( latestNotificationTime && new Date(prevNotification.latestTime) < new Date(latestNotificationTime) ) { dispatch( updateNotification({ unread: true, latestTime: latestNotificationTime }) ) } } }, [queryNotification.data?.pages]) // Lazily update users's preferences, for e.g. composing default visibility useEffect(() => { if (localInstance) { dispatch(updateLocalAccountPreferences()) } }, []) return ( <> ({ tabBarIcon: ({ focused, color, size }) => { let name: any let updateColor: string = color switch (route.name) { case 'Screen-Local': name = 'home' break case 'Screen-Public': name = 'globe' !focused && (updateColor = theme.secondary) break case 'Screen-Post': name = 'plus' break case 'Screen-Notifications': name = 'bell' break case 'Screen-Me': name = focused ? 'meh' : 'smile' !focused && (updateColor = theme.secondary) break default: name = 'alert-octagon' break } return } })} tabBarOptions={{ activeTintColor: theme.primary, inactiveTintColor: localInstance ? theme.secondary : theme.disabled, showLabel: false }} > { if (!localInstance) { e.preventDefault() } } }} /> ({ tabPress: e => { e.preventDefault() localInstance && navigation.navigate(getCurrentTab(navigation), { screen: 'Screen-Shared-Compose' }) } })} > {() => null} { if (!localInstance) { e.preventDefault() } } }} /> Toast.setRef(ref)} config={toastConfig} /> ) }