import client from '@api/client' import { Feather } from '@expo/vector-icons' import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native' import ScreenLocal from '@screens/Local' import ScreenPublic from '@screens/Public' import ScreenNotifications from '@screens/Notifications' import ScreenMe from '@screens/Me' import { timelineFetch } from '@utils/fetches/timelineFetch' import { getLocalNotification, getLocalUrl, updateLocalAccountPreferences, updateNotification } from '@utils/slices/instancesSlice' import { useTheme } from '@utils/styles/ThemeManager' import { themes } from '@utils/styles/themes' import { toast, toastConfig } from '@components/toast' import * as Analytics from 'expo-firebase-analytics' import React, { useCallback, useEffect, useMemo, useRef } from 'react' import { StatusBar } from 'react-native' import Toast from 'react-native-toast-message' import { useDispatch, useSelector } from 'react-redux' import { useInfiniteQuery } from 'react-query' 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 } const Index: React.FC = ({ localCorrupt }) => { const dispatch = useDispatch() const localInstance = useSelector(getLocalUrl) const { mode, theme } = useTheme() enum barStyle { light = 'dark-content', dark = 'light-content' } const routeNameRef = useRef() const navigationRef = useRef(null) // 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]) // 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 useEffect(() => { console.log('Checking announcements') 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', { showAll: false }) } }) .catch(() => {}) }, []) // On launch check if there is any unread noficiations const queryNotification = useInfiniteQuery( ['Notifications', {}], timelineFetch, { enabled: localInstance ? true : false } ) 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()) } }, []) // 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 }, []) const tabNavigatorScreenOptions = useCallback( ({ route }) => ({ tabBarIcon: ({ focused, color, size }: { focused: boolean color: string size: number }) => { 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 } }), [] ) const tabNavigatorTabBarOptions = useMemo( () => ({ activeTintColor: theme.primary, inactiveTintColor: localInstance ? theme.secondary : theme.disabled, showLabel: false }), [] ) const tabScreenLocalListeners = useCallback( () => ({ tabPress: (e: any) => { if (!localInstance) { e.preventDefault() } } }), [] ) const tabScreenComposeListeners = useCallback( ({ navigation }) => ({ tabPress: (e: any) => { e.preventDefault() if (localInstance) { navigation.navigate('Screen-Shared-Compose') } } }), [] ) const tabScreenComposeComponent = useCallback(() => null, []) const tabScreenNotificationsListeners = useCallback( () => ({ tabPress: (e: any) => { if (!localInstance) { e.preventDefault() } } }), [] ) const tabScreenNotificationsOptions = useMemo( () => ({ tabBarBadge: prevNotification && prevNotification.unread ? '' : undefined, tabBarBadgeStyle: { transform: [{ scale: 0.5 }], backgroundColor: theme.red } }), [] ) return ( <> ) } export default React.memo(Index, () => true)