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 { notificationService } from '@/services/notifications'; import { setupQuickActions } from '@/services/quickActions'; import { initializeWaterRecordBridge } from '@/services/waterRecordBridge'; import { WaterRecordSource } from '@/services/waterRecords'; import { store } from '@/store'; import { fetchMyProfile, setPrivacyAgreed } from '@/store/userSlice'; import { createWaterRecordAction } from '@/store/waterSlice'; import { ensureHealthPermissions, initializeHealthPermissions } from '@/utils/health'; import { DailySummaryNotificationHelpers, MoodNotificationHelpers, NutritionNotificationHelpers } from '@/utils/notificationHelpers'; import { clearPendingWaterRecords, syncPendingWidgetChanges } from '@/utils/widgetDataSync'; import React, { useEffect } from 'react'; import { DialogProvider } from '@/components/ui/DialogProvider'; import { ToastProvider } from '@/contexts/ToastContext'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { STORAGE_KEYS } from '@/services/api'; import { BackgroundTaskManager } from '@/services/backgroundTaskManager'; import { fetchChallenges } from '@/store/challengesSlice'; import AsyncStorage from '@/utils/kvStore'; import { Provider } from 'react-redux'; function Bootstrapper({ children }: { children: React.ReactNode }) { const dispatch = useAppDispatch(); const { profile } = useAppSelector((state) => state.user); const [showPrivacyModal, setShowPrivacyModal] = React.useState(false); const { isLoggedIn } = useAuthGuard() // 初始化快捷动作处理 useQuickActions(); useEffect(() => { if (isLoggedIn) { dispatch(fetchChallenges()); } }, [isLoggedIn]); React.useEffect(() => { const loadUserData = async () => { // 数据已经在启动界面预加载,这里只需要快速同步到 Redux 状态 await dispatch(fetchMyProfile()); }; const initHealthPermissions = async () => { // 初始化 HealthKit 权限管理系统 try { console.log('初始化 HealthKit 权限管理系统...'); initializeHealthPermissions(); // 延迟请求权限,避免应用启动时弹窗 setTimeout(async () => { try { await ensureHealthPermissions(); console.log('HealthKit 权限请求完成'); } catch (error) { console.warn('HealthKit 权限请求失败,可能在模拟器上运行:', error); } }, 2000); console.log('HealthKit 权限管理初始化完成'); } catch (error) { console.warn('HealthKit 权限管理初始化失败:', error); } } const initializeNotifications = async () => { try { await BackgroundTaskManager.getInstance().initialize(); // 初始化通知服务 await notificationService.initialize(); console.log('通知服务初始化成功'); // 注册午餐提醒(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('心情提醒已注册'); await DailySummaryNotificationHelpers.scheduleDailySummaryNotification(profile.name || '') // 初始化快捷动作 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(); initHealthPermissions(); initializeNotifications(); // 冷启动时清空 AI 教练会话缓存 clearAiCoachSessionCache(); }, [dispatch]); React.useEffect(() => { const getPrivacyAgreed = async () => { const str = await AsyncStorage.getItem(STORAGE_KEYS.privacyAgreed) setShowPrivacyModal(str !== 'true'); } getPrivacyAgreed(); }, []); 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 ( ); }