97 lines
2.8 KiB
TypeScript
97 lines
2.8 KiB
TypeScript
import type { ErrorBoundaryProps } from 'expo-router'
|
|
import { ToastProvider } from '@gluestack-ui/core/toast/creator'
|
|
import { useFonts } from 'expo-font'
|
|
import { Stack, useRouter } from 'expo-router'
|
|
import * as SplashScreen from 'expo-splash-screen'
|
|
import { StatusBar } from 'expo-status-bar'
|
|
import { RefreshCw } from 'lucide-react-native'
|
|
import { useEffect, useState } from 'react'
|
|
import EmptyState from '@/components/common/EmptyStatus'
|
|
import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'
|
|
import { useUserStore } from '@/store/user'
|
|
import { ToastProviderWrapper } from '@/utils/toast'
|
|
import '@/styles/global.css'
|
|
import 'react-native-reanimated'
|
|
import 'react-native-gesture-handler'
|
|
|
|
SplashScreen.preventAutoHideAsync()
|
|
|
|
export function ErrorBoundary({ error, retry }: ErrorBoundaryProps) {
|
|
return (
|
|
<GluestackUIProvider>
|
|
<EmptyState
|
|
image={require('@/static/images/server-error.png')}
|
|
title="(´・ω・`) 出错啦~"
|
|
description={`发生了一点小问题:\n${error?.message || '请稍后再试'}`}
|
|
buttonText="重新加载"
|
|
buttonIcon={RefreshCw}
|
|
onButtonPress={retry}
|
|
/>
|
|
</GluestackUIProvider>
|
|
)
|
|
}
|
|
|
|
export default function RootLayout() {
|
|
const router = useRouter()
|
|
|
|
const token = useUserStore(state => state.token)
|
|
|
|
const [fontsLoaded] = useFonts({
|
|
SpaceMono: require('@/static/fonts/SpaceMono-Regular.ttf'),
|
|
})
|
|
|
|
const [storeLoaded, setStoreLoaded] = useState(false)
|
|
|
|
// 等待 store 恢复数据
|
|
useEffect(() => {
|
|
if (token !== undefined) {
|
|
setStoreLoaded(true)
|
|
}
|
|
}, [token])
|
|
|
|
// splash screen 隐藏 & 登录跳转
|
|
useEffect(() => {
|
|
if (fontsLoaded && storeLoaded) {
|
|
SplashScreen.hideAsync()
|
|
|
|
// 如果没有 token,则跳转登录页
|
|
if (token === null) {
|
|
router.replace('/auth')
|
|
}
|
|
}
|
|
}, [fontsLoaded, storeLoaded, token])
|
|
|
|
return (
|
|
<GluestackUIProvider>
|
|
<ToastProvider>
|
|
<ToastProviderWrapper>
|
|
<Stack
|
|
screenOptions={{
|
|
headerTitleAlign: 'center',
|
|
animation: 'slide_from_right',
|
|
gestureEnabled: true, // 启用手势返回
|
|
gestureDirection: 'horizontal', // 水平手势
|
|
contentStyle: {
|
|
backgroundColor: '#fff',
|
|
},
|
|
}}
|
|
>
|
|
<Stack.Screen
|
|
name="(tabs)"
|
|
options={{ headerShown: false }}
|
|
/>
|
|
<Stack.Screen
|
|
name="auth"
|
|
options={{
|
|
headerShown: false,
|
|
}}
|
|
/>
|
|
<Stack.Screen name="+not-found" />
|
|
</Stack>
|
|
<StatusBar style="auto" />
|
|
</ToastProviderWrapper>
|
|
</ToastProvider>
|
|
</GluestackUIProvider>
|
|
)
|
|
}
|