Files
mindfulness/client/app/_layout.tsx
2026-01-28 22:54:21 +08:00

82 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import * as SplashScreen from 'expo-splash-screen';
import { useEffect, useState } from 'react';
import 'react-native-reanimated';
import { useColorScheme } from '@/components/useColorScheme';
import { initI18n } from '@/src/i18n';
export {
// Catch any errors thrown by the Layout component.
ErrorBoundary,
} from 'expo-router';
export const unstable_settings = {
// Ensure that reloading on `/modal` keeps a back button present.
initialRouteName: 'index',
};
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded, error] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
...FontAwesome.font,
});
const [i18nReady, setI18nReady] = useState(false);
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
useEffect(() => {
if (error) throw error;
}, [error]);
useEffect(() => {
initI18n()
.catch((e) => {
// i18n 初始化失败不应阻塞 App 启动,先打印错误再继续
console.error('i18n 初始化失败', e);
})
.finally(() => setI18nReady(true));
}, []);
useEffect(() => {
// 等字体与 i18n 都准备好后再隐藏启动页,避免文案闪烁
if (loaded && i18nReady) {
SplashScreen.hideAsync();
}
}, [loaded, i18nReady]);
if (!loaded || !i18nReady) {
return null;
}
return <RootLayoutNav />;
}
function RootLayoutNav() {
const colorScheme = useColorScheme();
return (
<ThemeProvider value={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<Stack screenOptions={{ headerShown: false }}>
{/* 启动分发页:根据 onboarding 状态跳转 */}
<Stack.Screen name="index" />
{/* Onboarding 分组 */}
<Stack.Screen name="(onboarding)" />
{/* 主应用分组(不使用 Tabs */}
<Stack.Screen name="(app)" />
{/* 其他 */}
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
<Stack.Screen name="+not-found" />
</Stack>
</ThemeProvider>
);
}