import { DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { Stack } from 'expo-router';
import { StatusBar } from 'expo-status-bar';
import 'react-native-reanimated';
import PrivacyConsentModal from '@/components/PrivacyConsentModal';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useColorScheme } from '@/hooks/useColorScheme';
import { clearAiCoachSessionCache } from '@/services/aiCoachSession';
import { store } from '@/store';
import { rehydrateUser, setPrivacyAgreed } from '@/store/userSlice';
import React from 'react';
import RNExitApp from 'react-native-exit-app';
import Toast from 'react-native-toast-message';
import { DialogProvider } from '@/components/ui/DialogProvider';
import { Provider } from 'react-redux';
import { ROUTES } from '@/constants/Routes';
function Bootstrapper({ children }: { children: React.ReactNode }) {
const dispatch = useAppDispatch();
const { privacyAgreed } = useAppSelector((state) => state.user);
const [showPrivacyModal, setShowPrivacyModal] = React.useState(false);
const [userDataLoaded, setUserDataLoaded] = React.useState(false);
React.useEffect(() => {
const loadUserData = async () => {
await dispatch(rehydrateUser());
setUserDataLoaded(true);
};
loadUserData();
// 冷启动时清空 AI 教练会话缓存
clearAiCoachSessionCache();
}, [dispatch]);
React.useEffect(() => {
// 当用户数据加载完成后,检查是否需要显示隐私同意弹窗
if (userDataLoaded && !privacyAgreed) {
setShowPrivacyModal(true);
}
}, [userDataLoaded, privacyAgreed]);
const handlePrivacyAgree = () => {
dispatch(setPrivacyAgreed());
setShowPrivacyModal(false);
};
const handlePrivacyDisagree = () => {
RNExitApp.exitApp();
};
return (
{children}
);
}
export default function RootLayout() {
const colorScheme = useColorScheme();
const [loaded] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
});
if (!loaded) {
// Async font loading only occurs in development.
return null;
}
return (
);
}