import { DefaultTheme, ThemeProvider } from '@react-navigation/native'; import { useFonts } from 'expo-font'; import { Stack } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import 'react-native-reanimated'; import PrivacyConsentModal from '@/components/PrivacyConsentModal'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useQuickActions } from '@/hooks/useQuickActions'; import { clearAiCoachSessionCache } from '@/services/aiCoachSession'; import { backgroundTaskManager } from '@/services/backgroundTaskManager'; import { notificationService } from '@/services/notifications'; import { setupQuickActions } from '@/services/quickActions'; import { initializeWaterRecordBridge } from '@/services/waterRecordBridge'; import { WaterRecordSource } from '@/services/waterRecords'; import { store } from '@/store'; import { rehydrateUser, setPrivacyAgreed } from '@/store/userSlice'; import { createWaterRecordAction } from '@/store/waterSlice'; import { MoodNotificationHelpers, NutritionNotificationHelpers } from '@/utils/notificationHelpers'; import { clearPendingWaterRecords, syncPendingWidgetChanges } from '@/utils/widgetDataSync'; import React from 'react'; import RNExitApp from 'react-native-exit-app'; import { DialogProvider } from '@/components/ui/DialogProvider'; import { ToastProvider } from '@/contexts/ToastContext'; import { Provider } from 'react-redux'; function Bootstrapper({ children }: { children: React.ReactNode }) { const dispatch = useAppDispatch(); const { privacyAgreed, profile } = useAppSelector((state) => state.user); const [showPrivacyModal, setShowPrivacyModal] = React.useState(false); const [userDataLoaded, setUserDataLoaded] = React.useState(false); // 初始化快捷动作处理 useQuickActions(); React.useEffect(() => { const loadUserData = async () => { await dispatch(rehydrateUser()); setUserDataLoaded(true); }; const initializeNotifications = async () => { try { // 初始化通知服务 await notificationService.initialize(); console.log('通知服务初始化成功'); // 初始化后台任务管理器 await backgroundTaskManager.initialize(); console.log('后台任务管理器初始化成功'); // 初始化快捷动作 await setupQuickActions(); console.log('快捷动作初始化成功'); // 初始化喝水记录 bridge initializeWaterRecordBridge(); console.log('喝水记录 Bridge 初始化成功'); // 检查并同步Widget数据更改 const widgetSync = await syncPendingWidgetChanges(); if (widgetSync.hasPendingChanges && widgetSync.pendingRecords) { console.log(`检测到 ${widgetSync.pendingRecords.length} 条待同步的水记录`); // 将待同步的记录添加到 Redux store for (const record of widgetSync.pendingRecords) { try { await store.dispatch(createWaterRecordAction({ amount: record.amount, recordedAt: record.recordedAt, source: WaterRecordSource.Auto, // 标记为自动添加(来自Widget) })).unwrap(); console.log(`成功同步水记录: ${record.amount}ml at ${record.recordedAt}`); } catch (error) { console.error('同步水记录失败:', error); } } // 清除已同步的记录 await clearPendingWaterRecords(); console.log('所有待同步的水记录已处理完成'); } } catch (error) { console.error('通知服务、后台任务管理器或快捷动作初始化失败:', error); } }; loadUserData(); initializeNotifications(); // 冷启动时清空 AI 教练会话缓存 clearAiCoachSessionCache(); }, [dispatch]); React.useEffect(() => { // 当用户数据加载完成后,检查是否需要显示隐私同意弹窗 if (userDataLoaded && !privacyAgreed) { setShowPrivacyModal(true); } }, [userDataLoaded, privacyAgreed]); // 当用户数据加载完成且用户名存在时,注册所有提醒 React.useEffect(() => { const registerAllReminders = async () => { try { await notificationService.initialize(); // 后台任务 await backgroundTaskManager.initialize() // 注册午餐提醒(12:00) await NutritionNotificationHelpers.scheduleDailyLunchReminder(profile.name || ''); console.log('午餐提醒已注册'); // 注册晚餐提醒(18:00) await NutritionNotificationHelpers.scheduleDailyDinnerReminder(profile.name || ''); console.log('晚餐提醒已注册'); // 注册心情提醒(21:00) await MoodNotificationHelpers.scheduleDailyMoodReminder(profile.name || ''); console.log('心情提醒已注册'); console.log('喝水提醒后台任务已注册'); } catch (error) { console.error('注册提醒失败:', error); } }; registerAllReminders(); }, [userDataLoaded, profile?.name]); const handlePrivacyAgree = () => { dispatch(setPrivacyAgreed()); setShowPrivacyModal(false); }; const handlePrivacyDisagree = () => { RNExitApp.exitApp(); }; return ( {children} ); } export default function RootLayout() { const [loaded] = useFonts({ SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), }); if (!loaded) { // Async font loading only occurs in development. return null; } return ( ); }