From 16c2351160df9c61d078f3466abd9ce2fb6ee865 Mon Sep 17 00:00:00 2001 From: richarjiang Date: Fri, 31 Oct 2025 08:49:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=A7=BB=E9=99=A4=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 删除了完整的目标管理功能,包括目标创建、编辑、任务管理等相关页面和组件。同时移除了相关的API服务、Redux状态管理、类型定义和通知功能。应用版本从1.0.20升级到1.0.21。 --- app/(tabs)/_layout.tsx | 7 - app/(tabs)/goals.tsx | 920 --------------------- app/_layout.tsx | 6 +- app/goals-list.tsx | 471 ----------- app/task-detail.tsx | 659 --------------- app/task-list.tsx | 289 ------- components/GoalCard.tsx | 304 ------- components/GoalCarousel.tsx | 102 --- components/GoalsPageGuide.tsx | 457 ----------- components/NotificationTest.tsx | 47 +- components/TaskCard.tsx | 501 ------------ components/TaskFilterTabs.tsx | 203 ----- components/TaskProgressCard.tsx | 174 ---- components/model/CreateGoalModal.tsx | 1107 -------------------------- constants/Routes.ts | 7 +- constants/goalTemplates.ts | 227 ------ hooks/useNotifications.ts | 28 +- ios/OutLive/Info.plist | 2 +- ios/Podfile.lock | 620 +++++++-------- package-lock.json | 1045 ++++++++++++++---------- package.json | 14 +- services/goalsApi.ts | 123 --- services/notifications.ts | 13 +- services/tasksApi.ts | 83 -- store/goalsSlice.ts | 603 -------------- store/index.ts | 14 +- store/tasksSlice.ts | 322 -------- types/goals.ts | 251 ------ utils/guideHelpers.ts | 28 +- utils/notificationHelpers.ts | 209 +---- utils/welcomeMessage.ts | 1 - 31 files changed, 953 insertions(+), 7884 deletions(-) delete mode 100644 app/(tabs)/goals.tsx delete mode 100644 app/goals-list.tsx delete mode 100644 app/task-detail.tsx delete mode 100644 app/task-list.tsx delete mode 100644 components/GoalCard.tsx delete mode 100644 components/GoalCarousel.tsx delete mode 100644 components/GoalsPageGuide.tsx delete mode 100644 components/TaskCard.tsx delete mode 100644 components/TaskFilterTabs.tsx delete mode 100644 components/TaskProgressCard.tsx delete mode 100644 components/model/CreateGoalModal.tsx delete mode 100644 constants/goalTemplates.ts delete mode 100644 services/goalsApi.ts delete mode 100644 services/tasksApi.ts delete mode 100644 store/goalsSlice.ts delete mode 100644 store/tasksSlice.ts delete mode 100644 types/goals.ts diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 928173f..aff9d27 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -22,7 +22,6 @@ type TabConfig = { const TAB_CONFIGS: Record = { statistics: { icon: 'chart.pie.fill', title: '健康' }, fasting: { icon: 'timer', title: '断食' }, - goals: { icon: 'flag.fill', title: '习惯' }, challenges: { icon: 'trophy.fill', title: '挑战' }, personal: { icon: 'person.fill', title: '个人' }, }; @@ -38,7 +37,6 @@ export default function TabLayout() { const routeMap: Record = { statistics: ROUTES.TAB_STATISTICS, fasting: ROUTES.TAB_FASTING, - goals: ROUTES.TAB_GOALS, challenges: ROUTES.TAB_CHALLENGES, personal: ROUTES.TAB_PERSONAL, }; @@ -182,10 +180,6 @@ export default function TabLayout() { - - - - @@ -205,7 +199,6 @@ export default function TabLayout() { - diff --git a/app/(tabs)/goals.tsx b/app/(tabs)/goals.tsx deleted file mode 100644 index 972804f..0000000 --- a/app/(tabs)/goals.tsx +++ /dev/null @@ -1,920 +0,0 @@ -import CelebrationAnimation, { CelebrationAnimationRef } from '@/components/CelebrationAnimation'; -import GoalTemplateModal from '@/components/GoalTemplateModal'; -import { GoalsPageGuide } from '@/components/GoalsPageGuide'; -import { GuideTestButton } from '@/components/GuideTestButton'; -import { TaskCard } from '@/components/TaskCard'; -import { TaskFilterTabs, TaskFilterType } from '@/components/TaskFilterTabs'; -import { TaskProgressCard } from '@/components/TaskProgressCard'; -import { CreateGoalModal } from '@/components/model/CreateGoalModal'; -import { useGlobalDialog } from '@/components/ui/DialogProvider'; -import { Colors } from '@/constants/Colors'; -import { TAB_BAR_BOTTOM_OFFSET, TAB_BAR_HEIGHT } from '@/constants/TabBar'; -import { GoalTemplate } from '@/constants/goalTemplates'; -import { useAppDispatch, useAppSelector } from '@/hooks/redux'; -import { useAuthGuard } from '@/hooks/useAuthGuard'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import { clearErrors, createGoal } from '@/store/goalsSlice'; -import { clearErrors as clearTaskErrors, fetchTasks, loadMoreTasks } from '@/store/tasksSlice'; -import { CreateGoalRequest, TaskListItem } from '@/types/goals'; -import { checkGuideCompleted, markGuideCompleted } from '@/utils/guideHelpers'; -import { GoalNotificationHelpers } from '@/utils/notificationHelpers'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { useFocusEffect } from '@react-navigation/native'; -import dayjs from 'dayjs'; -import * as Haptics from 'expo-haptics'; -import { LinearGradient } from 'expo-linear-gradient'; -import Lottie from 'lottie-react-native'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; -import { Alert, FlatList, Image, RefreshControl, SafeAreaView, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; - -export default function GoalsScreen() { - const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; - const colorTokens = Colors[theme]; - const dispatch = useAppDispatch(); - - const { pushIfAuthedElseLogin, isLoggedIn } = useAuthGuard(); - - const { showConfirm } = useGlobalDialog(); - - // Redux状态 - const { - tasks, - tasksLoading, - tasksError, - tasksPagination, - completeError, - skipError, - } = useAppSelector((state) => state.tasks); - - - const { - createLoading, - createError - } = useAppSelector((state) => state.goals); - - const userProfile = useAppSelector((state) => state.user.profile); - - const [showTemplateModal, setShowTemplateModal] = useState(false); - const [showCreateModal, setShowCreateModal] = useState(false); - const [refreshing, setRefreshing] = useState(false); - const [selectedFilter, setSelectedFilter] = useState('all'); - const [modalKey, setModalKey] = useState(0); // 用于强制重新渲染弹窗 - const [showGuide, setShowGuide] = useState(false); // 控制引导显示 - const [selectedTemplateData, setSelectedTemplateData] = useState | undefined>(); - - // 庆祝动画引用 - const celebrationAnimationRef = useRef(null); - - // 页面聚焦时重新加载数据 - useFocusEffect( - useCallback(() => { - console.log('useFocusEffect - loading tasks isLoggedIn', isLoggedIn); - - if (isLoggedIn) { - loadTasks(); - checkAndShowGuide(); - } - }, [dispatch, isLoggedIn]) - ); - - // 检查并显示用户引导 - const checkAndShowGuide = async () => { - try { - const hasCompletedGuide = await checkGuideCompleted('GOALS_PAGE'); - if (!hasCompletedGuide) { - // 延迟显示引导,确保页面完全加载 - setTimeout(() => { - setShowGuide(true); - }, 1000); - } - } catch (error) { - console.error('检查引导状态失败:', error); - } - }; - - // 加载任务列表 - const loadTasks = async () => { - try { - - await dispatch(fetchTasks({ - startDate: dayjs().startOf('day').toISOString(), - endDate: dayjs().endOf('day').toISOString(), - })).unwrap(); - } catch (error) { - console.error('Failed to load tasks:', error); - } - }; - - // 下拉刷新 - const onRefresh = async () => { - setRefreshing(true); - try { - if (!isLoggedIn) return - - await loadTasks(); - } finally { - setRefreshing(false); - } - }; - - // 加载更多任务 - const handleLoadMoreTasks = async () => { - if (!isLoggedIn) return - - if (tasksPagination.hasMore && !tasksLoading) { - try { - await dispatch(loadMoreTasks()).unwrap(); - } catch (error) { - console.error('Failed to load more tasks:', error); - } - } - }; - - // 处理错误提示 - useEffect(() => { - - if (tasksError) { - Alert.alert('错误', tasksError); - dispatch(clearTaskErrors()); - } - if (createError) { - Alert.alert('创建失败', createError); - dispatch(clearErrors()); - } - if (completeError) { - Alert.alert('完成失败', completeError); - dispatch(clearTaskErrors()); - } - if (skipError) { - Alert.alert('跳过失败', skipError); - dispatch(clearTaskErrors()); - } - }, [tasksError, createError, completeError, skipError, dispatch]); - - // 重置弹窗表单数据 - const handleModalSuccess = () => { - // 不需要在这里改变 modalKey,因为弹窗已经关闭了 - // 下次打开时会自动使用新的 modalKey - setSelectedTemplateData(undefined); - }; - - // 处理模板选择 - const handleSelectTemplate = (template: GoalTemplate) => { - setSelectedTemplateData(template.data); - setShowTemplateModal(false); - setModalKey(prev => prev + 1); - setShowCreateModal(true); - }; - - // 处理创建自定义目标 - const handleCreateCustomGoal = () => { - setSelectedTemplateData(undefined); - setShowTemplateModal(false); - setModalKey(prev => prev + 1); - setShowCreateModal(true); - }; - - // 打开模板选择弹窗 - const handleOpenTemplateModal = () => { - setSelectedTemplateData(undefined); - setShowTemplateModal(true); - }; - - // 创建目标处理函数 - const handleCreateGoal = async (goalData: CreateGoalRequest) => { - try { - await dispatch(createGoal(goalData)).unwrap(); - setShowCreateModal(false); - - // 获取用户名 - const userName = userProfile?.name || '主人'; - - // 创建目标成功后,设置定时推送 - try { - if (goalData.hasReminder) { - const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications( - { - title: goalData.title, - repeatType: goalData.repeatType, - frequency: goalData.frequency, - hasReminder: goalData.hasReminder, - reminderTime: goalData.reminderTime, - customRepeatRule: goalData.customRepeatRule, - startTime: goalData.startTime, - }, - userName - ); - console.log(`目标"${goalData.title}"的定时推送已创建,通知ID:`, notificationIds); - } - - } catch (notificationError) { - console.error('创建目标定时推送失败:', notificationError); - // 通知创建失败不影响目标创建的成功 - } - - // 使用确认弹窗显示成功消息 - showConfirm( - { - title: '目标创建成功', - message: '恭喜!您的目标已成功创建。系统将自动生成相应的任务,帮助您实现目标。', - confirmText: '确定', - cancelText: '', - icon: 'checkmark-circle', - iconColor: '#10B981', - }, - () => { - // 用户点击确定后的回调 - console.log('用户确认了目标创建成功'); - } - ); - - // 创建目标后重新加载任务列表 - loadTasks(); - } catch (error) { - // 错误已在useEffect中处理 - } - }; - - - - // 导航到任务列表页面 - const handleNavigateToTasks = () => { - pushIfAuthedElseLogin('/task-list'); - }; - - // 计算各状态的任务数量 - const taskCounts = { - all: tasks.length, - pending: tasks.filter(task => task.status === 'pending').length, - completed: tasks.filter(task => task.status === 'completed').length, - skipped: tasks.filter(task => task.status === 'skipped').length, - }; - - // 根据筛选条件过滤任务,并将已完成的任务放到最后 - const filteredTasks = React.useMemo(() => { - let filtered: TaskListItem[] = []; - - switch (selectedFilter) { - case 'pending': - filtered = tasks.filter(task => task.status === 'pending'); - break; - case 'completed': - filtered = tasks.filter(task => task.status === 'completed'); - break; - case 'skipped': - filtered = tasks.filter(task => task.status === 'skipped'); - break; - default: - filtered = tasks; - break; - } - - // 对所有筛选结果进行排序:已完成的任务放到最后 - return [...filtered].sort((a, b) => { - // 如果a已完成而b未完成,a排在后面 - if (a.status === 'completed' && b.status !== 'completed') { - return 1; - } - // 如果b已完成而a未完成,b排在后面 - if (b.status === 'completed' && a.status !== 'completed') { - return -1; - } - // 如果都已完成或都未完成,保持原有顺序 - return 0; - }); - }, [tasks, selectedFilter]); - - // 处理筛选变化 - const handleFilterChange = (filter: TaskFilterType) => { - setSelectedFilter(filter); - }; - - // 处理引导完成 - const handleGuideComplete = async () => { - try { - await markGuideCompleted('GOALS_PAGE'); - setShowGuide(false); - } catch (error) { - console.error('保存引导状态失败:', error); - setShowGuide(false); - } - }; - - // 处理任务完成 - const handleTaskCompleted = (completedTask: TaskListItem) => { - // 触发震动反馈 - if (process.env.EXPO_OS === 'ios') { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); - } - - // 播放庆祝动画 - celebrationAnimationRef.current?.play(); - - console.log(`任务 "${completedTask.title}" 已完成,播放庆祝动画`); - }; - - // 渲染任务项 - const renderTaskItem = ({ item }: { item: TaskListItem }) => ( - - ); - - // 渲染空状态 - const renderEmptyState = () => { - // 未登录状态下的引导 - if (!isLoggedIn) { - return ( - - - - - {/* 清新的图标设计 */} - - - - - - - {/* 主标题 */} - - 开启您的健康之旅 - - - {/* 副标题 */} - - 登录后即可创建个人目标,让我们一起建立健康的生活习惯 - - - {/* 登录按钮 */} - pushIfAuthedElseLogin('/goals')} - > - - 立即登录 - - - - - - ); - } - - // 已登录但无任务的状态 - let title = '暂无任务'; - let subtitle = '创建目标后,系统会自动生成相应的任务'; - - if (selectedFilter === 'pending') { - title = '暂无待完成的任务'; - subtitle = '当前没有待完成的任务'; - } else if (selectedFilter === 'completed') { - title = '暂无已完成的任务'; - subtitle = '完成一些任务后,它们会显示在这里'; - } else if (selectedFilter === 'skipped') { - title = '暂无已跳过的任务'; - subtitle = '跳过一些任务后,它们会显示在这里'; - } - - return ( - - - - {title} - - - {subtitle} - - - ); - }; - - // 渲染加载更多 - const renderLoadMore = () => { - if (!tasksPagination.hasMore) return null; - return ( - - - {tasksLoading ? '加载中...' : '上拉加载更多'} - - - ); - }; - - return ( - - - - {/* 背景渐变 */} - - - - {/* 右下角Lottie动画 */} - - - - - {/* 标题区域 */} - - - - 习惯养成 - - - 自律让我更健康 - - - - - {/* 任务进度卡片 */} - - - - - 历史 - - - - - + - - - } - /> - - - {/* 任务筛选标签 */} - - - {/* 任务列表 */} - - item.id} - contentContainerStyle={styles.taskList} - showsVerticalScrollIndicator={false} - refreshControl={ - - } - onEndReached={handleLoadMoreTasks} - onEndReachedThreshold={0.1} - ListEmptyComponent={renderEmptyState} - ListFooterComponent={renderLoadMore} - /> - - - {/* 目标模板选择弹窗 */} - setShowTemplateModal(false)} - onSelectTemplate={handleSelectTemplate} - onCreateCustom={handleCreateCustomGoal} - /> - - {/* 创建目标弹窗 */} - { - setShowCreateModal(false); - setSelectedTemplateData(undefined); - }} - onSubmit={handleCreateGoal} - onSuccess={handleModalSuccess} - loading={createLoading} - initialData={selectedTemplateData} - /> - - {/* 目标页面引导 */} - - - {/* 开发测试按钮 */} - - - {/* 目标通知测试按钮 */} - {__DEV__ && ( - { - // 这里可以导航到测试页面或显示测试弹窗 - Alert.alert( - '目标通知测试', - '选择要测试的通知类型', - [ - { text: '取消', style: 'cancel' }, - { - text: '每日目标通知', - onPress: async () => { - try { - const userName = userProfile?.name || ''; - const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications( - { - title: '每日运动目标', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '09:00', - }, - userName - ); - Alert.alert('成功', `每日目标通知已创建,ID: ${notificationIds.join(', ')}`); - } catch (error) { - Alert.alert('错误', `创建通知失败: ${error}`); - } - } - }, - { - text: '每周目标通知', - onPress: async () => { - try { - const userName = userProfile?.name || ''; - const notificationIds = await GoalNotificationHelpers.scheduleGoalNotifications( - { - title: '每周运动目标', - repeatType: 'weekly', - frequency: 1, - hasReminder: true, - reminderTime: '10:00', - customRepeatRule: { - weekdays: [1, 3, 5], // 周一、三、五 - }, - }, - userName - ); - Alert.alert('成功', `每周目标通知已创建,ID: ${notificationIds.join(', ')}`); - } catch (error) { - Alert.alert('错误', `创建通知失败: ${error}`); - } - } - }, - { - text: '目标达成通知', - onPress: async () => { - try { - const userName = userProfile?.name || ''; - await GoalNotificationHelpers.sendGoalAchievementNotification(userName, '每日运动目标'); - Alert.alert('成功', '目标达成通知已发送'); - } catch (error) { - Alert.alert('错误', `发送通知失败: ${error}`); - } - } - }, - { - text: '测试庆祝动画', - onPress: () => { - celebrationAnimationRef.current?.play(); - } - }, - ] - ); - }} - > - 测试通知 - - )} - - {/* 庆祝动画组件 */} - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - gradientBackground: { - position: 'absolute', - left: 0, - right: 0, - top: 0, - bottom: 0, - opacity: 0.6, - }, - decorativeCircle1: { - position: 'absolute', - top: -20, - right: -20, - width: 60, - height: 60, - borderRadius: 30, - backgroundColor: '#0EA5E9', - opacity: 0.1, - }, - decorativeCircle2: { - position: 'absolute', - bottom: -15, - left: -15, - width: 40, - height: 40, - borderRadius: 20, - backgroundColor: '#0EA5E9', - opacity: 0.05, - }, - content: { - flex: 1, - }, - header: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 20, - paddingTop: 20, - paddingBottom: 16, - }, - headerButtons: { - flexDirection: 'row', - alignItems: 'center', - gap: 12, - }, - goalsButton: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 12, - paddingVertical: 8, - borderRadius: 20, - backgroundColor: 'rgba(255, 255, 255, 0.8)', - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, - }, - pageTitle: { - fontSize: 28, - fontWeight: '800', - marginBottom: 4, - }, - pageTitle2: { - fontSize: 16, - fontWeight: '400', - color: '#FFFFFF', - lineHeight: 24, - }, - addButton: { - width: 30, - height: 30, - borderRadius: 20, - backgroundColor: '#0EA5E9', - alignItems: 'center', - justifyContent: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, - }, - addButtonText: { - color: '#FFFFFF', - fontSize: 22, - fontWeight: '600', - lineHeight: 22, - }, - - taskListContainer: { - flex: 1, - borderTopLeftRadius: 24, - borderTopRightRadius: 24, - overflow: 'hidden', - }, - taskList: { - paddingHorizontal: 20, - paddingTop: 20, - paddingBottom: TAB_BAR_HEIGHT + TAB_BAR_BOTTOM_OFFSET + 20, // 避让底部导航栏 + 额外间距 - }, - emptyState: { - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 60, - }, - emptyStateImage: { - width: 223, - height: 59, - marginBottom: 20, - }, - emptyStateTitle: { - fontSize: 18, - fontWeight: '600', - marginBottom: 8, - }, - emptyStateSubtitle: { - fontSize: 14, - textAlign: 'center', - lineHeight: 20, - }, - // 未登录空状态样式 - emptyStateLogin: { - flex: 1, - alignItems: 'center', - justifyContent: 'center', - paddingHorizontal: 24, - paddingVertical: 80, - position: 'relative', - }, - emptyStateLoginBackground: { - position: 'absolute', - left: 0, - right: 0, - top: 0, - bottom: 0, - borderRadius: 24, - }, - emptyStateLoginContent: { - alignItems: 'center', - justifyContent: 'center', - zIndex: 1, - }, - emptyStateLoginIconContainer: { - marginBottom: 24, - shadowColor: '#7A5AF8', - shadowOffset: { width: 0, height: 8 }, - shadowOpacity: 0.15, - shadowRadius: 16, - elevation: 8, - }, - emptyStateLoginIconGradient: { - width: 80, - height: 80, - borderRadius: 40, - alignItems: 'center', - justifyContent: 'center', - }, - emptyStateLoginTitle: { - fontSize: 24, - fontWeight: '700', - marginBottom: 12, - textAlign: 'center', - letterSpacing: -0.5, - }, - emptyStateLoginSubtitle: { - fontSize: 16, - lineHeight: 24, - textAlign: 'center', - marginBottom: 32, - paddingHorizontal: 8, - }, - emptyStateLoginButton: { - borderRadius: 28, - shadowColor: '#7A5AF8', - shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.2, - shadowRadius: 12, - elevation: 6, - }, - emptyStateLoginButtonGradient: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - paddingHorizontal: 32, - paddingVertical: 16, - borderRadius: 28, - gap: 8, - }, - emptyStateLoginButtonText: { - color: '#FFFFFF', - fontSize: 17, - fontWeight: '600', - letterSpacing: -0.2, - }, - loadMoreContainer: { - alignItems: 'center', - paddingVertical: 20, - }, - loadMoreText: { - fontSize: 14, - fontWeight: '500', - }, - bottomRightImage: { - position: 'absolute', - top: 40, - right: 36, - width: 120, - height: 120, - }, - // 任务进度卡片中的按钮样式 - cardHeaderButtons: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }, - cardGoalsButton: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 10, - paddingVertical: 6, - borderRadius: 16, - backgroundColor: '#F3F4F6', - borderWidth: 1, - }, - cardGoalsListButton: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 10, - paddingVertical: 6, - borderRadius: 16, - backgroundColor: '#F3F4F6', - borderWidth: 1, - }, - cardGoalsButtonText: { - fontSize: 12, - fontWeight: '600', - color: '#374151', - }, - cardAddButton: { - width: 28, - height: 28, - borderRadius: 14, - alignItems: 'center', - justifyContent: 'center', - }, - cardAddButtonText: { - color: '#FFFFFF', - fontSize: 18, - fontWeight: '600', - lineHeight: 18, - }, - testButton: { - position: 'absolute', - top: 100, - right: 20, - backgroundColor: '#10B981', - paddingHorizontal: 12, - paddingVertical: 8, - borderRadius: 8, - zIndex: 1000, - }, - testButtonText: { - color: '#FFFFFF', - fontSize: 12, - fontWeight: '600', - }, -}); diff --git a/app/_layout.tsx b/app/_layout.tsx index d787caa..b9a4fdc 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -18,13 +18,14 @@ import { store } from '@/store'; import { hydrateActiveSchedule, selectActiveFastingSchedule } from '@/store/fastingSlice'; import { fetchMyProfile, setPrivacyAgreed } from '@/store/userSlice'; import { createWaterRecordAction } from '@/store/waterSlice'; -import { ensureHealthPermissions, initializeHealthPermissions } from '@/utils/health'; import { loadActiveFastingSchedule } from '@/utils/fasting'; +import { ensureHealthPermissions, initializeHealthPermissions } from '@/utils/health'; import { MoodNotificationHelpers, NutritionNotificationHelpers } from '@/utils/notificationHelpers'; import { clearPendingWaterRecords, syncPendingWidgetChanges } from '@/utils/widgetDataSync'; import React, { useEffect } from 'react'; import { DialogProvider } from '@/components/ui/DialogProvider'; +import { MembershipModalProvider } from '@/contexts/MembershipModalContext'; import { ToastProvider } from '@/contexts/ToastContext'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { STORAGE_KEYS } from '@/services/api'; @@ -32,7 +33,6 @@ import { BackgroundTaskManager } from '@/services/backgroundTaskManager'; import { fetchChallenges } from '@/store/challengesSlice'; import AsyncStorage from '@/utils/kvStore'; import { Provider } from 'react-redux'; -import { MembershipModalProvider } from '@/contexts/MembershipModalContext'; function Bootstrapper({ children }: { children: React.ReactNode }) { @@ -242,8 +242,6 @@ export default function RootLayout() { - - diff --git a/app/goals-list.tsx b/app/goals-list.tsx deleted file mode 100644 index ebd112a..0000000 --- a/app/goals-list.tsx +++ /dev/null @@ -1,471 +0,0 @@ -import { GoalCard } from '@/components/GoalCard'; -import { CreateGoalModal } from '@/components/model/CreateGoalModal'; -import { useGlobalDialog } from '@/components/ui/DialogProvider'; -import { Colors } from '@/constants/Colors'; -import { TAB_BAR_BOTTOM_OFFSET, TAB_BAR_HEIGHT } from '@/constants/TabBar'; -import { useAppDispatch, useAppSelector } from '@/hooks/redux'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import { deleteGoal, fetchGoals, loadMoreGoals, updateGoal } from '@/store/goalsSlice'; -import { CreateGoalRequest, GoalListItem, UpdateGoalRequest } from '@/types/goals'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { useFocusEffect } from '@react-navigation/native'; -import { LinearGradient } from 'expo-linear-gradient'; -import { useRouter } from 'expo-router'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { Alert, FlatList, RefreshControl, StatusBar, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { SafeAreaView } from 'react-native-safe-area-context'; - -export default function GoalsListScreen() { - const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; - const colorTokens = Colors[theme]; - const dispatch = useAppDispatch(); - const router = useRouter(); - - const { showConfirm } = useGlobalDialog(); - - // Redux状态 - const { - goals, - goalsLoading, - goalsError, - goalsPagination, - updateLoading, - updateError, - } = useAppSelector((state) => state.goals); - - const [refreshing, setRefreshing] = useState(false); - - // 编辑目标相关状态 - const [showEditModal, setShowEditModal] = useState(false); - const [editingGoal, setEditingGoal] = useState(null); - - // 页面聚焦时重新加载数据 - useFocusEffect( - useCallback(() => { - console.log('useFocusEffect - loading goals'); - loadGoals(); - }, [dispatch]) - ); - - // 加载目标列表 - const loadGoals = async () => { - try { - await dispatch(fetchGoals({ - page: 1, - pageSize: 20, - sortBy: 'createdAt', - sortOrder: 'desc', - })).unwrap(); - } catch (error) { - console.error('Failed to load goals:', error); - // 在开发模式下,如果API调用失败,使用模拟数据 - if (__DEV__) { - console.log('Using mock data for development'); - // 添加模拟数据用于测试左滑删除功能 - const mockGoals: GoalListItem[] = [ - { - id: 'mock-1', - userId: 'test-user-1', - title: '每日运动30分钟', - repeatType: 'daily', - frequency: 1, - status: 'active', - completedCount: 5, - targetCount: 30, - hasReminder: true, - reminderTime: '09:00', - category: '运动', - priority: 5, - startDate: '2024-01-01', - startTime: 900, - endTime: 1800, - progressPercentage: 17, - }, - { - id: 'mock-2', - userId: 'test-user-1', - title: '每天喝8杯水', - repeatType: 'daily', - frequency: 8, - status: 'active', - completedCount: 6, - targetCount: 8, - hasReminder: true, - reminderTime: '10:00', - category: '健康', - priority: 8, - startDate: '2024-01-01', - startTime: 600, - endTime: 2200, - progressPercentage: 75, - }, - { - id: 'mock-3', - userId: 'test-user-1', - title: '每周读书2小时', - repeatType: 'weekly', - frequency: 2, - status: 'paused', - completedCount: 1, - targetCount: 2, - hasReminder: false, - category: '学习', - priority: 3, - startDate: '2024-01-01', - startTime: 800, - endTime: 2000, - progressPercentage: 50, - }, - ]; - - // 直接更新 Redux 状态(仅用于开发测试) - dispatch({ - type: 'goals/fetchGoals/fulfilled', - payload: { - query: { page: 1, pageSize: 20, sortBy: 'createdAt', sortOrder: 'desc' }, - response: { - list: mockGoals, - page: 1, - pageSize: 20, - total: mockGoals.length, - } - } - }); - } - } - }; - - // 下拉刷新 - const onRefresh = async () => { - setRefreshing(true); - try { - await loadGoals(); - } finally { - setRefreshing(false); - } - }; - - // 加载更多目标 - const handleLoadMoreGoals = async () => { - if (goalsPagination.hasMore && !goalsLoading) { - try { - await dispatch(loadMoreGoals()).unwrap(); - } catch (error) { - console.error('Failed to load more goals:', error); - } - } - }; - - // 处理删除目标 - const handleDeleteGoal = async (goalId: string) => { - try { - await dispatch(deleteGoal(goalId)).unwrap(); - // 删除成功,Redux 会自动更新状态 - } catch (error) { - console.error('Failed to delete goal:', error); - Alert.alert('错误', '删除目标失败,请重试'); - } - }; - - // 处理错误提示 - useEffect(() => { - if (goalsError) { - Alert.alert('错误', goalsError); - } - if (updateError) { - Alert.alert('更新失败', updateError); - } - }, [goalsError, updateError]); - - - // 根据筛选条件过滤目标 - const filteredGoals = useMemo(() => { - return goals; - }, [goals]); - - - - // 处理目标点击 - const handleGoalPress = (goal: GoalListItem) => { - setEditingGoal(goal); - setShowEditModal(true); - }; - - // 将 GoalListItem 转换为 CreateGoalRequest 格式 - const convertGoalToModalData = (goal: GoalListItem): Partial => { - return { - title: goal.title, - description: goal.description, - repeatType: goal.repeatType, - frequency: goal.frequency, - category: goal.category, - priority: goal.priority, - hasReminder: goal.hasReminder, - reminderTime: goal.reminderTime, - customRepeatRule: goal.customRepeatRule, - endDate: goal.endDate, - }; - }; - - // 处理更新目标 - const handleUpdateGoal = async (goalId: string, goalData: UpdateGoalRequest) => { - try { - await dispatch(updateGoal({ goalId, goalData })).unwrap(); - setShowEditModal(false); - setEditingGoal(null); - - // 使用全局弹窗显示成功消息 - showConfirm( - { - title: '目标更新成功', - message: '恭喜!您的目标已成功更新。', - confirmText: '确定', - cancelText: '', - icon: 'checkmark-circle', - iconColor: '#10B981', - }, - () => { - console.log('用户确认了目标更新成功'); - } - ); - } catch (error) { - console.error('Failed to update goal:', error); - Alert.alert('错误', '更新目标失败,请重试'); - // 更新失败时不关闭弹窗,保持编辑状态 - } - }; - - // 处理编辑弹窗关闭 - const handleCloseEditModal = () => { - setShowEditModal(false); - setEditingGoal(null); - }; - - // 渲染目标项 - const renderGoalItem = ({ item }: { item: GoalListItem }) => ( - - ); - - // 渲染空状态 - const renderEmptyState = () => { - let title = '暂无目标'; - let subtitle = '创建您的第一个目标,开始您的健康之旅'; - - - - return ( - - - - {title} - - - {subtitle} - - router.push('/(tabs)/goals')} - > - 创建目标 - - - ); - }; - - - - // 渲染加载更多 - const renderLoadMore = () => { - if (!goalsPagination.hasMore) return null; - return ( - - - {goalsLoading ? '加载中...' : '上拉加载更多'} - - - ); - }; - - return ( - - - - {/* 背景渐变 */} - - - - {/* 标题区域 */} - - router.back()} - > - - - - 目标列表 - - router.push('/(tabs)/goals')} - > - - - - - - {/* 目标列表 */} - - item.id} - contentContainerStyle={styles.goalsList} - showsVerticalScrollIndicator={false} - refreshControl={ - - } - onEndReached={handleLoadMoreGoals} - onEndReachedThreshold={0.1} - ListEmptyComponent={renderEmptyState} - ListFooterComponent={renderLoadMore} - /> - - - {/* 编辑目标弹窗 */} - {editingGoal && ( - {}} // 编辑模式下不使用这个回调 - onUpdate={handleUpdateGoal} - loading={updateLoading} - initialData={convertGoalToModalData(editingGoal)} - editGoalId={editingGoal.id} - /> - )} - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - gradientBackground: { - position: 'absolute', - left: 0, - right: 0, - top: 0, - bottom: 0, - }, - content: { - flex: 1, - }, - header: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 20, - paddingTop: 20, - paddingBottom: 16, - }, - backButton: { - width: 40, - height: 40, - borderRadius: 20, - backgroundColor: 'rgba(255, 255, 255, 0.8)', - alignItems: 'center', - justifyContent: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, - }, - pageTitle: { - fontSize: 24, - fontWeight: '700', - flex: 1, - textAlign: 'center', - }, - addButton: { - width: 40, - height: 40, - borderRadius: 20, - backgroundColor: '#7A5AF8', - alignItems: 'center', - justifyContent: 'center', - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, - }, - goalsListContainer: { - flex: 1, - borderTopLeftRadius: 24, - borderTopRightRadius: 24, - overflow: 'hidden', - }, - goalsList: { - paddingHorizontal: 20, - paddingTop: 20, - paddingBottom: TAB_BAR_HEIGHT + TAB_BAR_BOTTOM_OFFSET + 20, - }, - emptyState: { - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 80, - }, - emptyStateTitle: { - fontSize: 18, - fontWeight: '600', - marginTop: 16, - marginBottom: 8, - }, - emptyStateSubtitle: { - fontSize: 14, - textAlign: 'center', - lineHeight: 20, - marginBottom: 24, - paddingHorizontal: 40, - }, - createButton: { - paddingHorizontal: 24, - paddingVertical: 12, - borderRadius: 20, - }, - createButtonText: { - color: '#FFFFFF', - fontSize: 16, - fontWeight: '600', - }, - loadMoreContainer: { - alignItems: 'center', - paddingVertical: 20, - }, - loadMoreText: { - fontSize: 14, - fontWeight: '500', - }, -}); diff --git a/app/task-detail.tsx b/app/task-detail.tsx deleted file mode 100644 index 944d62d..0000000 --- a/app/task-detail.tsx +++ /dev/null @@ -1,659 +0,0 @@ -import { useGlobalDialog } from '@/components/ui/DialogProvider'; -import { HeaderBar } from '@/components/ui/HeaderBar'; -import { Colors } from '@/constants/Colors'; -import { useAppDispatch, useAppSelector } from '@/hooks/redux'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding'; -import { completeTask, skipTask } from '@/store/tasksSlice'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { useLocalSearchParams, useRouter } from 'expo-router'; -import React, { useState } from 'react'; -import { - Alert, - Image, - ScrollView, - StyleSheet, - Text, - TextInput, - TouchableOpacity, - View -} from 'react-native'; - -export default function TaskDetailScreen() { - const safeAreaTop = useSafeAreaTop() - const { taskId } = useLocalSearchParams<{ taskId: string }>(); - const router = useRouter(); - const theme = useColorScheme() ?? 'light'; - const colorTokens = Colors[theme]; - const dispatch = useAppDispatch(); - const { showConfirm } = useGlobalDialog(); - - // 从Redux中获取任务数据 - const { tasks, tasksLoading } = useAppSelector(state => state.tasks); - const task = tasks.find(t => t.id === taskId) || null; - - const [comment, setComment] = useState(''); - - const getStatusText = (status: string) => { - switch (status) { - case 'completed': - return '已完成'; - case 'in_progress': - return '进行中'; - case 'overdue': - return '已过期'; - case 'skipped': - return '已跳过'; - default: - return '待开始'; - } - }; - - const getStatusColor = (status: string) => { - switch (status) { - case 'completed': - return '#10B981'; - case 'in_progress': - return '#7A5AF8'; - case 'overdue': - return '#EF4444'; - case 'skipped': - return '#6B7280'; - default: - return '#6B7280'; - } - }; - - const getDifficultyText = (difficulty: string) => { - switch (difficulty) { - case 'very_easy': - return '非常简单 (少于一天)'; - case 'easy': - return '简单 (1-2天)'; - case 'medium': - return '中等 (3-5天)'; - case 'hard': - return '困难 (1-2周)'; - case 'very_hard': - return '非常困难 (2周以上)'; - default: - return '非常简单 (少于一天)'; - } - }; - - const getDifficultyColor = (difficulty: string) => { - switch (difficulty) { - case 'very_easy': - return '#10B981'; - case 'easy': - return '#34D399'; - case 'medium': - return '#F59E0B'; - case 'hard': - return '#F97316'; - case 'very_hard': - return '#EF4444'; - default: - return '#10B981'; - } - }; - - const formatDate = (dateString: string) => { - const date = new Date(dateString); - const options: Intl.DateTimeFormatOptions = { - year: 'numeric', - month: 'long', - day: 'numeric' - }; - return `创建于 ${date.toLocaleDateString('zh-CN', options)}`; - }; - - const handleCompleteTask = async () => { - if (!task || task.status === 'completed') { - return; - } - - try { - await dispatch(completeTask({ - taskId: task.id, - completionData: { - count: 1, - notes: '通过任务详情页面完成' - } - })).unwrap(); - - // 检查任务是否真正完成(当前完成次数是否达到目标次数) - const updatedTask = tasks.find(t => t.id === task.id); - if (updatedTask && updatedTask.currentCount >= updatedTask.targetCount) { - Alert.alert('成功', '任务已完成!'); - router.back(); - } else { - Alert.alert('成功', '任务进度已更新!'); - } - } catch (error) { - Alert.alert('错误', '完成任务失败,请重试'); - } - }; - - const handleSkipTask = async () => { - if (!task || task.status === 'completed' || task.status === 'skipped') { - return; - } - - showConfirm( - { - title: '确认跳过任务', - message: `确定要跳过任务"${task.title}"吗?\n\n跳过后的任务将不会显示在任务列表中,且无法恢复。`, - confirmText: '跳过', - cancelText: '取消', - destructive: true, - icon: 'warning', - iconColor: '#F59E0B', - }, - async () => { - try { - await dispatch(skipTask({ - taskId: task.id, - skipData: { - reason: '用户主动跳过' - } - })).unwrap(); - - Alert.alert('成功', '任务已跳过!'); - router.back(); - } catch (error) { - Alert.alert('错误', '跳过任务失败,请重试'); - } - } - ); - }; - - const handleSendComment = () => { - if (comment.trim()) { - // 这里应该调用API发送评论 - console.log('发送评论:', comment); - setComment(''); - Alert.alert('成功', '评论已发送!'); - } - }; - - if (tasksLoading) { - return ( - - router.back()} - /> - - - 加载中... - - - ); - } - - if (!task) { - return ( - - router.back()} - /> - - - 任务不存在 - - - ); - } - - return ( - - {/* 使用HeaderBar组件 */} - router.back()} - right={ - task.status !== 'completed' && task.status !== 'skipped' && task.currentCount < task.targetCount ? ( - - - - ) : undefined - } - /> - - - {/* 任务标题和创建时间 */} - - {task.title} - - {formatDate(task.startDate)} - - - - {/* 状态标签 */} - - - {getStatusText(task.status)} - - - - {/* 描述区域 */} - - 描述 - - {task.description || '暂无描述'} - - - - {/* 优先级和难度 */} - - - 优先级 - - - - - - - - 难度 - - - 非常简单 (少于一天) - - - - - {/* 任务进度信息 */} - - 进度 - - {/* 进度条 */} - - 0 ? `${Math.min(task.progressPercentage, 100)}%` : '2%', - backgroundColor: task.progressPercentage >= 100 - ? '#10B981' - : task.progressPercentage >= 50 - ? '#F59E0B' - : task.progressPercentage > 0 - ? colorTokens.primary - : '#E5E7EB', - }, - ]} - /> - {task.progressPercentage > 0 && task.progressPercentage < 100 && ( - - )} - {/* 进度文本 */} - - {task.currentCount}/{task.targetCount} - - - - {/* 进度详细信息 */} - - - 目标次数 - {task.targetCount} - - - 已完成 - {task.currentCount} - - - 剩余天数 - {task.daysRemaining} - - - - - {/* 底部操作按钮 */} - {task.status !== 'completed' && task.status !== 'skipped' && task.currentCount < task.targetCount && ( - - - - 跳过任务 - - - )} - - {/* 评论区域 */} - - 评论区域 - - - - - - - - - - - - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - loadingContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - loadingText: { - fontSize: 16, - fontWeight: '500', - }, - errorContainer: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - }, - errorText: { - fontSize: 16, - fontWeight: '500', - }, - completeButton: { - width: 32, - height: 32, - borderRadius: 16, - backgroundColor: '#7A5AF8', - alignItems: 'center', - justifyContent: 'center', - }, - taskIcon: { - width: 20, - height: 20, - }, - scrollView: { - flex: 1, - }, - titleSection: { - padding: 16, - paddingBottom: 8, - }, - taskTitle: { - fontSize: 20, - fontWeight: '600', - lineHeight: 28, - marginBottom: 4, - }, - createdDate: { - fontSize: 14, - fontWeight: '400', - opacity: 0.7, - }, - statusContainer: { - paddingHorizontal: 16, - paddingBottom: 16, - alignItems: 'flex-end', - }, - statusTag: { - alignSelf: 'flex-end', - paddingHorizontal: 12, - paddingVertical: 6, - borderRadius: 16, - }, - statusTagText: { - fontSize: 14, - fontWeight: '600', - color: '#FFFFFF', - }, - imagePlaceholder: { - height: 240, - backgroundColor: '#F9FAFB', - marginHorizontal: 16, - marginBottom: 20, - borderRadius: 12, - borderWidth: 2, - borderColor: '#E5E7EB', - borderStyle: 'dashed', - alignItems: 'center', - justifyContent: 'center', - }, - imagePlaceholderText: { - fontSize: 16, - fontWeight: '500', - color: '#9CA3AF', - marginTop: 8, - }, - descriptionSection: { - paddingHorizontal: 16, - marginBottom: 20, - }, - sectionTitle: { - fontSize: 16, - fontWeight: '600', - marginBottom: 12, - }, - descriptionText: { - fontSize: 15, - lineHeight: 22, - fontWeight: '400', - }, - infoSection: { - paddingHorizontal: 16, - marginBottom: 20, - }, - infoItem: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - marginBottom: 12, - }, - infoLabel: { - fontSize: 15, - fontWeight: '500', - }, - priorityTag: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 10, - paddingVertical: 4, - borderRadius: 12, - backgroundColor: '#EF4444', - }, - priorityTagText: { - fontSize: 13, - fontWeight: '600', - color: '#FFFFFF', - }, - difficultyTag: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 10, - paddingVertical: 4, - borderRadius: 12, - }, - difficultyTagText: { - fontSize: 13, - fontWeight: '600', - color: '#FFFFFF', - }, - progressSection: { - paddingHorizontal: 16, - marginBottom: 20, - }, - progressBar: { - height: 6, - backgroundColor: '#F3F4F6', - borderRadius: 3, - marginBottom: 16, - overflow: 'visible', - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.1, - shadowRadius: 2, - elevation: 2, - position: 'relative', - }, - progressFill: { - height: '100%', - borderRadius: 3, - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.2, - shadowRadius: 2, - elevation: 3, - }, - progressGlow: { - position: 'absolute', - right: 0, - top: 0, - width: 8, - height: '100%', - backgroundColor: 'rgba(255, 255, 255, 0.6)', - borderRadius: 3, - }, - progressTextContainer: { - position: 'absolute', - right: 0, - top: -6, - backgroundColor: '#FFFFFF', - paddingHorizontal: 6, - paddingVertical: 2, - borderRadius: 8, - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.1, - shadowRadius: 2, - elevation: 2, - borderWidth: 1, - borderColor: '#E5E7EB', - zIndex: 1, - }, - progressText: { - fontSize: 10, - fontWeight: '600', - color: '#374151', - }, - progressInfo: { - flexDirection: 'row', - justifyContent: 'space-between', - }, - progressItem: { - alignItems: 'center', - flex: 1, - }, - progressLabel: { - fontSize: 13, - fontWeight: '400', - marginBottom: 4, - }, - progressValue: { - fontSize: 18, - fontWeight: '600', - }, - commentSection: { - paddingHorizontal: 16, - marginBottom: 20, - }, - commentInputContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 12, - }, - commentAvatar: { - width: 28, - height: 28, - borderRadius: 14, - overflow: 'hidden', - }, - commentAvatarImage: { - width: '100%', - height: '100%', - }, - commentInputWrapper: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }, - commentInput: { - flex: 1, - minHeight: 36, - maxHeight: 120, - paddingHorizontal: 12, - paddingVertical: 8, - borderRadius: 18, - fontSize: 15, - textAlignVertical: 'top', - }, - sendButton: { - width: 28, - height: 28, - borderRadius: 14, - alignItems: 'center', - justifyContent: 'center', - }, - actionButtons: { - paddingHorizontal: 16, - paddingBottom: 20, - }, - actionButton: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - gap: 8, - paddingVertical: 12, - paddingHorizontal: 16, - borderRadius: 8, - borderWidth: 1, - }, - skipButton: { - backgroundColor: '#F9FAFB', - borderColor: '#E5E7EB', - }, - skipButtonText: { - fontSize: 16, - fontWeight: '500', - color: '#6B7280', - }, -}); diff --git a/app/task-list.tsx b/app/task-list.tsx deleted file mode 100644 index 7a2bc63..0000000 --- a/app/task-list.tsx +++ /dev/null @@ -1,289 +0,0 @@ -import { DateSelector } from '@/components/DateSelector'; -import { TaskCard } from '@/components/TaskCard'; -import { HeaderBar } from '@/components/ui/HeaderBar'; -import { Colors } from '@/constants/Colors'; -import { TAB_BAR_BOTTOM_OFFSET, TAB_BAR_HEIGHT } from '@/constants/TabBar'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding'; -import { tasksApi } from '@/services/tasksApi'; -import { TaskListItem } from '@/types/goals'; -import { getTodayIndexInMonth } from '@/utils/date'; -import { useFocusEffect } from '@react-navigation/native'; -import dayjs from 'dayjs'; -import { LinearGradient } from 'expo-linear-gradient'; -import { useRouter } from 'expo-router'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { Alert, FlatList, RefreshControl, StyleSheet, Text, View } from 'react-native'; - -export default function GoalsDetailScreen() { - const safeAreaTop = useSafeAreaTop() - const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; - const colorTokens = Colors[theme]; - const router = useRouter(); - - // 本地状态管理 - const [tasks, setTasks] = useState([]); - const [tasksLoading, setTasksLoading] = useState(false); - const [tasksError, setTasksError] = useState(null); - const [selectedDate, setSelectedDate] = useState(new Date()); - const [refreshing, setRefreshing] = useState(false); - - // 日期选择器相关状态 - const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth()); - - // 加载任务列表 - const loadTasks = async (targetDate?: Date) => { - try { - setTasksLoading(true); - setTasksError(null); - - const dateToUse = targetDate || selectedDate; - console.log('Loading tasks for date:', dayjs(dateToUse).format('YYYY-MM-DD')); - - const response = await tasksApi.getTasks({ - startDate: dayjs(dateToUse).startOf('day').toISOString(), - endDate: dayjs(dateToUse).endOf('day').toISOString(), - }); - - console.log('Tasks API response:', response); - setTasks(response.list || []); - } catch (error: any) { - console.error('Failed to load tasks:', error); - setTasksError(error.message || '获取任务列表失败'); - setTasks([]); - } finally { - setTasksLoading(false); - } - }; - - // 页面聚焦时重新加载数据 - useFocusEffect( - useCallback(() => { - console.log('useFocusEffect - loading tasks'); - loadTasks(); - }, []) - ); - - // 下拉刷新 - const onRefresh = async () => { - setRefreshing(true); - try { - await loadTasks(); - } finally { - setRefreshing(false); - } - }; - - // 处理错误提示 - useEffect(() => { - if (tasksError) { - Alert.alert('错误', tasksError); - setTasksError(null); - } - }, [tasksError]); - - - - // 日期选择处理 - const onSelectDate = async (index: number, date: Date) => { - console.log('Date selected:', dayjs(date).format('YYYY-MM-DD')); - setSelectedIndex(index); - setSelectedDate(date); - // 重新加载对应日期的任务数据 - await loadTasks(date); - }; - - // 根据选中日期筛选任务,并将已完成的任务放到最后 - const filteredTasks = useMemo(() => { - const selected = dayjs(selectedDate); - const filtered = tasks.filter(task => { - if (task.status === 'skipped') return false; - const taskDate = dayjs(task.startDate); - return taskDate.isSame(selected, 'day'); - }); - - // 对筛选结果进行排序:已完成的任务放到最后 - return [...filtered].sort((a, b) => { - const aCompleted = a.status === 'completed'; - const bCompleted = b.status === 'completed'; - - // 如果a已完成而b未完成,a排在后面 - if (aCompleted && !bCompleted) { - return 1; - } - // 如果b已完成而a未完成,b排在后面 - if (bCompleted && !aCompleted) { - return -1; - } - // 如果都已完成或都未完成,保持原有顺序 - return 0; - }); - }, [selectedDate, tasks]); - - const handleBackPress = () => { - router.back(); - }; - - // 渲染任务项 - const renderTaskItem = ({ item }: { item: TaskListItem }) => ( - - ); - - // 渲染空状态 - const renderEmptyState = () => { - const selectedDateStr = dayjs(selectedDate).format('YYYY年M月D日'); - - if (tasksLoading) { - return ( - - - 加载中... - - - ); - } - - return ( - - - 暂无任务 - - - {selectedDateStr} 没有任务安排 - - - ); - }; - - return ( - - - {/* 标题区域 */} - - {/* 背景渐变 */} - - - {/* 装饰性圆圈 */} - - - - - - - - - - {/* 日期选择器 */} - - - - - {/* 任务列表 */} - - item.id} - contentContainerStyle={styles.taskList} - showsVerticalScrollIndicator={false} - refreshControl={ - - } - ListEmptyComponent={renderEmptyState} - /> - - - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - gradientBackground: { - position: 'absolute', - left: 0, - right: 0, - top: 0, - bottom: 0, - opacity: 0.6, - }, - decorativeCircle1: { - position: 'absolute', - top: -20, - right: -20, - width: 60, - height: 60, - borderRadius: 30, - backgroundColor: '#0EA5E9', - opacity: 0.1, - }, - decorativeCircle2: { - position: 'absolute', - bottom: -15, - left: -15, - width: 40, - height: 40, - borderRadius: 20, - backgroundColor: '#0EA5E9', - opacity: 0.05, - }, - content: { - flex: 1, - }, - - // 日期选择器样式 - dateSelector: { - paddingHorizontal: 20, - }, - taskListContainer: { - flex: 1, - borderTopLeftRadius: 24, - borderTopRightRadius: 24, - overflow: 'hidden', - }, - taskList: { - paddingHorizontal: 20, - paddingBottom: TAB_BAR_HEIGHT + TAB_BAR_BOTTOM_OFFSET + 20, - }, - emptyState: { - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 60, - }, - emptyStateTitle: { - fontSize: 18, - fontWeight: '600', - marginBottom: 8, - }, - emptyStateSubtitle: { - fontSize: 14, - textAlign: 'center', - lineHeight: 20, - }, -}); diff --git a/components/GoalCard.tsx b/components/GoalCard.tsx deleted file mode 100644 index 971ef3f..0000000 --- a/components/GoalCard.tsx +++ /dev/null @@ -1,304 +0,0 @@ -import { GoalListItem } from '@/types/goals'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import React, { useRef } from 'react'; -import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; -import { Swipeable } from 'react-native-gesture-handler'; - -interface GoalCardProps { - goal: GoalListItem; - onPress?: (goal: GoalListItem) => void; - onDelete?: (goalId: string) => void; - showStatus?: boolean; -} - -export const GoalCard: React.FC = ({ - goal, - onPress, - onDelete, - showStatus = true -}) => { - const swipeableRef = useRef(null); - - // 获取重复类型显示文本 - const getRepeatTypeText = (goal: GoalListItem) => { - switch (goal.repeatType) { - case 'daily': - return '每日'; - case 'weekly': - return '每周'; - case 'monthly': - return '每月'; - default: - return '每日'; - } - }; - - // 获取目标状态显示文本 - const getStatusText = (goal: GoalListItem) => { - switch (goal.status) { - case 'active': - return '进行中'; - case 'paused': - return '已暂停'; - case 'completed': - return '已完成'; - case 'cancelled': - return '已取消'; - default: - return '进行中'; - } - }; - - // 获取目标状态颜色 - const getStatusColor = (goal: GoalListItem) => { - switch (goal.status) { - case 'active': - return '#10B981'; - case 'paused': - return '#F59E0B'; - case 'completed': - return '#3B82F6'; - case 'cancelled': - return '#EF4444'; - default: - return '#10B981'; - } - }; - - // 获取目标图标 - const getGoalIcon = (goal: GoalListItem) => { - // 根据目标类别或标题返回不同的图标 - const title = goal.title.toLowerCase(); - const category = goal.category?.toLowerCase(); - - if (title.includes('运动') || title.includes('健身') || title.includes('跑步')) { - return 'fitness-center'; - } else if (title.includes('喝水') || title.includes('饮水')) { - return 'local-drink'; - } else if (title.includes('睡眠') || title.includes('睡觉')) { - return 'bedtime'; - } else if (title.includes('学习') || title.includes('读书')) { - return 'school'; - } else if (title.includes('冥想') || title.includes('放松')) { - return 'self-improvement'; - } else if (title.includes('早餐') || title.includes('午餐') || title.includes('晚餐')) { - return 'restaurant'; - } else { - return 'flag'; - } - }; - - // 处理删除操作 - const handleDelete = () => { - Alert.alert( - '确认删除', - `确定要删除目标"${goal.title}"吗?此操作无法撤销。`, - [ - { - text: '取消', - style: 'cancel', - }, - { - text: '删除', - style: 'destructive', - onPress: () => { - onDelete?.(goal.id); - swipeableRef.current?.close(); - }, - }, - ] - ); - }; - - // 渲染删除按钮 - const renderRightActions = () => { - return ( - - - - ); - }; - - return ( - - onPress?.(goal)} - activeOpacity={0.7} - > - {/* 左侧图标 */} - - - - - - - - - {/* 中间内容 */} - - - {goal.title} - - - {/* 底部信息行 */} - - {/* 积分 */} - - +1 - - - {/* 目标数量 */} - - - {goal.targetCount || goal.frequency} - - - - {/* 提醒图标(如果有提醒) */} - {goal.hasReminder && ( - - - - )} - - {/* 提醒时间(如果有提醒) */} - {goal.hasReminder && goal.reminderTime && ( - - {goal.reminderTime} - - )} - - {/* 重复图标 */} - - - - - {/* 重复类型 */} - - {getRepeatTypeText(goal)} - - - {/* 结束日期 */} - {goal.endDate && ( - - - {goal.endDate} - - )} - - - - {/* 右侧状态指示器 */} - {showStatus && ( - - {getStatusText(goal)} - - )} - - - ); -}; - -const styles = StyleSheet.create({ - goalCard: { - flexDirection: 'row', - alignItems: 'center', - backgroundColor: '#FFFFFF', - borderRadius: 16, - padding: 16, - marginBottom: 12, - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.05, - shadowRadius: 8, - elevation: 2, - }, - goalIcon: { - width: 32, - height: 32, - borderRadius: 20, - backgroundColor: '#F3F4F6', - alignItems: 'center', - justifyContent: 'center', - marginRight: 12, - position: 'relative', - }, - iconStars: { - position: 'absolute', - top: -2, - right: -2, - flexDirection: 'row', - gap: 1, - }, - star: { - width: 4, - height: 4, - borderRadius: 2, - backgroundColor: '#FFFFFF', - }, - goalContent: { - flex: 1, - marginRight: 12, - }, - goalTitle: { - fontSize: 14, - fontWeight: '600', - color: '#1F2937', - marginBottom: 8, - }, - goalInfo: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }, - infoItem: { - flexDirection: 'row', - alignItems: 'center', - }, - infoText: { - fontSize: 12, - color: '#9CA3AF', - fontWeight: '500', - }, - statusIndicator: { - paddingHorizontal: 8, - paddingVertical: 4, - borderRadius: 12, - minWidth: 60, - alignItems: 'center', - }, - statusText: { - fontSize: 10, - color: '#FFFFFF', - fontWeight: '600', - }, - deleteButton: { - width: 60, - height: '100%', - justifyContent: 'center', - alignItems: 'center', - }, - deleteButtonText: { - color: '#FFFFFF', - fontSize: 12, - fontWeight: '600', - marginTop: 4, - }, -}); diff --git a/components/GoalCarousel.tsx b/components/GoalCarousel.tsx deleted file mode 100644 index ceb979f..0000000 --- a/components/GoalCarousel.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { Colors } from '@/constants/Colors'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import React, { useRef } from 'react'; -import { Dimensions, ScrollView, StyleSheet, Text, View } from 'react-native'; -import { GoalCard, GoalItem } from './GoalCard'; - -interface GoalCarouselProps { - goals: GoalItem[]; - onGoalPress?: (item: GoalItem) => void; -} - -const { width: screenWidth } = Dimensions.get('window'); - -export function GoalCarousel({ goals, onGoalPress }: GoalCarouselProps) { - const theme = useColorScheme() ?? 'light'; - const colorTokens = Colors[theme]; - const scrollViewRef = useRef(null); - - if (!goals || goals.length === 0) { - return ( - - - 今天暂无目标 - - - ); - } - - return ( - - - {goals.map((item, index) => ( - - ))} - {/* 占位符,确保最后一张卡片有足够的滑动空间 */} - - - - {/* 底部指示器 */} - {/* - {goals.map((_, index) => ( - - ))} - */} - - ); -} - -const styles = StyleSheet.create({ - container: { - }, - scrollView: { - }, - scrollContent: { - paddingHorizontal: 20, - alignItems: 'center', - }, - emptyContainer: { - height: 140, - justifyContent: 'center', - alignItems: 'center', - marginHorizontal: 20, - borderRadius: 20, - borderWidth: 1, - borderColor: '#E5E7EB', - borderStyle: 'dashed', - }, - emptyText: { - fontSize: 14, - fontWeight: '500', - }, - indicatorContainer: { - flexDirection: 'row', - justifyContent: 'center', - alignItems: 'center', - gap: 6, - }, - indicator: { - width: 6, - height: 6, - borderRadius: 3, - }, -}); diff --git a/components/GoalsPageGuide.tsx b/components/GoalsPageGuide.tsx deleted file mode 100644 index ef1359a..0000000 --- a/components/GoalsPageGuide.tsx +++ /dev/null @@ -1,457 +0,0 @@ -import { TaskListItem } from '@/types/goals'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import React, { useEffect, useRef, useState } from 'react'; -import { - Animated, - Dimensions, - Modal, - StatusBar, - StyleSheet, - Text, - TouchableOpacity, - View, -} from 'react-native'; - -interface GoalsPageGuideProps { - visible: boolean; - onComplete: () => void; - tasks?: TaskListItem[]; // 添加任务数据,用于智能引导 -} - -const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); - -// 计算精确的高亮位置 -const calculateHighlightPosition = (stepIndex: number, hasTasks: boolean) => { - const baseTop = 120; // 状态栏 + 标题区域高度 - const cardHeight = 180; // 任务进度卡片高度 - const filterHeight = 60; // 筛选标签高度 - const listHeight = 300; // 任务列表高度 - - switch (stepIndex) { - case 0: // 欢迎标题 - return { - top: baseTop - 40, - left: 20, - right: 20, - height: 60, - borderRadius: 12, - }; - case 1: // 任务进度卡片 - return { - top: baseTop + 20, - left: 20, - right: 20, - height: cardHeight, - borderRadius: 16, - }; - case 2: // 目标管理按钮(有任务时) - if (hasTasks) { - return { - top: baseTop + 40, - right: 60, - width: 40, - height: 28, - borderRadius: 14, - }; - } else { - return { - top: baseTop + 40, - right: 20, - width: 28, - height: 28, - borderRadius: 14, - }; - } - case 3: // 创建新目标按钮(有任务时) - if (hasTasks) { - return { - top: baseTop + 40, - right: 20, - width: 28, - height: 28, - borderRadius: 14, - }; - } else { - return null; // 没有这一步 - } - case 4: // 任务筛选标签 - return { - top: baseTop + cardHeight + 40, - left: 20, - right: 20, - height: filterHeight, - borderRadius: 24, - }; - case 5: // 任务列表 - return { - top: baseTop + cardHeight + filterHeight + 60, - left: 20, - right: 20, - height: listHeight, - borderRadius: 24, - }; - default: - return null; - } -}; - -export const GoalsPageGuide: React.FC = ({ - visible, - onComplete, - tasks = [], -}) => { - const [currentStep, setCurrentStep] = useState(0); - const fadeAnim = useRef(new Animated.Value(0)).current; - const scaleAnim = useRef(new Animated.Value(0.8)).current; - - // 根据任务数据智能生成引导步骤 - const generateSteps = () => { - const hasTasks = tasks.length > 0; - const hasCompletedTasks = tasks.some(task => task.status === 'completed'); - const hasPendingTasks = tasks.some(task => task.status === 'pending'); - - const baseSteps = [ - { - title: '欢迎来到目标页面', - description: '这里是您的目标管理中心,让我们一起来了解各个功能。', - icon: 'flag', - }, - { - title: '任务进度统计', - description: '这里显示您当天的任务完成情况,包括待完成、已完成和已跳过的任务数量。', - icon: 'analytics', - }, - ]; - - // 根据任务状态添加不同的引导内容 - if (!hasTasks) { - baseSteps.push({ - title: '创建您的第一个目标', - description: '点击加号按钮,创建您的第一个目标,系统会自动生成相应的任务。', - icon: 'add', - }); - } else { - baseSteps.push( - { - title: '目标管理', - description: '点击右上角的目标按钮,可以查看和管理您的所有目标。', - icon: 'flag', - }, - { - title: '创建新目标', - description: '点击加号按钮,可以快速创建新的目标。', - icon: 'add', - } - ); - } - - baseSteps.push({ - title: '任务筛选', - description: '使用这些标签可以筛选查看不同状态的任务。', - icon: 'filter-list', - }); - - // 根据任务状态调整任务列表的引导内容 - if (!hasTasks) { - baseSteps.push({ - title: '任务列表', - description: '创建目标后,您的任务将显示在这里。', - icon: 'list', - }); - } else if (!hasPendingTasks && hasCompletedTasks) { - baseSteps.push({ - title: '任务列表', - description: '您已完成所有任务!可以创建新目标或查看历史记录。', - icon: 'check-circle', - }); - } else { - baseSteps.push({ - title: '任务列表', - description: '这里显示您的所有任务,可以标记完成或跳过。', - icon: 'list', - }); - } - - return baseSteps; - }; - - const steps = generateSteps(); - const hasTasks = tasks.length > 0; - const currentHighlightPosition = calculateHighlightPosition(currentStep, hasTasks); - - useEffect(() => { - if (visible) { - Animated.parallel([ - Animated.timing(fadeAnim, { - toValue: 1, - duration: 300, - useNativeDriver: true, - }), - Animated.timing(scaleAnim, { - toValue: 1, - duration: 300, - useNativeDriver: true, - }), - ]).start(); - } else { - Animated.parallel([ - Animated.timing(fadeAnim, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(scaleAnim, { - toValue: 0.8, - duration: 200, - useNativeDriver: true, - }), - ]).start(); - } - }, [visible, fadeAnim, scaleAnim]); - - const handleNext = () => { - if (currentStep < steps.length - 1) { - setCurrentStep(currentStep + 1); - } else { - handleComplete(); - } - }; - - const handlePrevious = () => { - if (currentStep > 0) { - setCurrentStep(currentStep - 1); - } - }; - - const handleComplete = () => { - Animated.parallel([ - Animated.timing(fadeAnim, { - toValue: 0, - duration: 200, - useNativeDriver: true, - }), - Animated.timing(scaleAnim, { - toValue: 0.8, - duration: 200, - useNativeDriver: true, - }), - ]).start(() => { - setCurrentStep(0); - onComplete(); - }); - }; - - const handleSkip = () => { - handleComplete(); - }; - - if (!visible || !currentHighlightPosition) return null; - - const currentStepData = steps[currentStep]; - - return ( - - - - {/* 背景遮罩 */} - - {/* 高亮区域 */} - - - - - {/* 引导内容 */} - - {/* 步骤指示器 */} - - {steps.map((_, index) => ( - - ))} - - - {/* 图标 */} - - - - - {/* 标题 */} - {currentStepData.title} - - {/* 描述 */} - {currentStepData.description} - - {/* 按钮区域 */} - - - 跳过 - - - - {currentStep > 0 && ( - - 回顾 - - )} - - - - {currentStep === steps.length - 1 ? '完成' : '下一步'} - - - - - - - - ); -}; - -const styles = StyleSheet.create({ - overlay: { - flex: 1, - backgroundColor: 'rgba(0, 0, 0, 0.8)', - justifyContent: 'center', - alignItems: 'center', - }, - highlightArea: { - position: 'absolute', - justifyContent: 'center', - alignItems: 'center', - }, - highlightBorder: { - width: '100%', - height: '100%', - borderWidth: 2, - borderColor: '#7A5AF8', - backgroundColor: 'rgba(122, 90, 248, 0.08)', - shadowColor: '#7A5AF8', - shadowOffset: { width: 0, height: 0 }, - shadowOpacity: 0.3, - shadowRadius: 8, - elevation: 4, - }, - guideContainer: { - position: 'absolute', - bottom: 120, - left: 20, - right: 20, - backgroundColor: '#FFFFFF', - borderRadius: 20, - padding: 24, - alignItems: 'center', - shadowColor: '#000', - shadowOffset: { - width: 0, - height: 4, - }, - shadowOpacity: 0.25, - shadowRadius: 12, - elevation: 8, - }, - stepIndicator: { - flexDirection: 'row', - marginBottom: 20, - }, - stepDot: { - width: 8, - height: 8, - borderRadius: 4, - backgroundColor: '#E5E7EB', - marginHorizontal: 4, - }, - stepDotActive: { - backgroundColor: '#7A5AF8', - }, - iconContainer: { - width: 80, - height: 80, - borderRadius: 40, - backgroundColor: '#F3F4F6', - justifyContent: 'center', - alignItems: 'center', - marginBottom: 16, - }, - title: { - fontSize: 20, - fontWeight: '700', - color: '#1F2937', - textAlign: 'center', - marginBottom: 12, - }, - description: { - fontSize: 16, - color: '#6B7280', - textAlign: 'center', - lineHeight: 24, - marginBottom: 24, - }, - buttonContainer: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - width: '100%', - }, - navigationButtons: { - flexDirection: 'row', - gap: 12, - }, - skipButton: { - paddingHorizontal: 20, - paddingVertical: 12, - borderRadius: 12, - borderWidth: 1, - borderColor: '#E5E7EB', - }, - skipButtonText: { - fontSize: 16, - fontWeight: '600', - color: '#6B7280', - }, - previousButton: { - paddingHorizontal: 20, - paddingVertical: 12, - borderRadius: 12, - borderWidth: 1, - borderColor: '#7A5AF8', - backgroundColor: 'rgba(122, 90, 248, 0.1)', - }, - previousButtonText: { - fontSize: 16, - fontWeight: '600', - color: '#7A5AF8', - }, - nextButton: { - paddingHorizontal: 24, - paddingVertical: 12, - borderRadius: 12, - backgroundColor: '#7A5AF8', - }, - nextButtonText: { - fontSize: 16, - fontWeight: '600', - color: '#FFFFFF', - }, -}); diff --git a/components/NotificationTest.tsx b/components/NotificationTest.tsx index efd888c..eae3b1f 100644 --- a/components/NotificationTest.tsx +++ b/components/NotificationTest.tsx @@ -1,16 +1,14 @@ import React, { useState } from 'react'; import { - View, - Text, - TouchableOpacity, - StyleSheet, Alert, ScrollView, + StyleSheet, + TouchableOpacity, + View } from 'react-native'; import { useNotifications } from '../hooks/useNotifications'; import { ThemedText } from './ThemedText'; import { ThemedView } from './ThemedView'; -import { DailySummaryTest } from './DailySummaryTest'; export const NotificationTest: React.FC = () => { const { @@ -23,9 +21,7 @@ export const NotificationTest: React.FC = () => { cancelAllNotifications, getAllScheduledNotifications, sendWorkoutReminder, - sendGoalAchievement, sendMoodCheckinReminder, - debugNotificationStatus, } = useNotifications(); const [scheduledNotifications, setScheduledNotifications] = useState([]); @@ -97,15 +93,6 @@ export const NotificationTest: React.FC = () => { } }; - const handleSendGoalAchievement = async () => { - try { - await sendGoalAchievement('目标达成', '恭喜您完成了本周的运动目标!'); - Alert.alert('成功', '目标达成通知已发送'); - } catch (error) { - Alert.alert('错误', '发送目标达成通知失败'); - } - }; - const handleSendMoodCheckinReminder = async () => { try { await sendMoodCheckinReminder('心情打卡', '记得记录今天的心情状态哦'); @@ -134,20 +121,11 @@ export const NotificationTest: React.FC = () => { } }; - const handleDebugNotificationStatus = async () => { - try { - await debugNotificationStatus(); - Alert.alert('调试完成', '请查看控制台输出'); - } catch (error) { - Alert.alert('错误', '调试失败'); - } - }; - return ( 推送通知测试 - + 初始化状态: {isInitialized ? '已初始化' : '未初始化'} @@ -193,13 +171,6 @@ export const NotificationTest: React.FC = () => { 发送运动提醒 - - 发送目标达成通知 - - { 获取已安排通知 - - 调试通知状态 - - { ))} )} - - {/* 每日总结推送测试 */} - ); diff --git a/components/TaskCard.tsx b/components/TaskCard.tsx deleted file mode 100644 index 2dcd26c..0000000 --- a/components/TaskCard.tsx +++ /dev/null @@ -1,501 +0,0 @@ -import { useGlobalDialog } from '@/components/ui/DialogProvider'; -import { Colors } from '@/constants/Colors'; -import { useAppDispatch } from '@/hooks/redux'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import { completeTask, skipTask } from '@/store/tasksSlice'; -import { TaskListItem } from '@/types/goals'; -import { useRouter } from 'expo-router'; -import React from 'react'; -import { Alert, Animated, Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; - -interface TaskCardProps { - task: TaskListItem; - onTaskCompleted?: (task: TaskListItem) => void; // 任务完成回调 -} - -export const TaskCard: React.FC = ({ - task, - onTaskCompleted, -}) => { - const theme = useColorScheme() ?? 'light'; - const colorTokens = Colors[theme]; - const dispatch = useAppDispatch(); - const { showConfirm } = useGlobalDialog(); - const router = useRouter(); - - // 创建进度条动画值 - const progressAnimation = React.useRef(new Animated.Value(0)).current; - - // 当任务进度变化时,启动动画 - React.useEffect(() => { - const targetProgress = task.progressPercentage > 0 ? Math.min(task.progressPercentage, 100) : 6; - - Animated.timing(progressAnimation, { - toValue: targetProgress, - duration: 800, // 动画持续时间800毫秒 - useNativeDriver: false, // 因为我们要动画width属性,所以不能使用原生驱动 - }).start(); - }, [task.progressPercentage, progressAnimation]); - - const getStatusText = (status: string) => { - switch (status) { - case 'completed': - return '已完成'; - case 'in_progress': - return '进行中'; - case 'overdue': - return '已过期'; - case 'skipped': - return '已跳过'; - default: - return '待开始'; - } - }; - - const getPriorityColor = (status: string) => { - switch (status) { - case 'overdue': - return '#EF4444'; // High - 过期任务 - case 'in_progress': - return '#F59E0B'; // Medium - 进行中 - case 'completed': - return '#10B981'; // Low - 已完成 - default: - return '#6B7280'; // Default - 待开始 - } - }; - - const getPriorityText = (status: string) => { - switch (status) { - case 'overdue': - return '高'; - case 'in_progress': - return '中'; - case 'completed': - return '低'; - default: - return ''; - } - }; - - const formatDate = (dateString: string) => { - const date = new Date(dateString); - const month = date.toLocaleDateString('zh-CN', { month: 'short' }); - const day = date.getDate(); - return `${day} ${month}`; - }; - - const handleCompleteTask = async () => { - // 如果任务已经完成,不执行任何操作 - if (task.status === 'completed') { - return; - } - - try { - // 调用完成任务 API - await dispatch(completeTask({ - taskId: task.id, - completionData: { - count: 1, - notes: '通过任务卡片完成' - } - })).unwrap(); - - // 触发任务完成回调 - onTaskCompleted?.(task); - - } catch (error) { - Alert.alert('错误', '完成任务失败,请重试'); - } - }; - - const handleSkipTask = async () => { - // 如果任务已经完成或已跳过,不执行任何操作 - if (task.status === 'completed' || task.status === 'skipped') { - return; - } - - // 显示确认弹窗 - showConfirm( - { - title: '确认跳过任务', - message: `确定要跳过任务"${task.title}"吗?\n\n跳过后的任务将不会显示在任务列表中,且无法恢复。`, - confirmText: '跳过', - cancelText: '取消', - destructive: true, - icon: 'warning', - iconColor: '#F59E0B', - }, - async () => { - try { - // 调用跳过任务 API - await dispatch(skipTask({ - taskId: task.id, - skipData: { - reason: '用户主动跳过' - } - })).unwrap(); - } catch (error) { - Alert.alert('错误', '跳过任务失败,请重试'); - } - } - ); - }; - - const handleTaskPress = () => { - router.push(`/task-detail?taskId=${task.id}`); - }; - - const renderActionIcons = () => { - if (task.status === 'completed' || task.status === 'overdue' || task.status === 'skipped') { - return null; - } - - return ( - - {/* 完成任务图标 */} - - - - - {/* 跳过任务图标 - 仅对进行中的任务显示 */} - {task.status === 'pending' && ( - - - - )} - - ); - }; - - - - return ( - - - {/* 左侧图标区域 */} - - - - - - - {/* 右侧信息区域 */} - - {/* 任务标题 */} - - {task.title} - - - {/* 进度条 */} - - {/* 背景进度条 */} - - - {/* 实际进度条 */} - 0 - ? '#8B5CF6' - : '#C7D2FE', // 浅紫色,表示待开始 - }, - ]} - /> - - {/* 进度文字 */} - 20 || task.status === 'completed' - ? '#FFFFFF' - : '#374151', // 进度较少时使用深色文字 - } - ]}> - {task.currentCount}/{task.targetCount} 次 - - - - - {/* 操作按钮 */} - {renderActionIcons()} - - - ); -}; - -const styles = StyleSheet.create({ - container: { - padding: 14, - borderRadius: 30, - marginBottom: 12, - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 4, - elevation: 3, - }, - cardContent: { - flexDirection: 'row', - alignItems: 'center', - gap: 10, - }, - iconSection: { - flexShrink: 0, - }, - iconCircle: { - width: 36, - height: 36, - borderRadius: 18, - backgroundColor: '#F3E8FF', // 浅紫色背景 - alignItems: 'center', - justifyContent: 'center', - }, - infoSection: { - flex: 1, - gap: 8, - }, - title: { - fontSize: 15, - fontWeight: '600', - lineHeight: 20, - color: '#1F2937', // 深蓝紫色文字 - marginBottom: 2, - }, - progressContainer: { - position: 'relative', - height: 14, - justifyContent: 'center', - marginTop: 4, - }, - progressBackground: { - position: 'absolute', - left: 0, - right: 0, - height: 14, - backgroundColor: '#F3F4F6', - borderRadius: 10, - }, - progressBar: { - height: 14, - borderRadius: 10, - position: 'absolute', - left: 0, - minWidth: '6%', // 确保最小宽度可见 - }, - progressText: { - fontSize: 12, - fontWeight: '600', - color: '#FFFFFF', - textAlign: 'center', - position: 'absolute', - left: 0, - right: 0, - zIndex: 1, - }, - actionIconsContainer: { - flexDirection: 'row', - alignItems: 'center', - gap: 6, - flexShrink: 0, - }, - iconContainer: { - width: 28, - height: 28, - borderRadius: 14, - alignItems: 'center', - justifyContent: 'center', - backgroundColor: '#F3F4F6', - }, - skipIconContainer: { - width: 28, - height: 28, - borderRadius: 14, - backgroundColor: '#F3F4F6', - alignItems: 'center', - justifyContent: 'center', - }, - taskIcon: { - width: 18, - height: 18, - }, - // 保留其他样式以备后用 - header: { - marginBottom: 12, - }, - titleSection: { - flexDirection: 'row', - alignItems: 'center', - gap: 12, - }, - tagsContainer: { - flexDirection: 'row', - gap: 8, - marginBottom: 12, - }, - statusTag: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 8, - paddingVertical: 4, - borderRadius: 12, - backgroundColor: '#F3F4F6', - }, - statusTagText: { - fontSize: 12, - fontWeight: '500', - color: '#374151', - }, - priorityTag: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 8, - paddingVertical: 4, - borderRadius: 12, - }, - priorityTagText: { - fontSize: 12, - fontWeight: '500', - color: '#FFFFFF', - }, - progressBarOld: { - height: 6, - backgroundColor: '#F3F4F6', - borderRadius: 3, - marginBottom: 16, - overflow: 'visible', - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.1, - shadowRadius: 2, - elevation: 2, - position: 'relative', - }, - progressFill: { - height: '100%', - borderRadius: 3, - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.2, - shadowRadius: 2, - elevation: 3, - }, - progressGlow: { - position: 'absolute', - right: 0, - top: 0, - width: 8, - height: '100%', - backgroundColor: 'rgba(255, 255, 255, 0.6)', - borderRadius: 3, - }, - progressTextContainer: { - position: 'absolute', - right: 0, - top: -6, - backgroundColor: '#FFFFFF', - paddingHorizontal: 6, - paddingVertical: 2, - borderRadius: 8, - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.1, - shadowRadius: 2, - elevation: 2, - borderWidth: 1, - borderColor: '#E5E7EB', - zIndex: 1, - }, - footer: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - }, - teamSection: { - flexDirection: 'row', - alignItems: 'center', - }, - avatars: { - flexDirection: 'row', - alignItems: 'center', - }, - avatar: { - width: 24, - height: 24, - borderRadius: 24, - marginRight: -8, - borderWidth: 2, - borderColor: '#FFFFFF', - overflow: 'hidden', - }, - avatarImage: { - width: '100%', - height: '100%', - }, - infoTag: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingHorizontal: 8, - paddingVertical: 4, - borderRadius: 12, - }, - infoTagText: { - fontSize: 12, - fontWeight: '500', - color: '#374151', - }, -}); - diff --git a/components/TaskFilterTabs.tsx b/components/TaskFilterTabs.tsx deleted file mode 100644 index 875523a..0000000 --- a/components/TaskFilterTabs.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import React from 'react'; -import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; - -export type TaskFilterType = 'all' | 'pending' | 'completed' | 'skipped'; - -interface TaskFilterTabsProps { - selectedFilter: TaskFilterType; - onFilterChange: (filter: TaskFilterType) => void; - taskCounts: { - all: number; - pending: number; - completed: number; - skipped: number; - }; -} - -export const TaskFilterTabs: React.FC = ({ - selectedFilter, - onFilterChange, - taskCounts, -}) => { - return ( - - - {/* 全部 Tab */} - onFilterChange('all')} - > - - 全部 - - - - {taskCounts.all} - - - - - {/* 待完成 Tab */} - onFilterChange('pending')} - > - - 待完成 - - - - {taskCounts.pending} - - - - - {/* 已完成 Tab */} - onFilterChange('completed')} - > - - 已完成 - - - - {taskCounts.completed} - - - - - {/* 已跳过 Tab */} - onFilterChange('skipped')} - > - - 已跳过 - - - - {taskCounts.skipped} - - - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - paddingHorizontal: 20, - }, - tabContainer: { - backgroundColor: '#FFFFFF', - borderRadius: 24, - padding: 4, - flexDirection: 'row', - shadowColor: '#000', - shadowOffset: { width: 0, height: 1 }, - shadowOpacity: 0.05, - shadowRadius: 2, - elevation: 1, - borderWidth: 1, - borderColor: '#E5E7EB', - }, - tab: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 10, - paddingHorizontal: 12, - borderRadius: 20, - gap: 6, - }, - activeTab: { - backgroundColor: '#7A5AF8', - shadowColor: '#7A5AF8', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.2, - shadowRadius: 4, - elevation: 3, - }, - tabText: { - fontSize: 14, - fontWeight: '500', - color: '#374151', - }, - activeTabText: { - color: '#FFFFFF', - fontWeight: '600', - }, - badge: { - minWidth: 20, - height: 20, - borderRadius: 10, - alignItems: 'center', - justifyContent: 'center', - paddingHorizontal: 6, - }, - inactiveBadge: { - backgroundColor: '#E5E7EB', - }, - activeBadge: { - backgroundColor: '#EF4444', - }, - badgeText: { - fontSize: 12, - fontWeight: '600', - color: '#374151', - }, - activeBadgeText: { - color: '#FFFFFF', - }, -}); diff --git a/components/TaskProgressCard.tsx b/components/TaskProgressCard.tsx deleted file mode 100644 index b6e3a70..0000000 --- a/components/TaskProgressCard.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import { TaskListItem } from '@/types/goals'; -import MaterialIcons from '@expo/vector-icons/MaterialIcons'; -import { Image } from 'expo-image'; -import { useRouter } from 'expo-router'; -import React, { ReactNode } from 'react'; -import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; - -interface TaskProgressCardProps { - tasks: TaskListItem[]; - headerButtons?: ReactNode; -} - -export const TaskProgressCard: React.FC = ({ - tasks, - headerButtons, -}) => { - const router = useRouter(); - - // 计算各状态的任务数量 - const pendingTasks = tasks.filter(task => task.status === 'pending'); - const completedTasks = tasks.filter(task => task.status === 'completed'); - const skippedTasks = tasks.filter(task => task.status === 'skipped'); - - // 处理跳转到目标列表 - const handleNavigateToGoals = () => { - router.push('/goals-list'); - }; - - return ( - - {/* 标题区域 */} - - - 今日 - - - - - - - {headerButtons && ( - - {headerButtons} - - )} - - - - {/* 状态卡片区域 */} - - {/* 待完成 卡片 */} - - - - 待完成 - - {pendingTasks.length} - - - {/* 已完成 卡片 */} - - - - 已完成 - - {completedTasks.length} - - - {/* 已跳过 卡片 */} - - - - 已跳过 - - {skippedTasks.length} - - - - ); -}; - -const styles = StyleSheet.create({ - container: { - backgroundColor: '#FFFFFF', - borderRadius: 16, - padding: 20, - marginHorizontal: 20, - marginBottom: 20, - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.1, - shadowRadius: 8, - elevation: 4, - }, - header: { - marginBottom: 20, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - }, - titleContainer: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - gap: 4, - }, - headerButtons: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }, - headerActions: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - }, - goalsIconButton: { - width: 18, - height: 18, - }, - title: { - fontSize: 20, - fontWeight: '700', - lineHeight: 24, - height: 24, - color: '#1F2937', - marginBottom: 4, - }, - subtitle: { - fontSize: 14, - color: '#6B7280', - fontWeight: '400', - }, - statusCards: { - flexDirection: 'row', - justifyContent: 'space-between', - gap: 8, - }, - statusCard: { - flex: 1, - backgroundColor: '#FFFFFF', - borderRadius: 12, - padding: 12, - borderWidth: 1, - borderColor: '#E5E7EB', - alignItems: 'flex-start', - minHeight: 80, - }, - cardHeader: { - flexDirection: 'row', - alignItems: 'center', - marginBottom: 8, - gap: 6, - flexWrap: 'wrap', - }, - cardLabel: { - fontSize: 11, - fontWeight: '500', - color: '#1F2937', - lineHeight: 14, - }, - cardCount: { - fontSize: 24, - fontWeight: '700', - color: '#1F2937', - }, -}); diff --git a/components/model/CreateGoalModal.tsx b/components/model/CreateGoalModal.tsx deleted file mode 100644 index 66bedfb..0000000 --- a/components/model/CreateGoalModal.tsx +++ /dev/null @@ -1,1107 +0,0 @@ -import { Colors } from '@/constants/Colors'; -import { useColorScheme } from '@/hooks/useColorScheme'; -import { CreateGoalRequest, GoalPriority, RepeatType, UpdateGoalRequest } from '@/types/goals'; -import { Ionicons } from '@expo/vector-icons'; -import DateTimePicker from '@react-native-community/datetimepicker'; -import { LinearGradient } from 'expo-linear-gradient'; -import React, { useEffect, useState } from 'react'; -import { - Alert, - Image, - Modal, - Platform, - ScrollView, - StyleSheet, - Switch, - Text, - TextInput, - TouchableOpacity, - View, -} from 'react-native'; -import WheelPickerExpo from 'react-native-wheel-picker-expo'; - -interface CreateGoalModalProps { - visible: boolean; - onClose: () => void; - onSubmit: (goalData: CreateGoalRequest) => void; - onUpdate?: (goalId: string, goalData: UpdateGoalRequest) => void; - onSuccess?: () => void; - loading?: boolean; - initialData?: Partial; - editGoalId?: string; -} - -const REPEAT_TYPE_OPTIONS: { value: RepeatType; label: string }[] = [ - { value: 'daily', label: '每日' }, - { value: 'weekly', label: '每周' }, - { value: 'monthly', label: '每月' }, -]; - -const FREQUENCY_OPTIONS = Array.from({ length: 30 }, (_, i) => i + 1); - -export const CreateGoalModal: React.FC = ({ - visible, - onClose, - onSubmit, - onUpdate, - onSuccess, - loading = false, - initialData, - editGoalId, -}) => { - const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; - const colorTokens = Colors[theme]; - - // 表单状态 - const [title, setTitle] = useState(initialData?.title || ''); - const [description, setDescription] = useState(initialData?.description || ''); - const [repeatType, setRepeatType] = useState(initialData?.repeatType || 'daily'); - const [frequency, setFrequency] = useState(initialData?.frequency || 1); - const [hasReminder, setHasReminder] = useState(initialData?.hasReminder || false); - const [showFrequencyPicker, setShowFrequencyPicker] = useState(false); - const [showRepeatTypePicker, setShowRepeatTypePicker] = useState(false); - const [reminderTime, setReminderTime] = useState(initialData?.reminderTime || '20:00'); - const [category, setCategory] = useState(initialData?.category || ''); - const [priority, setPriority] = useState(initialData?.priority || 5); - const [showTimePicker, setShowTimePicker] = useState(false); - const [tempSelectedTime, setTempSelectedTime] = useState(null); - - // 周几选择状态 - const [selectedWeekdays, setSelectedWeekdays] = useState( - initialData?.customRepeatRule?.weekdays || [1, 2, 3, 4, 5] - ); // 默认周一到周五 - // 每月日期选择状态 - const [selectedMonthDays, setSelectedMonthDays] = useState( - initialData?.customRepeatRule?.dayOfMonth || [1, 15] - ); // 默认1号和15号 - - // 结束日期选择状态 - const [endDate, setEndDate] = useState(initialData?.endDate || null); - const [showDatePicker, setShowDatePicker] = useState(false); - const [tempSelectedDate, setTempSelectedDate] = useState(null); - - // 当 initialData 变化时更新表单状态 - useEffect(() => { - if (initialData) { - setTitle(initialData.title || ''); - setDescription(initialData.description || ''); - setRepeatType(initialData.repeatType || 'daily'); - setFrequency(initialData.frequency || 1); - setHasReminder(initialData.hasReminder || false); - setReminderTime(initialData.reminderTime || '20:00'); - setCategory(initialData.category || ''); - setPriority(initialData.priority || 5); - setSelectedWeekdays(initialData.customRepeatRule?.weekdays || [1, 2, 3, 4, 5]); - setSelectedMonthDays(initialData.customRepeatRule?.dayOfMonth || [1, 15]); - setEndDate(initialData.endDate || null); - } - }, [initialData]); - - // 重置表单 - const resetForm = () => { - setTitle(''); - setDescription(''); - setRepeatType('daily'); - setFrequency(1); - setHasReminder(false); - setReminderTime('20:00'); - setCategory(''); - setPriority(5); - setSelectedWeekdays([1, 2, 3, 4, 5]); - setSelectedMonthDays([1, 15]); - setEndDate(null); - }; - - // 处理关闭 - const handleClose = () => { - if (!loading) { - resetForm(); - onClose(); - } - }; - - // 处理提交 - const handleSubmit = () => { - if (!title.trim()) { - Alert.alert('提示', '请输入目标标题'); - return; - } - - // 计算startTime:从reminderTime中获取小时和分钟,转换为当天的分钟数 - let startTime: number | undefined; - if (reminderTime) { - const [hours, minutes] = reminderTime.split(':').map(Number); - startTime = hours * 60 + minutes; - } - - // 根据是否是编辑模式决定数据结构 - if (editGoalId && onUpdate) { - // 更新模式:使用 UpdateGoalRequest 结构 - const updateData: UpdateGoalRequest = { - title: title.trim(), - description: description.trim() || undefined, - repeatType, - frequency, - category: category.trim() || undefined, - priority, - hasReminder, - reminderTime: hasReminder ? reminderTime : undefined, - customRepeatRule: { - weekdays: repeatType === 'weekly' ? selectedWeekdays : [1, 2, 3, 4, 5, 6, 0], - dayOfMonth: repeatType === 'monthly' ? selectedMonthDays : undefined, - }, - endDate: endDate || undefined, - }; - - console.log('updateData', updateData); - onUpdate(editGoalId, updateData); - } else { - // 创建模式:使用 CreateGoalRequest 结构 - const goalData: CreateGoalRequest = { - title: title.trim(), - description: description.trim() || undefined, - repeatType, - frequency, - category: category.trim() || undefined, - priority, - hasReminder, - reminderTime: hasReminder ? reminderTime : undefined, - customRepeatRule: { - weekdays: repeatType === 'weekly' ? selectedWeekdays : [1, 2, 3, 4, 5, 6, 0], - dayOfMonth: repeatType === 'monthly' ? selectedMonthDays : undefined, - }, - startTime, - endDate: endDate || undefined, - }; - - console.log('goalData', goalData); - onSubmit(goalData); - } - - // 通知父组件提交成功 - if (onSuccess) { - onSuccess(); - } - }; - - // 时间选择器 - const handleTimeChange = (event: any, selectedDate?: Date) => { - if (Platform.OS === 'android') { - // Android: 用户点击系统确认按钮后自动关闭 - if (event.type === 'set' && selectedDate) { - const hours = selectedDate.getHours().toString().padStart(2, '0'); - const minutes = selectedDate.getMinutes().toString().padStart(2, '0'); - setReminderTime(`${hours}:${minutes}`); - } - setShowTimePicker(false); - } else { - // iOS: 只在用户点击自定义确认按钮时更新 - if (selectedDate) { - setTempSelectedTime(selectedDate); - } - } - }; - - const handleConfirmTime = () => { - setShowTimePicker(false); - if (tempSelectedTime) { - const hours = tempSelectedTime.getHours().toString().padStart(2, '0'); - const minutes = tempSelectedTime.getMinutes().toString().padStart(2, '0'); - setReminderTime(`${hours}:${minutes}`); - } - setTempSelectedTime(null); - }; - - const handleCancelTime = () => { - setShowTimePicker(false); - setTempSelectedTime(null); - }; - - const showTimePickerModal = () => { - setShowTimePicker(true); - }; - - // 获取当前时间对应的Date对象 - const getCurrentTimeDate = () => { - const [hours, minutes] = reminderTime.split(':').map(Number); - const date = new Date(); - date.setHours(hours, minutes, 0, 0); - return date; - }; - - // 日期选择器处理 - const handleDateChange = (event: any, selectedDate?: Date) => { - if (Platform.OS === 'android') { - if (event.type === 'set' && selectedDate) { - const isoDate = selectedDate.toISOString().split('T')[0]; - setEndDate(isoDate); - } - setShowDatePicker(false); - } else { - if (selectedDate) { - setTempSelectedDate(selectedDate); - } - } - }; - - const handleConfirmDate = () => { - setShowDatePicker(false); - if (tempSelectedDate) { - const isoDate = tempSelectedDate.toISOString().split('T')[0]; - setEndDate(isoDate); - } - setTempSelectedDate(null); - }; - - const handleCancelDate = () => { - setShowDatePicker(false); - setTempSelectedDate(null); - }; - - const showDatePickerModal = () => { - setShowDatePicker(true); - }; - - // 获取当前结束日期对应的Date对象 - const getCurrentEndDate = () => { - if (endDate) { - return new Date(endDate + 'T00:00:00'); - } - const tomorrow = new Date(); - tomorrow.setDate(tomorrow.getDate() + 1); - return tomorrow; - }; - - // 格式化显示日期 - const formatDisplayDate = (dateString: string) => { - const date = new Date(dateString + 'T00:00:00'); - return `${date.getFullYear()}年${(date.getMonth() + 1).toString().padStart(2, '0')}月${date.getDate().toString().padStart(2, '0')}日`; - }; - - return ( - - - {/* 渐变背景 */} - - - {/* 装饰性圆圈 */} - - - {/* 头部 */} - - - - - - {editGoalId ? '编辑目标' : '创建新目标'} - - - - - - {/* 目标标题输入 */} - - - {/* - 图标 - */} - - - {/* 装饰图案 */} - - - - - - {/* 目标重复周期 */} - - setShowRepeatTypePicker(true)}> - - - - - - 重复周期 - - - {repeatType === 'weekly' && selectedWeekdays.length > 0 - ? selectedWeekdays.length <= 3 - ? `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedWeekdays.map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(' ')}` - : `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedWeekdays.slice(0, 2).map(day => ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][day]).join(' ')}等${selectedWeekdays.length}天` - : repeatType === 'monthly' && selectedMonthDays.length > 0 - ? selectedMonthDays.length <= 3 - ? `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedMonthDays.map(day => `${day}号`).join(' ')}` - : `${REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label} ${selectedMonthDays.slice(0, 2).map(day => `${day}号`).join(' ')}等${selectedMonthDays.length}天` - : REPEAT_TYPE_OPTIONS.find(opt => opt.value === repeatType)?.label - } - - - › - - - - - - {/* 重复周期选择器弹窗 */} - setShowRepeatTypePicker(false)} - > - setShowRepeatTypePicker(false)} - /> - - {/* 关闭按钮 */} - setShowRepeatTypePicker(false)} - > - × - - - {/* 标题 */} - 目标重复周期 - - {/* 重复类型选择 */} - - {REPEAT_TYPE_OPTIONS.map((option) => ( - setRepeatType(option.value)} - > - - {option.label} - - - ))} - - - {/* 周几选择 - 仅在选择每周时显示 */} - {repeatType === 'weekly' && ( - - - {[ - { value: 0, label: '周日' }, - { value: 1, label: '周一' }, - { value: 2, label: '周二' }, - { value: 3, label: '周三' }, - { value: 4, label: '周四' }, - { value: 5, label: '周五' }, - { value: 6, label: '周六' }, - ].map((weekday) => ( - { - if (selectedWeekdays.includes(weekday.value)) { - setSelectedWeekdays(selectedWeekdays.filter(day => day !== weekday.value)); - } else { - setSelectedWeekdays([...selectedWeekdays, weekday.value]); - } - }} - > - - {weekday.label} - - - ))} - - - )} - - {/* 每月日期选择 - 仅在选择每月时显示 */} - {repeatType === 'monthly' && ( - - - {Array.from({ length: 31 }, (_, i) => i + 1).map((day) => ( - { - if (selectedMonthDays.includes(day)) { - setSelectedMonthDays(selectedMonthDays.filter(d => d !== day)); - } else { - setSelectedMonthDays([...selectedMonthDays, day]); - } - }} - activeOpacity={0.8} - > - - {day} - - - ))} - - - )} - - {/* 完成按钮 */} - setShowRepeatTypePicker(false)} - > - 完成 - - - - - {/* 频率设置 */} - - setShowFrequencyPicker(true)}> - - - - - - - 频率 - - - {frequency} - - - › - - - - - - {/* 频率选择器弹窗 */} - setShowFrequencyPicker(false)} - > - setShowFrequencyPicker(false)} - /> - - - ({ label: num.toString(), value: num }))} - onChange={({ item }) => setFrequency(item.value)} - backgroundColor={colorTokens.card} - // selectedStyle={{ borderColor: colorTokens.primary, borderWidth: 2 }} - haptics - /> - - {Platform.OS === 'ios' && ( - - setShowFrequencyPicker(false)} - > - 取消 - - setShowFrequencyPicker(false)} - > - 确定 - - - )} - - - - {/* 提醒设置 */} - - - - - - - 提醒 - - - - - - {/* 时间设置 */} - - - - - - - 时间 - - - - {reminderTime} - - - › - - - - - - {/* 结束日期设置 */} - - - - - - - 结束日期 - - - - {endDate ? formatDisplayDate(endDate) : '无限制'} - - - › - - - - {endDate && ( - setEndDate(null)} - > - 清除结束日期 - - )} - - - {/* 时间选择器弹窗 */} - setShowTimePicker(false)} - > - - - - {Platform.OS === 'ios' && ( - - - 取消 - - - 确定 - - - )} - - - - {/* 日期选择器弹窗 */} - setShowDatePicker(false)} - > - - - - {Platform.OS === 'ios' && ( - - - 取消 - - - 确定 - - - )} - - - - {/* 描述输入(可选) */} - - - - - - {/* 保存按钮 */} - - - - {loading ? (editGoalId ? '更新中...' : '保存中...') : (editGoalId ? '更新' : '保存')} - - - - - - ); -}; - -const styles = StyleSheet.create({ - gradientBackground: { - position: 'absolute', - left: 0, - right: 0, - top: 0, - bottom: 0, - opacity: 0.6, - }, - decorativeCircle1: { - position: 'absolute', - top: -20, - right: -20, - width: 60, - height: 60, - borderRadius: 30, - backgroundColor: '#0EA5E9', - opacity: 0.1, - }, - decorativeCircle2: { - position: 'absolute', - bottom: -15, - left: -15, - width: 40, - height: 40, - borderRadius: 20, - backgroundColor: '#0EA5E9', - opacity: 0.05, - }, - container: { - flex: 1, - }, - header: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingHorizontal: 20, - paddingTop: 20, - paddingBottom: 20, - }, - cancelButton: { - fontSize: 24, - fontWeight: '600', - }, - title: { - fontSize: 18, - fontWeight: '600', - }, - content: { - flex: 1, - paddingHorizontal: 20, - }, - section: { - }, - iconTitleContainer: { - flexDirection: 'row', - alignItems: 'flex-start', - backgroundColor: '#FFFFFF', - borderRadius: 16, - padding: 16, - }, - iconPlaceholder: { - width: 60, - height: 60, - borderRadius: 30, - backgroundColor: '#F3F4F6', - alignItems: 'center', - justifyContent: 'center', - marginRight: 16, - }, - iconText: { - fontSize: 12, - color: '#9CA3AF', - fontWeight: '500', - }, - titleInput: { - flex: 1, - fontSize: 16, - fontWeight: '500', - minHeight: 60, - textAlignVertical: 'top', - }, - decorationContainer: { - alignItems: 'flex-end', - paddingRight: 20, - }, - decoration: { - width: 80, - height: 60, - backgroundColor: '#E0E7FF', - borderRadius: 40, - opacity: 0.6, - }, - optionCard: { - borderRadius: 16, - marginBottom: 12, - overflow: 'hidden', - }, - optionHeader: { - flexDirection: 'row', - alignItems: 'center', - padding: 16, - }, - optionIcon: { - width: 32, - height: 32, - borderRadius: 16, - backgroundColor: '#F3F4F6', - alignItems: 'center', - justifyContent: 'center', - marginRight: 12, - }, - optionIconText: { - fontSize: 16, - }, - optionIconImage: { - width: 20, - height: 20, - resizeMode: 'contain', - }, - optionLabel: { - flex: 1, - fontSize: 16, - fontWeight: '500', - }, - optionValue: { - flexDirection: 'row', - alignItems: 'center', - }, - optionValueText: { - fontSize: 16, - fontWeight: '500', - marginRight: 8, - }, - chevron: { - fontSize: 20, - fontWeight: '300', - }, - descriptionInput: { - padding: 16, - fontSize: 16, - minHeight: 80, - textAlignVertical: 'top', - }, - footer: { - padding: 20, - paddingBottom: 40, - }, - saveButton: { - backgroundColor: '#6366F1', - borderRadius: 16, - paddingVertical: 16, - alignItems: 'center', - }, - saveButtonText: { - color: '#FFFFFF', - fontSize: 18, - fontWeight: '600', - }, - modalBackdrop: { - ...StyleSheet.absoluteFillObject, - backgroundColor: 'rgba(0,0,0,0.35)', - }, - modalSheet: { - position: 'absolute', - left: 0, - right: 0, - bottom: 0, - padding: 16, - backgroundColor: '#FFFFFF', - justifyContent: 'center', - alignItems: 'center', - borderTopLeftRadius: 16, - borderTopRightRadius: 16, - }, - modalActions: { - flexDirection: 'row', - justifyContent: 'flex-end', - marginTop: 8, - gap: 12, - }, - modalBtn: { - paddingHorizontal: 14, - paddingVertical: 10, - borderRadius: 10, - backgroundColor: '#F1F5F9', - }, - modalBtnPrimary: { - backgroundColor: '#6366F1', - }, - modalBtnText: { - color: '#334155', - fontWeight: '700', - }, - modalBtnTextPrimary: { - color: '#FFFFFF', - fontWeight: '700', - }, - // 重复类型选择器弹窗样式 - repeatTypeModalSheet: { - position: 'absolute', - left: 20, - right: 20, - top: '50%', - transform: [{ translateY: -300 }], - backgroundColor: '#FFFFFF', - borderRadius: 16, - padding: 24, - alignItems: 'center', - maxHeight: 500, - }, - modalCloseButton: { - position: 'absolute', - top: 16, - left: 16, - width: 24, - height: 24, - alignItems: 'center', - justifyContent: 'center', - }, - modalCloseButtonText: { - fontSize: 20, - color: '#666666', - fontWeight: '300', - }, - repeatTypeModalTitle: { - fontSize: 18, - fontWeight: '600', - color: '#333333', - marginBottom: 20, - textAlign: 'center', - }, - repeatTypeOptions: { - flexDirection: 'row', - flexWrap: 'wrap', - justifyContent: 'center', - gap: 8, - marginBottom: 20, - }, - repeatTypeButton: { - paddingHorizontal: 16, - paddingVertical: 10, - borderRadius: 20, - backgroundColor: '#F5F5F5', - borderWidth: 1, - borderColor: '#E5E5E5', - marginHorizontal: 4, - }, - repeatTypeButtonSelected: { - backgroundColor: '#E6E6FA', - borderColor: '#8A2BE2', - }, - repeatTypeButtonText: { - fontSize: 14, - color: '#666666', - fontWeight: '500', - }, - repeatTypeButtonTextSelected: { - color: '#8A2BE2', - fontWeight: '600', - }, - weekdaySelection: { - width: '100%', - marginBottom: 20, - }, - weekdayOptions: { - flexDirection: 'row', - flexWrap: 'wrap', - justifyContent: 'center', - gap: 6, - }, - weekdayButton: { - paddingHorizontal: 12, - paddingVertical: 8, - borderRadius: 16, - backgroundColor: '#F5F5F5', - borderWidth: 1, - borderColor: '#E5E5E5', - marginHorizontal: 2, - }, - weekdayButtonSelected: { - backgroundColor: '#8A2BE2', - borderColor: '#8A2BE2', - }, - weekdayButtonText: { - fontSize: 12, - color: '#666666', - fontWeight: '500', - }, - weekdayButtonTextSelected: { - color: '#FFFFFF', - fontWeight: '600', - }, - // 每月日期选择样式 - 日历网格布局 - monthDaySelection: { - width: '100%', - marginBottom: 20, - }, - monthDayGrid: { - flexDirection: 'row', - flexWrap: 'wrap', - justifyContent: 'flex-start', - paddingHorizontal: 8, - }, - monthDayGridItem: { - width: 36, - height: 36, - borderRadius: 18, - backgroundColor: '#F5F5F5', - alignItems: 'center', - justifyContent: 'center', - marginBottom: 10, - marginRight: 8, - }, - monthDayGridItemSelected: { - backgroundColor: '#8A2BE2', - }, - monthDayGridText: { - fontSize: 12, - fontWeight: '600', - color: '#666666', - }, - monthDayGridTextSelected: { - color: '#FFFFFF', - }, - repeatTypeCompleteButton: { - width: '100%', - backgroundColor: '#8A2BE2', - borderRadius: 20, - paddingVertical: 14, - alignItems: 'center', - marginTop: 10, - }, - repeatTypeCompleteButtonText: { - color: '#FFFFFF', - fontSize: 16, - fontWeight: '600', - }, - // 清除结束日期按钮样式 - clearEndDateButton: { - paddingHorizontal: 16, - paddingVertical: 8, - alignItems: 'center', - borderTopWidth: 1, - borderTopColor: '#F1F5F9', - }, - clearEndDateText: { - color: '#EF4444', - fontSize: 14, - fontWeight: '500', - }, -}); - -export default CreateGoalModal; \ No newline at end of file diff --git a/constants/Routes.ts b/constants/Routes.ts index 837b76f..5a244d4 100644 --- a/constants/Routes.ts +++ b/constants/Routes.ts @@ -3,7 +3,6 @@ export const ROUTES = { // Tab路由 TAB_EXPLORE: '/explore', TAB_COACH: '/coach', - TAB_GOALS: '/goals', TAB_STATISTICS: '/statistics', TAB_CHALLENGES: '/challenges', TAB_PERSONAL: '/personal', @@ -30,7 +29,6 @@ export const ROUTES = { // 用户相关路由 AUTH_LOGIN: '/auth/login', PROFILE_EDIT: '/profile/edit', - PROFILE_GOALS: '/profile/goals', // 法律相关路由 LEGAL_USER_AGREEMENT: '/legal/user-agreement', @@ -59,8 +57,6 @@ export const ROUTES = { // 轻断食相关 FASTING_PLAN_DETAIL: '/fasting', - // 任务相关路由 - TASK_DETAIL: '/task-detail', // 目标管理路由 (已移至tab中) // GOAL_MANAGEMENT: '/goal-management', @@ -85,8 +81,7 @@ export const ROUTE_PARAMS = { // 文章参数 ARTICLE_ID: 'id', - // 任务参数 - TASK_ID: 'taskId', + // 断食计划参数 FASTING_PLAN_ID: 'planId', // 重定向参数 diff --git a/constants/goalTemplates.ts b/constants/goalTemplates.ts deleted file mode 100644 index cc8ca22..0000000 --- a/constants/goalTemplates.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { CreateGoalRequest } from '@/types/goals'; - -export interface GoalTemplate { - id: string; - title: string; - icon: string; - iconColor: string; - backgroundColor: string; - category: 'recommended' | 'health' | 'lifestyle' | 'exercise'; - data: Partial; - isRecommended?: boolean; -} - -export interface GoalCategory { - id: string; - title: string; - icon?: string; - isRecommended?: boolean; -} - -export const goalTemplates: GoalTemplate[] = [ - // 改善睡眠分类的模板 - { - id: 'afternoon-nap', - title: '睡一会午觉', - icon: 'hotel', - iconColor: '#22D3EE', - backgroundColor: '#E0F2FE', - category: 'health', - data: { - title: '午休时间', - description: '每天午休30分钟,恢复精力', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '13:00', - }, - isRecommended: true - }, - { - id: 'regular-bedtime', - title: '规律作息', - icon: 'access-time', - iconColor: '#8B5CF6', - backgroundColor: '#F3E8FF', - category: 'health', - data: { - title: '保持规律作息', - description: '每天固定时间睡觉起床,建立健康的生物钟', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '22:30', - }, - isRecommended: true - }, - - // 生活习惯分类的模板 - { - id: 'eat-breakfast', - title: '坚持吃早餐', - icon: 'restaurant', - iconColor: '#F97316', - backgroundColor: '#FFF7ED', - category: 'lifestyle', - data: { - title: '坚持吃早餐', - description: '每天按时吃早餐,保持营养均衡', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '07:30', - }, - isRecommended: true - }, - { - id: 'drink-water', - title: '喝八杯水', - icon: 'local-drink', - iconColor: '#06B6D4', - backgroundColor: '#E0F2FE', - category: 'lifestyle', - data: { - title: '每日饮水目标', - description: '每天喝足够的水,保持身体水分', - repeatType: 'daily', - frequency: 8, - hasReminder: true, - reminderTime: '09:00', - }, - isRecommended: true - }, - { - id: 'read-book', - title: '看一本新书', - icon: 'book', - iconColor: '#8B5CF6', - backgroundColor: '#F3E8FF', - category: 'lifestyle', - data: { - title: '阅读新书', - description: '每天阅读30分钟,丰富知识', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '20:00', - } - }, - { - id: 'housework', - title: '做一会家务', - icon: 'home', - iconColor: '#F97316', - backgroundColor: '#FFF7ED', - category: 'lifestyle', - data: { - title: '日常家务', - description: '每天做一些家务,保持家居整洁', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '19:00', - } - }, - { - id: 'mindfulness', - title: '练习一次正念', - icon: 'self-improvement', - iconColor: '#10B981', - backgroundColor: '#ECFDF5', - category: 'lifestyle', - data: { - title: '正念练习', - description: '每天练习10分钟正念冥想', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '21:00', - }, - isRecommended: true - }, - - // 运动锻炼分类的模板 - { - id: 'exercise-duration', - title: '锻炼时长达标', - icon: 'timer', - iconColor: '#7C3AED', - backgroundColor: '#F3E8FF', - category: 'exercise', - data: { - title: '每日锻炼时长', - description: '每天至少锻炼30分钟', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '17:00', - } - }, - { - id: 'morning-run', - title: '晨跑', - icon: 'directions-run', - iconColor: '#EF4444', - backgroundColor: '#FEF2F2', - category: 'exercise', - data: { - title: '每日晨跑', - description: '每天早上跑步30分钟,保持活力', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '06:30', - } - }, - { - id: 'yoga-practice', - title: '瑜伽练习', - icon: 'self-improvement', - iconColor: '#10B981', - backgroundColor: '#ECFDF5', - category: 'exercise', - data: { - title: '每日瑜伽', - description: '每天练习瑜伽,提升身体柔韧性', - repeatType: 'daily', - frequency: 1, - hasReminder: true, - reminderTime: '19:30', - } - }, -]; - -// 分类定义 -export const goalCategories: GoalCategory[] = [ - { - id: 'recommended', - title: '推荐', - isRecommended: true - }, - { - id: 'health', - title: '改善睡眠' - }, - { - id: 'lifestyle', - title: '生活习惯' - }, - { - id: 'exercise', - title: '运动锻炼' - } -]; - -// 按类别分组的模板 -export const getTemplatesByCategory = (category: string) => { - if (category === 'recommended') { - // 推荐分类显示所有分类中的精选模板 - return goalTemplates.filter(template => template.isRecommended); - } - return goalTemplates.filter(template => template.category === category); -}; - -// 获取所有分类 -export const getAllCategories = () => { - return goalCategories; -}; \ No newline at end of file diff --git a/hooks/useNotifications.ts b/hooks/useNotifications.ts index 06ab112..ec66b6c 100644 --- a/hooks/useNotifications.ts +++ b/hooks/useNotifications.ts @@ -1,6 +1,6 @@ -import { useEffect, useState, useCallback } from 'react'; -import { notificationService, NotificationData, NotificationTypes } from '../services/notifications'; import * as Notifications from 'expo-notifications'; +import { useCallback, useEffect, useState } from 'react'; +import { NotificationData, notificationService, NotificationTypes } from '../services/notifications'; export interface UseNotificationsReturn { isInitialized: boolean; @@ -25,9 +25,7 @@ export interface UseNotificationsReturn { cancelAllNotifications: () => Promise; getAllScheduledNotifications: () => Promise; sendWorkoutReminder: (title: string, body: string, date?: Date) => Promise; - sendGoalAchievement: (title: string, body: string) => Promise; sendMoodCheckinReminder: (title: string, body: string, date?: Date) => Promise; - debugNotificationStatus: () => Promise; } export const useNotifications = (): UseNotificationsReturn => { @@ -99,7 +97,7 @@ export const useNotifications = (): UseNotificationsReturn => { sound: true, priority: 'high', }; - + if (date) { return notificationService.scheduleNotificationAtDate(notification, date); } else { @@ -107,17 +105,7 @@ export const useNotifications = (): UseNotificationsReturn => { } }, []); - const sendGoalAchievement = useCallback(async (title: string, body: string) => { - const notification: NotificationData = { - title, - body, - data: { type: NotificationTypes.GOAL_ACHIEVEMENT }, - sound: true, - priority: 'high', - }; - - return notificationService.sendImmediateNotification(notification); - }, []); + // sendGoalAchievement 函数已删除,因为目标功能已移除 const sendMoodCheckinReminder = useCallback(async (title: string, body: string, date?: Date) => { const notification: NotificationData = { @@ -127,7 +115,7 @@ export const useNotifications = (): UseNotificationsReturn => { sound: true, priority: 'normal', }; - + if (date) { return notificationService.scheduleNotificationAtDate(notification, date); } else { @@ -135,10 +123,6 @@ export const useNotifications = (): UseNotificationsReturn => { } }, []); - const debugNotificationStatus = useCallback(async () => { - return notificationService.debugNotificationStatus(); - }, []); - // 组件挂载时自动初始化 useEffect(() => { initialize(); @@ -156,8 +140,6 @@ export const useNotifications = (): UseNotificationsReturn => { cancelAllNotifications, getAllScheduledNotifications, sendWorkoutReminder, - sendGoalAchievement, sendMoodCheckinReminder, - debugNotificationStatus, }; }; diff --git a/ios/OutLive/Info.plist b/ios/OutLive/Info.plist index e8edd7f..315ee6e 100644 --- a/ios/OutLive/Info.plist +++ b/ios/OutLive/Info.plist @@ -25,7 +25,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0.20 + 1.0.21 CFBundleSignature ???? CFBundleURLTypes diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 52cd5df..2ab655b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,14 +1,14 @@ PODS: - EXApplication (7.0.7): - ExpoModulesCore - - EXConstants (18.0.9): + - EXConstants (18.0.10): - ExpoModulesCore - EXImageLoader (6.0.0): - ExpoModulesCore - React-Core - EXNotifications (0.32.12): - ExpoModulesCore - - Expo (54.0.13): + - Expo (54.0.21): - ExpoModulesCore - hermes-engine - RCTRequired @@ -49,14 +49,14 @@ PODS: - ExpoModulesCore - ExpoFont (14.0.9): - ExpoModulesCore - - ExpoGlassEffect (0.1.4): + - ExpoGlassEffect (0.1.5): - ExpoModulesCore - ExpoHaptics (15.0.7): - ExpoModulesCore - - ExpoHead (6.0.12): + - ExpoHead (6.0.14): - ExpoModulesCore - RNScreens - - ExpoImage (3.0.9): + - ExpoImage (3.0.10): - ExpoModulesCore - libavif/libdav1d - SDWebImage (~> 5.21.0) @@ -74,7 +74,7 @@ PODS: - ExpoMediaLibrary (18.2.0): - ExpoModulesCore - React-Core - - ExpoModulesCore (3.0.21): + - ExpoModulesCore (3.0.23): - hermes-engine - RCTRequired - RCTTypeSafety @@ -105,19 +105,19 @@ PODS: - ExpoModulesCore - ExpoSymbols (1.0.7): - ExpoModulesCore - - ExpoSystemUI (6.0.7): + - ExpoSystemUI (6.0.8): - ExpoModulesCore - ExpoUI (0.2.0-beta.7): - ExpoModulesCore - ExpoWebBrowser (15.0.8): - ExpoModulesCore - - EXTaskManager (14.0.7): + - EXTaskManager (14.0.8): - ExpoModulesCore - UMAppLoader - - FBLazyVector (0.81.4) - - hermes-engine (0.81.4): - - hermes-engine/Pre-built (= 0.81.4) - - hermes-engine/Pre-built (0.81.4) + - FBLazyVector (0.81.5) + - hermes-engine (0.81.5): + - hermes-engine/Pre-built (= 0.81.5) + - hermes-engine/Pre-built (0.81.5) - libavif/core (0.11.1) - libavif/libdav1d (0.11.1): - libavif/core @@ -161,31 +161,31 @@ PODS: - Yoga - PurchasesHybridCommon (17.10.0): - RevenueCat (= 5.43.0) - - RCTDeprecation (0.81.4) - - RCTRequired (0.81.4) - - RCTTypeSafety (0.81.4): - - FBLazyVector (= 0.81.4) - - RCTRequired (= 0.81.4) - - React-Core (= 0.81.4) - - React (0.81.4): - - React-Core (= 0.81.4) - - React-Core/DevSupport (= 0.81.4) - - React-Core/RCTWebSocket (= 0.81.4) - - React-RCTActionSheet (= 0.81.4) - - React-RCTAnimation (= 0.81.4) - - React-RCTBlob (= 0.81.4) - - React-RCTImage (= 0.81.4) - - React-RCTLinking (= 0.81.4) - - React-RCTNetwork (= 0.81.4) - - React-RCTSettings (= 0.81.4) - - React-RCTText (= 0.81.4) - - React-RCTVibration (= 0.81.4) - - React-callinvoker (0.81.4) - - React-Core (0.81.4): + - RCTDeprecation (0.81.5) + - RCTRequired (0.81.5) + - RCTTypeSafety (0.81.5): + - FBLazyVector (= 0.81.5) + - RCTRequired (= 0.81.5) + - React-Core (= 0.81.5) + - React (0.81.5): + - React-Core (= 0.81.5) + - React-Core/DevSupport (= 0.81.5) + - React-Core/RCTWebSocket (= 0.81.5) + - React-RCTActionSheet (= 0.81.5) + - React-RCTAnimation (= 0.81.5) + - React-RCTBlob (= 0.81.5) + - React-RCTImage (= 0.81.5) + - React-RCTLinking (= 0.81.5) + - React-RCTNetwork (= 0.81.5) + - React-RCTSettings (= 0.81.5) + - React-RCTText (= 0.81.5) + - React-RCTVibration (= 0.81.5) + - React-callinvoker (0.81.5) + - React-Core (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt - - React-Core/Default (= 0.81.4) + - React-Core/Default (= 0.81.5) - React-cxxreact - React-featureflags - React-hermes @@ -200,9 +200,9 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core-prebuilt (0.81.4): + - React-Core-prebuilt (0.81.5): - ReactNativeDependencies - - React-Core/CoreModulesHeaders (0.81.4): + - React-Core/CoreModulesHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -221,7 +221,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/Default (0.81.4): + - React-Core/Default (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -239,12 +239,12 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/DevSupport (0.81.4): + - React-Core/DevSupport (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt - - React-Core/Default (= 0.81.4) - - React-Core/RCTWebSocket (= 0.81.4) + - React-Core/Default (= 0.81.5) + - React-Core/RCTWebSocket (= 0.81.5) - React-cxxreact - React-featureflags - React-hermes @@ -259,7 +259,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTActionSheetHeaders (0.81.4): + - React-Core/RCTActionSheetHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -278,7 +278,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTAnimationHeaders (0.81.4): + - React-Core/RCTAnimationHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -297,7 +297,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTBlobHeaders (0.81.4): + - React-Core/RCTBlobHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -316,7 +316,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTImageHeaders (0.81.4): + - React-Core/RCTImageHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -335,7 +335,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTLinkingHeaders (0.81.4): + - React-Core/RCTLinkingHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -354,7 +354,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTNetworkHeaders (0.81.4): + - React-Core/RCTNetworkHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -373,7 +373,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTSettingsHeaders (0.81.4): + - React-Core/RCTSettingsHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -392,7 +392,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTTextHeaders (0.81.4): + - React-Core/RCTTextHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -411,7 +411,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTVibrationHeaders (0.81.4): + - React-Core/RCTVibrationHeaders (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt @@ -430,11 +430,11 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-Core/RCTWebSocket (0.81.4): + - React-Core/RCTWebSocket (0.81.5): - hermes-engine - RCTDeprecation - React-Core-prebuilt - - React-Core/Default (= 0.81.4) + - React-Core/Default (= 0.81.5) - React-cxxreact - React-featureflags - React-hermes @@ -449,37 +449,37 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-CoreModules (0.81.4): - - RCTTypeSafety (= 0.81.4) + - React-CoreModules (0.81.5): + - RCTTypeSafety (= 0.81.5) - React-Core-prebuilt - - React-Core/CoreModulesHeaders (= 0.81.4) - - React-jsi (= 0.81.4) + - React-Core/CoreModulesHeaders (= 0.81.5) + - React-jsi (= 0.81.5) - React-jsinspector - React-jsinspectorcdp - React-jsinspectortracing - React-NativeModulesApple - React-RCTBlob - React-RCTFBReactNativeSpec - - React-RCTImage (= 0.81.4) + - React-RCTImage (= 0.81.5) - React-runtimeexecutor - ReactCommon - ReactNativeDependencies - - React-cxxreact (0.81.4): + - React-cxxreact (0.81.5): - hermes-engine - - React-callinvoker (= 0.81.4) + - React-callinvoker (= 0.81.5) - React-Core-prebuilt - - React-debug (= 0.81.4) - - React-jsi (= 0.81.4) + - React-debug (= 0.81.5) + - React-jsi (= 0.81.5) - React-jsinspector - React-jsinspectorcdp - React-jsinspectortracing - - React-logger (= 0.81.4) - - React-perflogger (= 0.81.4) + - React-logger (= 0.81.5) + - React-perflogger (= 0.81.5) - React-runtimeexecutor - - React-timing (= 0.81.4) + - React-timing (= 0.81.5) - ReactNativeDependencies - - React-debug (0.81.4) - - React-defaultsnativemodule (0.81.4): + - React-debug (0.81.5) + - React-defaultsnativemodule (0.81.5): - hermes-engine - React-Core-prebuilt - React-domnativemodule @@ -490,7 +490,7 @@ PODS: - React-microtasksnativemodule - React-RCTFBReactNativeSpec - ReactNativeDependencies - - React-domnativemodule (0.81.4): + - React-domnativemodule (0.81.5): - hermes-engine - React-Core-prebuilt - React-Fabric @@ -504,7 +504,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-Fabric (0.81.4): + - React-Fabric (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -512,23 +512,23 @@ PODS: - React-Core-prebuilt - React-cxxreact - React-debug - - React-Fabric/animations (= 0.81.4) - - React-Fabric/attributedstring (= 0.81.4) - - React-Fabric/bridging (= 0.81.4) - - React-Fabric/componentregistry (= 0.81.4) - - React-Fabric/componentregistrynative (= 0.81.4) - - React-Fabric/components (= 0.81.4) - - React-Fabric/consistency (= 0.81.4) - - React-Fabric/core (= 0.81.4) - - React-Fabric/dom (= 0.81.4) - - React-Fabric/imagemanager (= 0.81.4) - - React-Fabric/leakchecker (= 0.81.4) - - React-Fabric/mounting (= 0.81.4) - - React-Fabric/observers (= 0.81.4) - - React-Fabric/scheduler (= 0.81.4) - - React-Fabric/telemetry (= 0.81.4) - - React-Fabric/templateprocessor (= 0.81.4) - - React-Fabric/uimanager (= 0.81.4) + - React-Fabric/animations (= 0.81.5) + - React-Fabric/attributedstring (= 0.81.5) + - React-Fabric/bridging (= 0.81.5) + - React-Fabric/componentregistry (= 0.81.5) + - React-Fabric/componentregistrynative (= 0.81.5) + - React-Fabric/components (= 0.81.5) + - React-Fabric/consistency (= 0.81.5) + - React-Fabric/core (= 0.81.5) + - React-Fabric/dom (= 0.81.5) + - React-Fabric/imagemanager (= 0.81.5) + - React-Fabric/leakchecker (= 0.81.5) + - React-Fabric/mounting (= 0.81.5) + - React-Fabric/observers (= 0.81.5) + - React-Fabric/scheduler (= 0.81.5) + - React-Fabric/telemetry (= 0.81.5) + - React-Fabric/templateprocessor (= 0.81.5) + - React-Fabric/uimanager (= 0.81.5) - React-featureflags - React-graphics - React-jsi @@ -540,7 +540,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/animations (0.81.4): + - React-Fabric/animations (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -559,7 +559,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/attributedstring (0.81.4): + - React-Fabric/attributedstring (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -578,7 +578,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/bridging (0.81.4): + - React-Fabric/bridging (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -597,7 +597,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/componentregistry (0.81.4): + - React-Fabric/componentregistry (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -616,7 +616,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/componentregistrynative (0.81.4): + - React-Fabric/componentregistrynative (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -635,7 +635,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/components (0.81.4): + - React-Fabric/components (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -643,10 +643,10 @@ PODS: - React-Core-prebuilt - React-cxxreact - React-debug - - React-Fabric/components/legacyviewmanagerinterop (= 0.81.4) - - React-Fabric/components/root (= 0.81.4) - - React-Fabric/components/scrollview (= 0.81.4) - - React-Fabric/components/view (= 0.81.4) + - React-Fabric/components/legacyviewmanagerinterop (= 0.81.5) + - React-Fabric/components/root (= 0.81.5) + - React-Fabric/components/scrollview (= 0.81.5) + - React-Fabric/components/view (= 0.81.5) - React-featureflags - React-graphics - React-jsi @@ -658,7 +658,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/components/legacyviewmanagerinterop (0.81.4): + - React-Fabric/components/legacyviewmanagerinterop (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -677,7 +677,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/components/root (0.81.4): + - React-Fabric/components/root (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -696,7 +696,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/components/scrollview (0.81.4): + - React-Fabric/components/scrollview (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -715,7 +715,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/components/view (0.81.4): + - React-Fabric/components/view (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -736,7 +736,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-Fabric/consistency (0.81.4): + - React-Fabric/consistency (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -755,7 +755,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/core (0.81.4): + - React-Fabric/core (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -774,7 +774,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/dom (0.81.4): + - React-Fabric/dom (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -793,7 +793,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/imagemanager (0.81.4): + - React-Fabric/imagemanager (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -812,7 +812,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/leakchecker (0.81.4): + - React-Fabric/leakchecker (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -831,7 +831,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/mounting (0.81.4): + - React-Fabric/mounting (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -850,7 +850,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/observers (0.81.4): + - React-Fabric/observers (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -858,7 +858,7 @@ PODS: - React-Core-prebuilt - React-cxxreact - React-debug - - React-Fabric/observers/events (= 0.81.4) + - React-Fabric/observers/events (= 0.81.5) - React-featureflags - React-graphics - React-jsi @@ -870,7 +870,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/observers/events (0.81.4): + - React-Fabric/observers/events (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -889,7 +889,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/scheduler (0.81.4): + - React-Fabric/scheduler (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -910,7 +910,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/telemetry (0.81.4): + - React-Fabric/telemetry (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -929,7 +929,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/templateprocessor (0.81.4): + - React-Fabric/templateprocessor (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -948,7 +948,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/uimanager (0.81.4): + - React-Fabric/uimanager (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -956,7 +956,7 @@ PODS: - React-Core-prebuilt - React-cxxreact - React-debug - - React-Fabric/uimanager/consistency (= 0.81.4) + - React-Fabric/uimanager/consistency (= 0.81.5) - React-featureflags - React-graphics - React-jsi @@ -969,7 +969,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-Fabric/uimanager/consistency (0.81.4): + - React-Fabric/uimanager/consistency (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -989,7 +989,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-FabricComponents (0.81.4): + - React-FabricComponents (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -998,8 +998,8 @@ PODS: - React-cxxreact - React-debug - React-Fabric - - React-FabricComponents/components (= 0.81.4) - - React-FabricComponents/textlayoutmanager (= 0.81.4) + - React-FabricComponents/components (= 0.81.5) + - React-FabricComponents/textlayoutmanager (= 0.81.5) - React-featureflags - React-graphics - React-jsi @@ -1012,7 +1012,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components (0.81.4): + - React-FabricComponents/components (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1021,17 +1021,17 @@ PODS: - React-cxxreact - React-debug - React-Fabric - - React-FabricComponents/components/inputaccessory (= 0.81.4) - - React-FabricComponents/components/iostextinput (= 0.81.4) - - React-FabricComponents/components/modal (= 0.81.4) - - React-FabricComponents/components/rncore (= 0.81.4) - - React-FabricComponents/components/safeareaview (= 0.81.4) - - React-FabricComponents/components/scrollview (= 0.81.4) - - React-FabricComponents/components/switch (= 0.81.4) - - React-FabricComponents/components/text (= 0.81.4) - - React-FabricComponents/components/textinput (= 0.81.4) - - React-FabricComponents/components/unimplementedview (= 0.81.4) - - React-FabricComponents/components/virtualview (= 0.81.4) + - React-FabricComponents/components/inputaccessory (= 0.81.5) + - React-FabricComponents/components/iostextinput (= 0.81.5) + - React-FabricComponents/components/modal (= 0.81.5) + - React-FabricComponents/components/rncore (= 0.81.5) + - React-FabricComponents/components/safeareaview (= 0.81.5) + - React-FabricComponents/components/scrollview (= 0.81.5) + - React-FabricComponents/components/switch (= 0.81.5) + - React-FabricComponents/components/text (= 0.81.5) + - React-FabricComponents/components/textinput (= 0.81.5) + - React-FabricComponents/components/unimplementedview (= 0.81.5) + - React-FabricComponents/components/virtualview (= 0.81.5) - React-featureflags - React-graphics - React-jsi @@ -1044,7 +1044,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/inputaccessory (0.81.4): + - React-FabricComponents/components/inputaccessory (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1065,7 +1065,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/iostextinput (0.81.4): + - React-FabricComponents/components/iostextinput (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1086,7 +1086,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/modal (0.81.4): + - React-FabricComponents/components/modal (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1107,7 +1107,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/rncore (0.81.4): + - React-FabricComponents/components/rncore (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1128,7 +1128,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/safeareaview (0.81.4): + - React-FabricComponents/components/safeareaview (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1149,7 +1149,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/scrollview (0.81.4): + - React-FabricComponents/components/scrollview (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1170,7 +1170,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/switch (0.81.4): + - React-FabricComponents/components/switch (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1191,7 +1191,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/text (0.81.4): + - React-FabricComponents/components/text (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1212,7 +1212,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/textinput (0.81.4): + - React-FabricComponents/components/textinput (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1233,7 +1233,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/unimplementedview (0.81.4): + - React-FabricComponents/components/unimplementedview (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1254,7 +1254,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/components/virtualview (0.81.4): + - React-FabricComponents/components/virtualview (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1275,7 +1275,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricComponents/textlayoutmanager (0.81.4): + - React-FabricComponents/textlayoutmanager (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1296,27 +1296,27 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-FabricImage (0.81.4): + - React-FabricImage (0.81.5): - hermes-engine - - RCTRequired (= 0.81.4) - - RCTTypeSafety (= 0.81.4) + - RCTRequired (= 0.81.5) + - RCTTypeSafety (= 0.81.5) - React-Core-prebuilt - React-Fabric - React-featureflags - React-graphics - React-ImageManager - React-jsi - - React-jsiexecutor (= 0.81.4) + - React-jsiexecutor (= 0.81.5) - React-logger - React-rendererdebug - React-utils - ReactCommon - ReactNativeDependencies - Yoga - - React-featureflags (0.81.4): + - React-featureflags (0.81.5): - React-Core-prebuilt - ReactNativeDependencies - - React-featureflagsnativemodule (0.81.4): + - React-featureflagsnativemodule (0.81.5): - hermes-engine - React-Core-prebuilt - React-featureflags @@ -1325,26 +1325,26 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-graphics (0.81.4): + - React-graphics (0.81.5): - hermes-engine - React-Core-prebuilt - React-jsi - React-jsiexecutor - React-utils - ReactNativeDependencies - - React-hermes (0.81.4): + - React-hermes (0.81.5): - hermes-engine - React-Core-prebuilt - - React-cxxreact (= 0.81.4) + - React-cxxreact (= 0.81.5) - React-jsi - - React-jsiexecutor (= 0.81.4) + - React-jsiexecutor (= 0.81.5) - React-jsinspector - React-jsinspectorcdp - React-jsinspectortracing - - React-perflogger (= 0.81.4) + - React-perflogger (= 0.81.5) - React-runtimeexecutor - ReactNativeDependencies - - React-idlecallbacksnativemodule (0.81.4): + - React-idlecallbacksnativemodule (0.81.5): - hermes-engine - React-Core-prebuilt - React-jsi @@ -1354,7 +1354,7 @@ PODS: - React-runtimescheduler - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-ImageManager (0.81.4): + - React-ImageManager (0.81.5): - React-Core-prebuilt - React-Core/Default - React-debug @@ -1363,7 +1363,7 @@ PODS: - React-rendererdebug - React-utils - ReactNativeDependencies - - React-jserrorhandler (0.81.4): + - React-jserrorhandler (0.81.5): - hermes-engine - React-Core-prebuilt - React-cxxreact @@ -1372,22 +1372,22 @@ PODS: - React-jsi - ReactCommon/turbomodule/bridging - ReactNativeDependencies - - React-jsi (0.81.4): + - React-jsi (0.81.5): - hermes-engine - React-Core-prebuilt - ReactNativeDependencies - - React-jsiexecutor (0.81.4): + - React-jsiexecutor (0.81.5): - hermes-engine - React-Core-prebuilt - - React-cxxreact (= 0.81.4) - - React-jsi (= 0.81.4) + - React-cxxreact (= 0.81.5) + - React-jsi (= 0.81.5) - React-jsinspector - React-jsinspectorcdp - React-jsinspectortracing - - React-perflogger (= 0.81.4) + - React-perflogger (= 0.81.5) - React-runtimeexecutor - ReactNativeDependencies - - React-jsinspector (0.81.4): + - React-jsinspector (0.81.5): - hermes-engine - React-Core-prebuilt - React-featureflags @@ -1396,43 +1396,43 @@ PODS: - React-jsinspectornetwork - React-jsinspectortracing - React-oscompat - - React-perflogger (= 0.81.4) + - React-perflogger (= 0.81.5) - React-runtimeexecutor - ReactNativeDependencies - - React-jsinspectorcdp (0.81.4): + - React-jsinspectorcdp (0.81.5): - React-Core-prebuilt - ReactNativeDependencies - - React-jsinspectornetwork (0.81.4): + - React-jsinspectornetwork (0.81.5): - React-Core-prebuilt - React-featureflags - React-jsinspectorcdp - React-performancetimeline - React-timing - ReactNativeDependencies - - React-jsinspectortracing (0.81.4): + - React-jsinspectortracing (0.81.5): - React-Core-prebuilt - React-oscompat - React-timing - ReactNativeDependencies - - React-jsitooling (0.81.4): + - React-jsitooling (0.81.5): - React-Core-prebuilt - - React-cxxreact (= 0.81.4) - - React-jsi (= 0.81.4) + - React-cxxreact (= 0.81.5) + - React-jsi (= 0.81.5) - React-jsinspector - React-jsinspectorcdp - React-jsinspectortracing - React-runtimeexecutor - ReactNativeDependencies - - React-jsitracing (0.81.4): + - React-jsitracing (0.81.5): - React-jsi - - React-logger (0.81.4): + - React-logger (0.81.5): - React-Core-prebuilt - ReactNativeDependencies - - React-Mapbuffer (0.81.4): + - React-Mapbuffer (0.81.5): - React-Core-prebuilt - React-debug - ReactNativeDependencies - - React-microtasksnativemodule (0.81.4): + - React-microtasksnativemodule (0.81.5): - hermes-engine - React-Core-prebuilt - React-jsi @@ -1557,7 +1557,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - React-NativeModulesApple (0.81.4): + - React-NativeModulesApple (0.81.5): - hermes-engine - React-callinvoker - React-Core @@ -1571,20 +1571,20 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - ReactNativeDependencies - - React-oscompat (0.81.4) - - React-perflogger (0.81.4): + - React-oscompat (0.81.5) + - React-perflogger (0.81.5): - React-Core-prebuilt - ReactNativeDependencies - - React-performancetimeline (0.81.4): + - React-performancetimeline (0.81.5): - React-Core-prebuilt - React-featureflags - React-jsinspectortracing - React-perflogger - React-timing - ReactNativeDependencies - - React-RCTActionSheet (0.81.4): - - React-Core/RCTActionSheetHeaders (= 0.81.4) - - React-RCTAnimation (0.81.4): + - React-RCTActionSheet (0.81.5): + - React-Core/RCTActionSheetHeaders (= 0.81.5) + - React-RCTAnimation (0.81.5): - RCTTypeSafety - React-Core-prebuilt - React-Core/RCTAnimationHeaders @@ -1594,7 +1594,7 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon - ReactNativeDependencies - - React-RCTAppDelegate (0.81.4): + - React-RCTAppDelegate (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1622,7 +1622,7 @@ PODS: - React-utils - ReactCommon - ReactNativeDependencies - - React-RCTBlob (0.81.4): + - React-RCTBlob (0.81.5): - hermes-engine - React-Core-prebuilt - React-Core/RCTBlobHeaders @@ -1635,7 +1635,7 @@ PODS: - React-RCTNetwork - ReactCommon - ReactNativeDependencies - - React-RCTFabric (0.81.4): + - React-RCTFabric (0.81.5): - hermes-engine - React-Core - React-Core-prebuilt @@ -1664,7 +1664,7 @@ PODS: - React-utils - ReactNativeDependencies - Yoga - - React-RCTFBReactNativeSpec (0.81.4): + - React-RCTFBReactNativeSpec (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1672,10 +1672,10 @@ PODS: - React-Core-prebuilt - React-jsi - React-NativeModulesApple - - React-RCTFBReactNativeSpec/components (= 0.81.4) + - React-RCTFBReactNativeSpec/components (= 0.81.5) - ReactCommon - ReactNativeDependencies - - React-RCTFBReactNativeSpec/components (0.81.4): + - React-RCTFBReactNativeSpec/components (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1692,7 +1692,7 @@ PODS: - ReactCommon - ReactNativeDependencies - Yoga - - React-RCTImage (0.81.4): + - React-RCTImage (0.81.5): - RCTTypeSafety - React-Core-prebuilt - React-Core/RCTImageHeaders @@ -1702,14 +1702,14 @@ PODS: - React-RCTNetwork - ReactCommon - ReactNativeDependencies - - React-RCTLinking (0.81.4): - - React-Core/RCTLinkingHeaders (= 0.81.4) - - React-jsi (= 0.81.4) + - React-RCTLinking (0.81.5): + - React-Core/RCTLinkingHeaders (= 0.81.5) + - React-jsi (= 0.81.5) - React-NativeModulesApple - React-RCTFBReactNativeSpec - ReactCommon - - ReactCommon/turbomodule/core (= 0.81.4) - - React-RCTNetwork (0.81.4): + - ReactCommon/turbomodule/core (= 0.81.5) + - React-RCTNetwork (0.81.5): - RCTTypeSafety - React-Core-prebuilt - React-Core/RCTNetworkHeaders @@ -1721,7 +1721,7 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon - ReactNativeDependencies - - React-RCTRuntime (0.81.4): + - React-RCTRuntime (0.81.5): - hermes-engine - React-Core - React-Core-prebuilt @@ -1735,7 +1735,7 @@ PODS: - React-runtimeexecutor - React-RuntimeHermes - ReactNativeDependencies - - React-RCTSettings (0.81.4): + - React-RCTSettings (0.81.5): - RCTTypeSafety - React-Core-prebuilt - React-Core/RCTSettingsHeaders @@ -1744,10 +1744,10 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon - ReactNativeDependencies - - React-RCTText (0.81.4): - - React-Core/RCTTextHeaders (= 0.81.4) + - React-RCTText (0.81.5): + - React-Core/RCTTextHeaders (= 0.81.5) - Yoga - - React-RCTVibration (0.81.4): + - React-RCTVibration (0.81.5): - React-Core-prebuilt - React-Core/RCTVibrationHeaders - React-jsi @@ -1755,15 +1755,15 @@ PODS: - React-RCTFBReactNativeSpec - ReactCommon - ReactNativeDependencies - - React-rendererconsistency (0.81.4) - - React-renderercss (0.81.4): + - React-rendererconsistency (0.81.5) + - React-renderercss (0.81.5): - React-debug - React-utils - - React-rendererdebug (0.81.4): + - React-rendererdebug (0.81.5): - React-Core-prebuilt - React-debug - ReactNativeDependencies - - React-RuntimeApple (0.81.4): + - React-RuntimeApple (0.81.5): - hermes-engine - React-callinvoker - React-Core-prebuilt @@ -1786,7 +1786,7 @@ PODS: - React-runtimescheduler - React-utils - ReactNativeDependencies - - React-RuntimeCore (0.81.4): + - React-RuntimeCore (0.81.5): - hermes-engine - React-Core-prebuilt - React-cxxreact @@ -1802,14 +1802,14 @@ PODS: - React-runtimescheduler - React-utils - ReactNativeDependencies - - React-runtimeexecutor (0.81.4): + - React-runtimeexecutor (0.81.5): - React-Core-prebuilt - React-debug - React-featureflags - - React-jsi (= 0.81.4) + - React-jsi (= 0.81.5) - React-utils - ReactNativeDependencies - - React-RuntimeHermes (0.81.4): + - React-RuntimeHermes (0.81.5): - hermes-engine - React-Core-prebuilt - React-featureflags @@ -1824,7 +1824,7 @@ PODS: - React-runtimeexecutor - React-utils - ReactNativeDependencies - - React-runtimescheduler (0.81.4): + - React-runtimescheduler (0.81.5): - hermes-engine - React-callinvoker - React-Core-prebuilt @@ -1840,17 +1840,17 @@ PODS: - React-timing - React-utils - ReactNativeDependencies - - React-timing (0.81.4): + - React-timing (0.81.5): - React-debug - - React-utils (0.81.4): + - React-utils (0.81.5): - hermes-engine - React-Core-prebuilt - React-debug - - React-jsi (= 0.81.4) + - React-jsi (= 0.81.5) - ReactNativeDependencies - - ReactAppDependencyProvider (0.81.4): + - ReactAppDependencyProvider (0.81.5): - ReactCodegen - - ReactCodegen (0.81.4): + - ReactCodegen (0.81.5): - hermes-engine - RCTRequired - RCTTypeSafety @@ -1870,43 +1870,43 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - ReactNativeDependencies - - ReactCommon (0.81.4): + - ReactCommon (0.81.5): - React-Core-prebuilt - - ReactCommon/turbomodule (= 0.81.4) + - ReactCommon/turbomodule (= 0.81.5) - ReactNativeDependencies - - ReactCommon/turbomodule (0.81.4): + - ReactCommon/turbomodule (0.81.5): - hermes-engine - - React-callinvoker (= 0.81.4) + - React-callinvoker (= 0.81.5) - React-Core-prebuilt - - React-cxxreact (= 0.81.4) - - React-jsi (= 0.81.4) - - React-logger (= 0.81.4) - - React-perflogger (= 0.81.4) - - ReactCommon/turbomodule/bridging (= 0.81.4) - - ReactCommon/turbomodule/core (= 0.81.4) + - React-cxxreact (= 0.81.5) + - React-jsi (= 0.81.5) + - React-logger (= 0.81.5) + - React-perflogger (= 0.81.5) + - ReactCommon/turbomodule/bridging (= 0.81.5) + - ReactCommon/turbomodule/core (= 0.81.5) - ReactNativeDependencies - - ReactCommon/turbomodule/bridging (0.81.4): + - ReactCommon/turbomodule/bridging (0.81.5): - hermes-engine - - React-callinvoker (= 0.81.4) + - React-callinvoker (= 0.81.5) - React-Core-prebuilt - - React-cxxreact (= 0.81.4) - - React-jsi (= 0.81.4) - - React-logger (= 0.81.4) - - React-perflogger (= 0.81.4) + - React-cxxreact (= 0.81.5) + - React-jsi (= 0.81.5) + - React-logger (= 0.81.5) + - React-perflogger (= 0.81.5) - ReactNativeDependencies - - ReactCommon/turbomodule/core (0.81.4): + - ReactCommon/turbomodule/core (0.81.5): - hermes-engine - - React-callinvoker (= 0.81.4) + - React-callinvoker (= 0.81.5) - React-Core-prebuilt - - React-cxxreact (= 0.81.4) - - React-debug (= 0.81.4) - - React-featureflags (= 0.81.4) - - React-jsi (= 0.81.4) - - React-logger (= 0.81.4) - - React-perflogger (= 0.81.4) - - React-utils (= 0.81.4) + - React-cxxreact (= 0.81.5) + - React-debug (= 0.81.5) + - React-featureflags (= 0.81.5) + - React-jsi (= 0.81.5) + - React-logger (= 0.81.5) + - React-perflogger (= 0.81.5) + - React-utils (= 0.81.5) - ReactNativeDependencies - - ReactNativeDependencies (0.81.4) + - ReactNativeDependencies (0.81.5) - RevenueCat (5.43.0) - RNCAsyncStorage (2.2.0): - hermes-engine @@ -2675,10 +2675,10 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: EXApplication: 296622817d459f46b6c5fe8691f4aac44d2b79e7 - EXConstants: a95804601ee4a6aa7800645f9b070d753b1142b3 + EXConstants: fd688cef4e401dcf798a021cfb5d87c890c30ba3 EXImageLoader: 189e3476581efe3ad4d1d3fb4735b7179eb26f05 EXNotifications: 7cff475adb5d7a255a9ea46bbd2589cb3b454506 - Expo: 6580dbf21d94626792b38a95cddb2fb369ec6b0c + Expo: 27ae59be9be4feab2b1c1ae06550752c524ca558 ExpoAppleAuthentication: bc9de6e9ff3340604213ab9031d4c4f7f802623e ExpoAsset: 9ba6fbd677fb8e241a3899ac00fa735bc911eadf ExpoBackgroundTask: e0d201d38539c571efc5f9cb661fae8ab36ed61b @@ -2686,101 +2686,101 @@ SPEC CHECKSUMS: ExpoCamera: e75f6807a2c047f3338bbadd101af4c71a1d13a5 ExpoFileSystem: b79eadbda7b7f285f378f95f959cc9313a1c9c61 ExpoFont: cf9d90ec1d3b97c4f513211905724c8171f82961 - ExpoGlassEffect: 744bf0c58c26a1b0212dff92856be07b98d01d8c + ExpoGlassEffect: 779c46bd04ea47ba4726efb73267b5bcc6abd664 ExpoHaptics: 807476b0c39e9d82b7270349d6487928ce32df84 - ExpoHead: 7141e494b0773a8f0dc5ca3366ce91b1300f5a9d - ExpoImage: 6356eb13d3a076a991cf191e4bb22cca91a8f317 + ExpoHead: e317214fa14edeaf17748d39ec9e550a3d1194fb + ExpoImage: 9c3428921c536ab29e5c6721d001ad5c1f469566 ExpoImagePicker: d251aab45a1b1857e4156fed88511b278b4eee1c ExpoKeepAwake: 1a2e820692e933c94a565ec3fbbe38ac31658ffe ExpoLinearGradient: a464898cb95153125e3b81894fd479bcb1c7dd27 ExpoLinking: f051f28e50ea9269ff539317c166adec81d9342d ExpoMediaLibrary: 641a6952299b395159ccd459bd8f5f6764bf55fe - ExpoModulesCore: 3a6eb12a5f4d67b2f5fc7d0bc4777b18348f2d7a + ExpoModulesCore: 5f20603cf25698682d7c43c05fbba8c748b189d2 ExpoQuickActions: 31a70aa6a606128de4416a4830e09cfabfe6667f ExpoSplashScreen: cbb839de72110dea1851dd3e85080b7923af2540 ExpoSQLite: 7fa091ba5562474093fef09be644161a65e11b3f ExpoSymbols: 1ae04ce686de719b9720453b988d8bc5bf776c68 - ExpoSystemUI: 6cd74248a2282adf6dec488a75fa532d69dee314 + ExpoSystemUI: 2761aa6875849af83286364811d46e8ed8ea64c7 ExpoUI: b99a1d1ef5352a60bebf4f4fd3a50d2f896ae804 ExpoWebBrowser: d04a0d6247a0bea4519fbc2ea816610019ad83e0 - EXTaskManager: cf225704fab8de8794a6f57f7fa41a90c0e2cd47 - FBLazyVector: 9e0cd874afd81d9a4d36679daca991b58b260d42 - hermes-engine: 35c763d57c9832d0eef764316ca1c4d043581394 + EXTaskManager: cbbb80cbccea6487ccca0631809fbba2ed3e5271 + FBLazyVector: e95a291ad2dadb88e42b06e0c5fb8262de53ec12 + hermes-engine: 9f4dfe93326146a1c99eb535b1cb0b857a3cd172 libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 lottie-ios: a881093fab623c467d3bce374367755c272bdd59 lottie-react-native: cbe3d931a7c24f7891a8e8032c2bb9b2373c4b9c PurchasesHybridCommon: b7b4eafb55fbaaac19b4c36d4082657a3f0d8490 - RCTDeprecation: 7487d6dda857ccd4cb3dd6ecfccdc3170e85dcbc - RCTRequired: 54128b7df8be566881d48c7234724a78cb9b6157 - RCTTypeSafety: d2b07797a79e45d7b19e1cd2f53c79ab419fe217 - React: 2073376f47c71b7e9a0af7535986a77522ce1049 - React-callinvoker: 00fa0972a70df7408a4f088144b67207b157e386 - React-Core: d375dd308561785c739a621a21802e5e7e047dee - React-Core-prebuilt: dde79b89f8863efebb1d532a3335f472927da669 - React-CoreModules: 3eb9b1410a317987c557afc683cc50099562c91d - React-cxxreact: 724210b64158d97f150d8d254a7319e73ef77ee7 - React-debug: c01d176522cf57cdc4a4a66d1974968fcf497f32 - React-defaultsnativemodule: 3953ff49013fa997e72586628e1d218fdaf3abdb - React-domnativemodule: 540b9c7a8f31b6f4ed449aafd3a272e1f1107089 - React-Fabric: 00b792be016edad758a63c4ebac15e01d35f6355 - React-FabricComponents: 16ebdb9245d91ec27985a038d0a6460f499db54e - React-FabricImage: 2a967b5f0293c1c49ec883babfd4992d161e3583 - React-featureflags: 4150b4ddac8210b1e3c538cfb455050b5ee05d8d - React-featureflagsnativemodule: ff977040205b96818ac1f884846493cb8a2aca28 - React-graphics: ec689ac1c13a9ddb1af83baf195264676ecdbeb6 - React-hermes: ff60a3407f27f3fc82f661774a7ab6559a24ab69 - React-idlecallbacksnativemodule: 5f5ce3c424941f77da4ac3adba681149e68b1221 - React-ImageManager: 8d87296a86f9ee290c1d32c68c7be1be63492467 - React-jserrorhandler: 072756f12136284c86e96c33cdfece4d7286a99f - React-jsi: b507852b42a9125dffbf6ae7a33792fb521b29a2 - React-jsiexecutor: f970eed6debb91fe5d5d6cb5734d39cf86c59896 - React-jsinspector: 766e113e9482b22971b30236d10c04d8af38269e - React-jsinspectorcdp: 5b60350e29fe2566d9ed9799858c04b8e6095a3e - React-jsinspectornetwork: b3cc9a20c6b270f792eaaaa14313019a031b327d - React-jsinspectortracing: d99120fcf0864209c45cefbc9fc4605c8189c0ef - React-jsitooling: 9e41724cc47feadefbede31ca91d70f6ff079656 - React-jsitracing: ca020d934502de8e02cccf451501434a5e584027 - React-logger: 7b234de35acb469ce76d6bbb0457f664d6f32f62 - React-Mapbuffer: fbe1da882a187e5898bdf125e1cc6e603d27ecae - React-microtasksnativemodule: 76905804171d8ccbe69329fc84c57eb7934add7f + RCTDeprecation: 943572d4be82d480a48f4884f670135ae30bf990 + RCTRequired: 8f3cfc90cc25cf6e420ddb3e7caaaabc57df6043 + RCTTypeSafety: 16a4144ca3f959583ab019b57d5633df10b5e97c + React: 914f8695f9bf38e6418228c2ffb70021e559f92f + React-callinvoker: 1c0808402aee0c6d4a0d8e7220ce6547af9fba71 + React-Core: c61410ef0ca6055e204a963992e363227e0fd1c5 + React-Core-prebuilt: 02f0ad625ddd47463c009c2d0c5dd35c0d982599 + React-CoreModules: 1f6d1744b5f9f2ec684a4bb5ced25370f87e5382 + React-cxxreact: 3af79478e8187b63ffc22b794cd42d3fc1f1f2da + React-debug: 6328c2228e268846161f10082e80dc69eac2e90a + React-defaultsnativemodule: d635ef36d755321e5d6fc065bd166b2c5a0e9833 + React-domnativemodule: dd28f6d96cd21236e020be2eff6fe0b7d4ec3b66 + React-Fabric: 2e32c3fdbb1fbcf5fde54607e3abe453c6652ce2 + React-FabricComponents: 5ed0cdb81f6b91656cb4d3be432feaa28a58071a + React-FabricImage: 2bc714f818cb24e454f5d3961864373271b2faf8 + React-featureflags: 847642f41fa71ad4eec5e0351badebcad4fe6171 + React-featureflagsnativemodule: c868a544b2c626fa337bcbd364b1befe749f0d3f + React-graphics: 192ec701def5b3f2a07db2814dfba5a44986cff6 + React-hermes: e875778b496c86d07ab2ccaa36a9505d248a254b + React-idlecallbacksnativemodule: 4d57965cdf82c14ee3b337189836cd8491632b76 + React-ImageManager: bd0b99e370b13de82c9cd15f0f08144ff3de079e + React-jserrorhandler: a2fdef4cbcfdcdf3fa9f5d1f7190f7fd4535248d + React-jsi: 89d43d1e7d4d0663f8ba67e0b39eb4e4672c27de + React-jsiexecutor: abe4874aaab90dfee5dec480680220b2f8af07e3 + React-jsinspector: a0b3e051aef842b0b2be2353790ae2b2a5a65a8f + React-jsinspectorcdp: 6346013b2247c6263fbf5199adf4a8751e53bd89 + React-jsinspectornetwork: 26281aa50d49fc1ec93abf981d934698fa95714f + React-jsinspectortracing: 55eedf6d57540507570259a778663b90060bbd6e + React-jsitooling: 0e001113fa56d8498aa8ac28437ac0d36348e51a + React-jsitracing: b713793eb8a5bbc4d86a84e9d9e5023c0f58cbaf + React-logger: 50fdb9a8236da90c0b1072da5c32ee03aeb5bf28 + React-Mapbuffer: 9050ee10c19f4f7fca8963d0211b2854d624973e + React-microtasksnativemodule: f775db9e991c6f3b8ccbc02bfcde22770f96e23b react-native-render-html: 5afc4751f1a98621b3009432ef84c47019dcb2bd react-native-safe-area-context: 42a1b4f8774b577d03b53de7326e3d5757fe9513 react-native-view-shot: fb3c0774edb448f42705491802a455beac1502a2 react-native-voice: 908a0eba96c8c3d643e4f98b7232c6557d0a6f9c react-native-webview: b29007f4723bca10872028067b07abacfa1cb35a - React-NativeModulesApple: a9464983ccc0f66f45e93558671f60fc7536e438 - React-oscompat: 73db7dbc80edef36a9d6ed3c6c4e1724ead4236d - React-perflogger: 123272debf907cc423962adafcf4513320e43757 - React-performancetimeline: 095146e4dc8fa4568e44d7a9debc134f27e103f9 - React-RCTActionSheet: 9fc2a0901af63cefe09c8df95a08c2cf8bb7797b - React-RCTAnimation: 785e743e489bc7aec14415dbc15f4f275b2c0276 - React-RCTAppDelegate: 0602c9e13130edcde4661ea66d11122a3a66f11a - React-RCTBlob: ae53b7508a5ced43378de2a88816f63423df1f24 - React-RCTFabric: 687a0cfb5726adea7fac63560b04410c86d97134 - React-RCTFBReactNativeSpec: 7c55cf4fb4d2baad32ce3850b8504a6ee22e11ce - React-RCTImage: f45474c75cdf1526114f75b27e86d004aa171b90 - React-RCTLinking: 56622ff97570e15e01dd9b5a657010c756a9e2d8 - React-RCTNetwork: 3fffa1ab5d6981f839e7679d56f8cb731ba92c07 - React-RCTRuntime: f38c04f744596fc8e1b4c5f6a57fc05c26955257 - React-RCTSettings: f4a8e1bd36f58ec8273c73d3deefdcf90143ac6a - React-RCTText: da852a51dd1d169b38136a4f4d1eaed35376556b - React-RCTVibration: ff92ef336e32e18efff0fa83c798a2dbbebe09bd - React-rendererconsistency: b83b300e607f4e30478a5c3365e260a760232b04 - React-renderercss: aa6a3cdd4fa4e3726123c42b49ba4dd978f81688 - React-rendererdebug: 6b12a782caf2e7e2f730434264357b7b6aed1781 - React-RuntimeApple: 8934aab108dcab957a87208fef4b6f1b3a04973a - React-RuntimeCore: 1d4345561ecc402e9e88b38e1d9b059a7a13b113 - React-runtimeexecutor: a9a059f222e4d78f45a4e92cada48a5fde989fb8 - React-RuntimeHermes: 05b955709a75038d282a9420342d7bea5857768a - React-runtimescheduler: 4ce23c9157b51101092537d4171ea4de48a5b863 - React-timing: 62441edf291b91ab5b96ab8f2f8fb648c063ce6f - React-utils: 485abe7eaefa04b20e0ef442593e022563a1419b - ReactAppDependencyProvider: 433ddfb4536948630aadd5bd925aff8a632d2fe3 - ReactCodegen: a15ad48730e9fb2a51a4c9f61fe1ed253dfcf10f - ReactCommon: 149b6c05126f2e99f2ed0d3c63539369546f8cae - ReactNativeDependencies: ed6d1e64802b150399f04f1d5728ec16b437251e + React-NativeModulesApple: 8969913947d5b576de4ed371a939455a8daf28aa + React-oscompat: ce47230ed20185e91de62d8c6d139ae61763d09c + React-perflogger: 02b010e665772c7dcb859d85d44c1bfc5ac7c0e4 + React-performancetimeline: 130db956b5a83aa4fb41ddf5ae68da89f3fb1526 + React-RCTActionSheet: 0b14875b3963e9124a5a29a45bd1b22df8803916 + React-RCTAnimation: a7b90fd2af7bb9c084428867445a1481a8cb112e + React-RCTAppDelegate: 3262bedd01263f140ec62b7989f4355f57cec016 + React-RCTBlob: c17531368702f1ebed5d0ada75a7cf5915072a53 + React-RCTFabric: 6409edd8cfdc3133b6cc75636d3b858fdb1d11ea + React-RCTFBReactNativeSpec: c004b27b4fa3bd85878ad2cf53de3bbec85da797 + React-RCTImage: c68078a120d0123f4f07a5ac77bea3bb10242f32 + React-RCTLinking: cf8f9391fe7fe471f96da3a5f0435235eca18c5b + React-RCTNetwork: ca31f7c879355760c2d9832a06ee35f517938a20 + React-RCTRuntime: a6cf4a1e42754fc87f493e538f2ac6b820e45418 + React-RCTSettings: e0e140b2ff4bf86d34e9637f6316848fc00be035 + React-RCTText: 75915bace6f7877c03a840cc7b6c622fb62bfa6b + React-RCTVibration: 25f26b85e5e432bb3c256f8b384f9269e9529f25 + React-rendererconsistency: 2dac03f448ff337235fd5820b10f81633328870d + React-renderercss: 477da167bb96b5ac86d30c5d295412fb853f5453 + React-rendererdebug: 2a1798c6f3ef5f22d466df24c33653edbabb5b89 + React-RuntimeApple: 28cf4d8eb18432f6a21abbed7d801ab7f6b6f0b4 + React-RuntimeCore: 41bf0fd56a00de5660f222415af49879fa49c4f0 + React-runtimeexecutor: 1afb774dde3011348e8334be69d2f57a359ea43e + React-RuntimeHermes: f3b158ea40e8212b1a723a68b4315e7a495c5fc6 + React-runtimescheduler: 3e1e2bec7300bae512533107d8e54c6e5c63fe0f + React-timing: 6fa9883de2e41791e5dc4ec404e5e37f3f50e801 + React-utils: 6e2035b53d087927768649a11a26c4e092448e34 + ReactAppDependencyProvider: 1bcd3527ac0390a1c898c114f81ff954be35ed79 + ReactCodegen: 7d4593f7591f002d137fe40cef3f6c11f13c88cc + ReactCommon: 08810150b1206cc44aecf5f6ae19af32f29151a8 + ReactNativeDependencies: 71ce9c28beb282aa720ea7b46980fff9669f428a RevenueCat: a51003d4cb33820cc504cf177c627832b462a98e RNCAsyncStorage: 3a4f5e2777dae1688b781a487923a08569e27fe4 RNCMaskedView: d2578d41c59b936db122b2798ba37e4722d21035 @@ -2800,7 +2800,7 @@ SPEC CHECKSUMS: SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 Sentry: b3ec44d01708fce73f99b544beb57e890eca4406 UMAppLoader: e1234c45d2b7da239e9e90fc4bbeacee12afd5b6 - Yoga: 051f086b5ccf465ff2ed38a2cf5a558ae01aaaa1 + Yoga: 5934998fbeaef7845dbf698f698518695ab4cd1a ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 PODFILE CHECKSUM: 78eca51725b1f0fcd006b70b9a09e3fb4f960d03 diff --git a/package-lock.json b/package-lock.json index 453f276..7a94832 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,35 +23,35 @@ "@sentry/react-native": "~7.2.0", "@types/lodash": "^4.17.20", "dayjs": "^1.11.18", - "expo": "^54.0.13", + "expo": "54.0.21", "expo-apple-authentication": "~8.0.7", "expo-background-task": "~1.0.8", "expo-blur": "~15.0.7", "expo-camera": "~17.0.8", "expo-constants": "~18.0.9", "expo-font": "~14.0.9", - "expo-glass-effect": "^0.1.4", + "expo-glass-effect": "~0.1.5", "expo-haptics": "~15.0.7", - "expo-image": "~3.0.9", + "expo-image": "~3.0.10", "expo-image-picker": "~17.0.8", "expo-linear-gradient": "~15.0.7", "expo-linking": "~8.0.8", "expo-media-library": "^18.2.0", "expo-notifications": "~0.32.12", "expo-quick-actions": "^6.0.0", - "expo-router": "~6.0.12", + "expo-router": "~6.0.14", "expo-splash-screen": "~31.0.10", "expo-sqlite": "^16.0.8", "expo-status-bar": "~3.0.8", "expo-symbols": "~1.0.7", - "expo-system-ui": "~6.0.7", - "expo-task-manager": "~14.0.7", + "expo-system-ui": "~6.0.8", + "expo-task-manager": "~14.0.8", "expo-web-browser": "~15.0.7", "lodash": "^4.17.21", "lottie-react-native": "^7.3.4", "react": "19.1.0", "react-dom": "19.1.0", - "react-native": "0.81.4", + "react-native": "0.81.5", "react-native-chart-kit": "^6.12.0", "react-native-device-info": "^14.0.4", "react-native-gesture-handler": "~2.28.0", @@ -148,13 +148,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://mirrors.tencent.com/npm/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -375,9 +375,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -506,12 +506,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -524,7 +524,6 @@ "version": "7.28.0", "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.28.0.tgz", "integrity": "sha512-zOiZqvANjWDUaUS9xMxbMcK/Zccztbe/6ikvUXaG9nsPH3w6qh5UaPGAnirI/WhIbZ8m3OHU0ReyPrknG+ZKeg==", - "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", @@ -881,9 +880,9 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.4", - "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", - "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", + "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -964,13 +963,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.0", - "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", - "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", + "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.0" + "@babel/traverse": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1059,9 +1058,9 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.27.1", - "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", - "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", + "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1344,9 +1343,9 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.28.3", - "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.3.tgz", - "integrity": "sha512-Y6ab1kGqZ0u42Zv/4a7l0l72n9DKP/MKoKWaUSBylrhNZO2prYuqFOLbn5aW5SIFXwSH93yfjbgllL8lxuGKLg==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.5.tgz", + "integrity": "sha512-20NUVgOrinudkIBzQ2bNxP08YpKprUkRTiRSd2/Z5GOdPImJGkoN4Z7IQe1T5AdyKI1i5L6RBmluqdSzvaq9/w==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -1461,14 +1460,14 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.27.1", - "resolved": "https://mirrors.tencent.com/npm/@babel/preset-react/-/preset-react-7.27.1.tgz", - "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/preset-react/-/preset-react-7.28.5.tgz", + "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.27.1", + "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" @@ -1523,17 +1522,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -1560,13 +1559,13 @@ } }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://mirrors.tencent.com/npm/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -1835,7 +1834,6 @@ "version": "3.2.7", "resolved": "https://mirrors.tencent.com/npm/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", "dependencies": { "ms": "^2.1.1" } @@ -1875,9 +1873,9 @@ } }, "node_modules/@expo/fingerprint": { - "version": "0.15.1", - "resolved": "https://mirrors.tencent.com/npm/@expo/fingerprint/-/fingerprint-0.15.1.tgz", - "integrity": "sha512-U1S9DwiapCHQjHdHDDyO/oXsl/1oEHSHZRRkWDDrHgXRUDiAVIySw9Unvvcr118Ee6/x4NmKSZY1X0VagrqmFg==", + "version": "0.15.2", + "resolved": "https://mirrors.tencent.com/npm/@expo/fingerprint/-/fingerprint-0.15.2.tgz", + "integrity": "sha512-mA3weHEOd9B3mbDLNDKmAcFWo3kqsAJqPne7uMJndheKXPbRw15bV+ajAGBYZh2SS37xixLJ5eDpuc+Wr6jJtw==", "license": "MIT", "dependencies": { "@expo/spawn-async": "^1.7.2", @@ -1909,7 +1907,6 @@ "version": "9.0.5", "resolved": "https://mirrors.tencent.com/npm/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1921,10 +1918,9 @@ } }, "node_modules/@expo/fingerprint/node_modules/semver": { - "version": "7.7.2", - "resolved": "https://mirrors.tencent.com/npm/semver/-/semver-7.7.2.tgz", - "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", - "license": "ISC", + "version": "7.7.3", + "resolved": "https://mirrors.tencent.com/npm/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "bin": { "semver": "bin/semver.js" }, @@ -2022,29 +2018,29 @@ } }, "node_modules/@expo/metro": { - "version": "54.0.0", - "resolved": "https://mirrors.tencent.com/npm/@expo/metro/-/metro-54.0.0.tgz", - "integrity": "sha512-x2HlliepLJVLSe0Fl/LuPT83Mn2EXpPlb1ngVtcawlz4IfbkYJo16/Zfsfrn1t9d8LpN5dD44Dc55Q1/fO05Nw==", + "version": "54.1.0", + "resolved": "https://mirrors.tencent.com/npm/@expo/metro/-/metro-54.1.0.tgz", + "integrity": "sha512-MgdeRNT/LH0v1wcO0TZp9Qn8zEF0X2ACI0wliPtv5kXVbXWI+yK9GyrstwLAiTXlULKVIg3HVSCCvmLu0M3tnw==", "license": "MIT", "dependencies": { - "metro": "0.83.1", - "metro-babel-transformer": "0.83.1", - "metro-cache": "0.83.1", - "metro-cache-key": "0.83.1", - "metro-config": "0.83.1", - "metro-core": "0.83.1", - "metro-file-map": "0.83.1", - "metro-resolver": "0.83.1", - "metro-runtime": "0.83.1", - "metro-source-map": "0.83.1", - "metro-transform-plugins": "0.83.1", - "metro-transform-worker": "0.83.1" + "metro": "0.83.2", + "metro-babel-transformer": "0.83.2", + "metro-cache": "0.83.2", + "metro-cache-key": "0.83.2", + "metro-config": "0.83.2", + "metro-core": "0.83.2", + "metro-file-map": "0.83.2", + "metro-resolver": "0.83.2", + "metro-runtime": "0.83.2", + "metro-source-map": "0.83.2", + "metro-transform-plugins": "0.83.2", + "metro-transform-worker": "0.83.2" } }, "node_modules/@expo/metro-config": { - "version": "54.0.6", - "resolved": "https://mirrors.tencent.com/npm/@expo/metro-config/-/metro-config-54.0.6.tgz", - "integrity": "sha512-z3wufTr1skM03PI6Dr1ZsrvjAiGKf/w0VQvdZL+mEnKNqRA7Q4bhJDGk1+nzs+WWRWz4vS488uad9ERmSclBmg==", + "version": "54.0.8", + "resolved": "https://mirrors.tencent.com/npm/@expo/metro-config/-/metro-config-54.0.8.tgz", + "integrity": "sha512-rCkDQ8IT6sgcGNy48O2cTE4NlazCAgAIsD5qBsNPJLZSS0XbaILvAgGsFt/4nrx0GMGj6iQcOn5ifwV4NssTmw==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", @@ -2053,7 +2049,7 @@ "@expo/config": "~12.0.10", "@expo/env": "~2.0.7", "@expo/json-file": "~10.0.7", - "@expo/metro": "~54.0.0", + "@expo/metro": "~54.1.0", "@expo/spawn-async": "^1.7.2", "browserslist": "^4.25.0", "chalk": "^4.1.0", @@ -2124,6 +2120,308 @@ } } }, + "node_modules/@expo/metro/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://mirrors.tencent.com/npm/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/@expo/metro/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://mirrors.tencent.com/npm/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/@expo/metro/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://mirrors.tencent.com/npm/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, + "node_modules/@expo/metro/node_modules/metro": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro/-/metro-0.83.2.tgz", + "integrity": "sha512-HQgs9H1FyVbRptNSMy/ImchTTE5vS2MSqLoOo7hbDoBq6hPPZokwJvBMwrYSxdjQZmLXz2JFZtdvS+ZfgTc9yw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "@babel/types": "^7.25.2", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.32.0", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.83.2", + "metro-cache": "0.83.2", + "metro-cache-key": "0.83.2", + "metro-config": "0.83.2", + "metro-core": "0.83.2", + "metro-file-map": "0.83.2", + "metro-resolver": "0.83.2", + "metro-runtime": "0.83.2", + "metro-source-map": "0.83.2", + "metro-symbolicate": "0.83.2", + "metro-transform-plugins": "0.83.2", + "metro-transform-worker": "0.83.2", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-babel-transformer": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-babel-transformer/-/metro-babel-transformer-0.83.2.tgz", + "integrity": "sha512-rirY1QMFlA1uxH3ZiNauBninwTioOgwChnRdDcbB4tgRZ+bGX9DiXoh9QdpppiaVKXdJsII932OwWXGGV4+Nlw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.32.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-cache": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-cache/-/metro-cache-0.83.2.tgz", + "integrity": "sha512-Z43IodutUZeIS7OTH+yQFjc59QlFJ6s5OvM8p2AP9alr0+F8UKr8ADzFzoGKoHefZSKGa4bJx7MZJLF6GwPDHQ==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.83.2" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-cache-key": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-cache-key/-/metro-cache-key-0.83.2.tgz", + "integrity": "sha512-3EMG/GkGKYoTaf5RqguGLSWRqGTwO7NQ0qXKmNBjr0y6qD9s3VBXYlwB+MszGtmOKsqE9q3FPrE5Nd9Ipv7rZw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-config": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-config/-/metro-config-0.83.2.tgz", + "integrity": "sha512-1FjCcdBe3e3D08gSSiU9u3Vtxd7alGH3x/DNFqWDFf5NouX4kLgbVloDDClr1UrLz62c0fHh2Vfr9ecmrOZp+g==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.83.2", + "metro-cache": "0.83.2", + "metro-core": "0.83.2", + "metro-runtime": "0.83.2", + "yaml": "^2.6.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-core": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-core/-/metro-core-0.83.2.tgz", + "integrity": "sha512-8DRb0O82Br0IW77cNgKMLYWUkx48lWxUkvNUxVISyMkcNwE/9ywf1MYQUE88HaKwSrqne6kFgCSA/UWZoUT0Iw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.83.2" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-file-map": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-file-map/-/metro-file-map-0.83.2.tgz", + "integrity": "sha512-cMSWnEqZrp/dzZIEd7DEDdk72PXz6w5NOKriJoDN9p1TDQ5nAYrY2lHi8d6mwbcGLoSlWmpPyny9HZYFfPWcGQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-minify-terser": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-minify-terser/-/metro-minify-terser-0.83.2.tgz", + "integrity": "sha512-zvIxnh7U0JQ7vT4quasKsijId3dOAWgq+ip2jF/8TMrPUqQabGrs04L2dd0haQJ+PA+d4VvK/bPOY8X/vL2PWw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-resolver": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-resolver/-/metro-resolver-0.83.2.tgz", + "integrity": "sha512-Yf5mjyuiRE/Y+KvqfsZxrbHDA15NZxyfg8pIk0qg47LfAJhpMVEX+36e6ZRBq7KVBqy6VDX5Sq55iHGM4xSm7Q==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-runtime": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-runtime/-/metro-runtime-0.83.2.tgz", + "integrity": "sha512-nnsPtgRvFbNKwemqs0FuyFDzXLl+ezuFsUXDbX8o0SXOfsOPijqiQrf3kuafO1Zx1aUWf4NOrKJMAQP5EEHg9A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-source-map": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-source-map/-/metro-source-map-0.83.2.tgz", + "integrity": "sha512-5FL/6BSQvshIKjXOennt9upFngq2lFvDakZn5LfauIVq8+L4sxXewIlSTcxAtzbtjAIaXeOSVMtCJ5DdfCt9AA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.83.2", + "nullthrows": "^1.1.1", + "ob1": "0.83.2", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-symbolicate": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-symbolicate/-/metro-symbolicate-0.83.2.tgz", + "integrity": "sha512-KoU9BLwxxED6n33KYuQQuc5bXkIxF3fSwlc3ouxrrdLWwhu64muYZNQrukkWzhVKRNFIXW7X2iM8JXpi2heIPw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.83.2", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-transform-plugins": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-transform-plugins/-/metro-transform-plugins-0.83.2.tgz", + "integrity": "sha512-5WlW25WKPkiJk2yA9d8bMuZrgW7vfA4f4MBb9ZeHbTB3eIAoNN8vS8NENgG/X/90vpTB06X66OBvxhT3nHwP6A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/metro-transform-worker": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/metro-transform-worker/-/metro-transform-worker-0.83.2.tgz", + "integrity": "sha512-G5DsIg+cMZ2KNfrdLnWMvtppb3+Rp1GMyj7Bvd9GgYc/8gRmvq1XVEF9XuO87Shhb03kFhGqMTgZerz3hZ1v4Q==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "metro": "0.83.2", + "metro-babel-transformer": "0.83.2", + "metro-cache": "0.83.2", + "metro-cache-key": "0.83.2", + "metro-minify-terser": "0.83.2", + "metro-source-map": "0.83.2", + "metro-transform-plugins": "0.83.2", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=20.19.4" + } + }, + "node_modules/@expo/metro/node_modules/ob1": { + "version": "0.83.2", + "resolved": "https://mirrors.tencent.com/npm/ob1/-/ob1-0.83.2.tgz", + "integrity": "sha512-XlK3w4M+dwd1g1gvHzVbxiXEbUllRONEgcF2uEO0zm4nxa0eKlh41c6N65q1xbiDOeKKda1tvNOAD33fNjyvCg==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=20.19.4" + } + }, "node_modules/@expo/osascript": { "version": "2.3.7", "resolved": "https://mirrors.tencent.com/npm/@expo/osascript/-/osascript-2.3.7.tgz", @@ -2163,9 +2461,9 @@ } }, "node_modules/@expo/prebuild-config": { - "version": "54.0.5", - "resolved": "https://mirrors.tencent.com/npm/@expo/prebuild-config/-/prebuild-config-54.0.5.tgz", - "integrity": "sha512-eCvbVUf01j1nSrs4mG/rWwY+SfgE30LM6JcElLrnNgNnaDWzt09E/c8n3ZeTLNKENwJaQQ1KIn2VE461/4VnWQ==", + "version": "54.0.6", + "resolved": "https://mirrors.tencent.com/npm/@expo/prebuild-config/-/prebuild-config-54.0.6.tgz", + "integrity": "sha512-xowuMmyPNy+WTNq+YX0m0EFO/Knc68swjThk4dKivgZa8zI1UjvFXOBIOp8RX4ljCXLzwxQJM5oBBTvyn+59ZA==", "license": "MIT", "dependencies": { "@expo/config": "~12.0.10", @@ -2173,7 +2471,7 @@ "@expo/config-types": "^54.0.8", "@expo/image-utils": "^0.8.7", "@expo/json-file": "^10.0.7", - "@react-native/normalize-colors": "0.81.4", + "@react-native/normalize-colors": "0.81.5", "debug": "^4.3.1", "resolve-from": "^5.0.0", "semver": "^7.6.0", @@ -2240,9 +2538,9 @@ } }, "node_modules/@expo/vector-icons": { - "version": "15.0.2", - "resolved": "https://mirrors.tencent.com/npm/@expo/vector-icons/-/vector-icons-15.0.2.tgz", - "integrity": "sha512-IiBjg7ZikueuHNf40wSGCf0zS73a3guJLdZzKnDUxsauB8VWPLMeWnRIupc+7cFhLUkqyvyo0jLNlcxG5xPOuQ==", + "version": "15.0.3", + "resolved": "https://mirrors.tencent.com/npm/@expo/vector-icons/-/vector-icons-15.0.3.tgz", + "integrity": "sha512-SBUyYKphmlfUBqxSfDdJ3jAdEVSALS2VUPOUyqn48oZmb2TL/O7t7/PQm5v4NQujYEPLPMTLn9KVw6H7twwbTA==", "license": "MIT", "peerDependencies": { "expo-font": ">=14.0.4", @@ -2275,7 +2573,6 @@ "version": "7.10.4", "resolved": "https://mirrors.tencent.com/npm/@babel/code-frame/-/code-frame-7.10.4.tgz", "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "license": "MIT", "dependencies": { "@babel/highlight": "^7.10.4" } @@ -3240,31 +3537,31 @@ } }, "node_modules/@react-native/assets-registry": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/assets-registry/-/assets-registry-0.81.4.tgz", - "integrity": "sha512-AMcDadefBIjD10BRqkWw+W/VdvXEomR6aEZ0fhQRAv7igrBzb4PTn4vHKYg+sUK0e3wa74kcMy2DLc/HtnGcMA==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", + "integrity": "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w==", "license": "MIT", "engines": { "node": ">= 20.19.4" } }, "node_modules/@react-native/babel-plugin-codegen": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.81.4.tgz", - "integrity": "sha512-6ztXf2Tl2iWznyI/Da/N2Eqymt0Mnn69GCLnEFxFbNdk0HxHPZBNWU9shTXhsLWOL7HATSqwg/bB1+3kY1q+mA==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.81.5.tgz", + "integrity": "sha512-oF71cIH6je3fSLi6VPjjC3Sgyyn57JLHXs+mHWc9MoCiJJcM4nqsS5J38zv1XQ8d3zOW2JtHro+LF0tagj2bfQ==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.3", - "@react-native/codegen": "0.81.4" + "@react-native/codegen": "0.81.5" }, "engines": { "node": ">= 20.19.4" } }, "node_modules/@react-native/babel-preset": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/babel-preset/-/babel-preset-0.81.4.tgz", - "integrity": "sha512-VYj0c/cTjQJn/RJ5G6P0L9wuYSbU9yGbPYDHCKstlQZQWkk+L9V8ZDbxdJBTIei9Xl3KPQ1odQ4QaeW+4v+AZg==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/babel-preset/-/babel-preset-0.81.5.tgz", + "integrity": "sha512-UoI/x/5tCmi+pZ3c1+Ypr1DaRMDLI3y+Q70pVLLVgrnC3DHsHRIbHcCHIeG/IJvoeFqFM2sTdhSOLJrf8lOPrA==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -3308,7 +3605,7 @@ "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", - "@react-native/babel-plugin-codegen": "0.81.4", + "@react-native/babel-plugin-codegen": "0.81.5", "babel-plugin-syntax-hermes-parser": "0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" @@ -3321,9 +3618,9 @@ } }, "node_modules/@react-native/codegen": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/codegen/-/codegen-0.81.4.tgz", - "integrity": "sha512-LWTGUTzFu+qOQnvkzBP52B90Ym3stZT8IFCzzUrppz8Iwglg83FCtDZAR4yLHI29VY/x/+pkcWAMCl3739XHdw==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/codegen/-/codegen-0.81.5.tgz", + "integrity": "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -3346,7 +3643,6 @@ "resolved": "https://mirrors.tencent.com/npm/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3363,12 +3659,12 @@ } }, "node_modules/@react-native/community-cli-plugin": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/community-cli-plugin/-/community-cli-plugin-0.81.4.tgz", - "integrity": "sha512-8mpnvfcLcnVh+t1ok6V9eozWo8Ut+TZhz8ylJ6gF9d6q9EGDQX6s8jenan5Yv/pzN4vQEKI4ib2pTf/FELw+SA==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/community-cli-plugin/-/community-cli-plugin-0.81.5.tgz", + "integrity": "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw==", "license": "MIT", "dependencies": { - "@react-native/dev-middleware": "0.81.4", + "@react-native/dev-middleware": "0.81.5", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", @@ -3396,7 +3692,6 @@ "version": "7.7.3", "resolved": "https://mirrors.tencent.com/npm/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -3405,22 +3700,22 @@ } }, "node_modules/@react-native/debugger-frontend": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/debugger-frontend/-/debugger-frontend-0.81.4.tgz", - "integrity": "sha512-SU05w1wD0nKdQFcuNC9D6De0ITnINCi8MEnx9RsTD2e4wN83ukoC7FpXaPCYyP6+VjFt5tUKDPgP1O7iaNXCqg==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/debugger-frontend/-/debugger-frontend-0.81.5.tgz", + "integrity": "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w==", "license": "BSD-3-Clause", "engines": { "node": ">= 20.19.4" } }, "node_modules/@react-native/dev-middleware": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/dev-middleware/-/dev-middleware-0.81.4.tgz", - "integrity": "sha512-hu1Wu5R28FT7nHXs2wWXvQ++7W7zq5GPY83llajgPlYKznyPLAY/7bArc5rAzNB7b0kwnlaoPQKlvD/VP9LZug==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/dev-middleware/-/dev-middleware-0.81.5.tgz", + "integrity": "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA==", "license": "MIT", "dependencies": { "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.81.4", + "@react-native/debugger-frontend": "0.81.5", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", @@ -3445,18 +3740,18 @@ } }, "node_modules/@react-native/gradle-plugin": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/gradle-plugin/-/gradle-plugin-0.81.4.tgz", - "integrity": "sha512-T7fPcQvDDCSusZFVSg6H1oVDKb/NnVYLnsqkcHsAF2C2KGXyo3J7slH/tJAwNfj/7EOA2OgcWxfC1frgn9TQvw==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz", + "integrity": "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg==", "license": "MIT", "engines": { "node": ">= 20.19.4" } }, "node_modules/@react-native/js-polyfills": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/js-polyfills/-/js-polyfills-0.81.4.tgz", - "integrity": "sha512-sr42FaypKXJHMVHhgSbu2f/ZJfrLzgaoQ+HdpRvKEiEh2mhFf6XzZwecyLBvWqf2pMPZa+CpPfNPiejXjKEy8w==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/js-polyfills/-/js-polyfills-0.81.5.tgz", + "integrity": "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==", "license": "MIT", "engines": { "node": ">= 20.19.4" @@ -3469,9 +3764,9 @@ "license": "MIT" }, "node_modules/@react-native/normalize-colors": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/normalize-colors/-/normalize-colors-0.81.4.tgz", - "integrity": "sha512-9nRRHO1H+tcFqjb9gAM105Urtgcanbta2tuqCVY0NATHeFPDEAB7gPyiLxCHKMi1NbhP6TH0kxgSWXKZl1cyRg==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", + "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", "license": "MIT" }, "node_modules/@react-native/virtualized-lists": { @@ -5056,9 +5351,9 @@ } }, "node_modules/babel-plugin-react-native-web": { - "version": "0.21.1", - "resolved": "https://mirrors.tencent.com/npm/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.1.tgz", - "integrity": "sha512-7XywfJ5QIRMwjOL+pwJt2w47Jmi5fFLvK7/So4fV4jIN6PcRbylCp9/l3cJY4VJbSz3lnWTeHDTD1LKIc1C09Q==", + "version": "0.21.2", + "resolved": "https://mirrors.tencent.com/npm/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.2.tgz", + "integrity": "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==", "license": "MIT" }, "node_modules/babel-plugin-syntax-hermes-parser": { @@ -5106,9 +5401,9 @@ } }, "node_modules/babel-preset-expo": { - "version": "54.0.4", - "resolved": "https://mirrors.tencent.com/npm/babel-preset-expo/-/babel-preset-expo-54.0.4.tgz", - "integrity": "sha512-0/1/xh2m/G4FSvIbJYcu5TGPfDrHRqmIDoAFm6zWSEuWyCDagZ8gjjTTJqxdNJHvsKQl65PzeXd6Q5k6tF57wA==", + "version": "54.0.6", + "resolved": "https://mirrors.tencent.com/npm/babel-preset-expo/-/babel-preset-expo-54.0.6.tgz", + "integrity": "sha512-GxJfwnuOPQJbzDe5WASJZdNQiukLw7i9z+Lh6JQWkUHXsShHyQrqgiKE55MD/KaP9VqJ70yZm7bYqOu8zwcWqQ==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -5126,7 +5421,7 @@ "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", - "@react-native/babel-preset": "0.81.4", + "@react-native/babel-preset": "0.81.5", "babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.29.1", @@ -5229,7 +5524,6 @@ "version": "8.4.2", "resolved": "https://mirrors.tencent.com/npm/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -5427,39 +5721,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "license": "MIT", - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-callsite/node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "license": "MIT", - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5679,7 +5940,6 @@ "version": "1.0.4", "resolved": "https://mirrors.tencent.com/npm/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "license": "MIT", "engines": { "node": ">=0.8" } @@ -5729,7 +5989,6 @@ "version": "7.2.0", "resolved": "https://mirrors.tencent.com/npm/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", "engines": { "node": ">= 10" } @@ -5768,7 +6027,6 @@ "version": "2.6.9", "resolved": "https://mirrors.tencent.com/npm/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -5843,65 +6101,6 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://mirrors.tencent.com/npm/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "license": "MIT", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cosmiconfig/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://mirrors.tencent.com/npm/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/cosmiconfig/node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://mirrors.tencent.com/npm/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", - "license": "MIT", - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://mirrors.tencent.com/npm/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/cosmiconfig/node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://mirrors.tencent.com/npm/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/cross-fetch": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", @@ -6116,7 +6315,6 @@ "version": "0.6.0", "resolved": "https://mirrors.tencent.com/npm/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -6141,7 +6339,6 @@ "version": "1.0.4", "resolved": "https://mirrors.tencent.com/npm/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -6170,7 +6367,6 @@ "version": "2.0.0", "resolved": "https://mirrors.tencent.com/npm/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "license": "MIT", "engines": { "node": ">=8" } @@ -6400,15 +6596,6 @@ "node": ">=8" } }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://mirrors.tencent.com/npm/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, "node_modules/error-stack-parser": { "version": "2.1.4", "resolved": "https://mirrors.tencent.com/npm/error-stack-parser/-/error-stack-parser-2.1.4.tgz", @@ -7056,29 +7243,29 @@ "license": "MIT" }, "node_modules/expo": { - "version": "54.0.13", - "resolved": "https://mirrors.tencent.com/npm/expo/-/expo-54.0.13.tgz", - "integrity": "sha512-F1puKXzw8ESnsbvaKdXtcIiyYLQ2kUHqP8LuhgtJS1wm6w55VhtOPg8yl/0i8kPbTA0YfD+KYdXjSfhPXgUPxw==", + "version": "54.0.21", + "resolved": "https://mirrors.tencent.com/npm/expo/-/expo-54.0.21.tgz", + "integrity": "sha512-I3kzMNW/43a71pt6hT0Zebd2zAPIMMeucUDDEdfUKYrzzTRwISZfVAv0dp8GWKHHDjZsy+FjE4RQCMdyKmiDeQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "54.0.11", + "@expo/cli": "54.0.14", "@expo/config": "~12.0.10", "@expo/config-plugins": "~54.0.2", "@expo/devtools": "0.1.7", - "@expo/fingerprint": "0.15.1", - "@expo/metro": "~54.0.0", - "@expo/metro-config": "54.0.6", - "@expo/vector-icons": "^15.0.2", + "@expo/fingerprint": "0.15.2", + "@expo/metro": "~54.1.0", + "@expo/metro-config": "54.0.8", + "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~54.0.3", + "babel-preset-expo": "~54.0.6", "expo-asset": "~12.0.9", - "expo-constants": "~18.0.9", + "expo-constants": "~18.0.10", "expo-file-system": "~19.0.17", "expo-font": "~14.0.9", "expo-keep-awake": "~15.0.7", - "expo-modules-autolinking": "3.0.15", - "expo-modules-core": "3.0.21", + "expo-modules-autolinking": "3.0.19", + "expo-modules-core": "3.0.23", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" @@ -7185,12 +7372,12 @@ } }, "node_modules/expo-constants": { - "version": "18.0.9", - "resolved": "https://mirrors.tencent.com/npm/expo-constants/-/expo-constants-18.0.9.tgz", - "integrity": "sha512-sqoXHAOGDcr+M9NlXzj1tGoZyd3zxYDy215W6E0Z0n8fgBaqce9FAYQE2bu5X4G629AYig5go7U6sQz7Pjcm8A==", + "version": "18.0.10", + "resolved": "https://mirrors.tencent.com/npm/expo-constants/-/expo-constants-18.0.10.tgz", + "integrity": "sha512-Rhtv+X974k0Cahmvx6p7ER5+pNhBC0XbP1lRviL2J1Xl4sT2FBaIuIxF/0I0CbhOsySf0ksqc5caFweAy9Ewiw==", "license": "MIT", "dependencies": { - "@expo/config": "~12.0.9", + "@expo/config": "~12.0.10", "@expo/env": "~2.0.7" }, "peerDependencies": { @@ -7223,9 +7410,9 @@ } }, "node_modules/expo-glass-effect": { - "version": "0.1.4", - "resolved": "https://mirrors.tencent.com/npm/expo-glass-effect/-/expo-glass-effect-0.1.4.tgz", - "integrity": "sha512-RW7lf2SWNVSvpJqBxQUlC/VVzeeHFrJeoKoIlNIFfKTFj3HyF7xQKq6/h/bpO8M0ssy0v5KEKw4GggkjTwx7Fw==", + "version": "0.1.5", + "resolved": "https://mirrors.tencent.com/npm/expo-glass-effect/-/expo-glass-effect-0.1.5.tgz", + "integrity": "sha512-DnleHtTpWET89I4GQsr4PDDvesKFA4miX+xV+1+ko5Z6SHkanBHD8gAOnvf07wTanzm4e8dAf0/abu7JmZlZIA==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7243,9 +7430,9 @@ } }, "node_modules/expo-image": { - "version": "3.0.9", - "resolved": "https://mirrors.tencent.com/npm/expo-image/-/expo-image-3.0.9.tgz", - "integrity": "sha512-GkPIjeqrODMBdpbRWOzbwiq8ztxjgq1rdZrnqwt/pzQavgXPlr4rW/7aigue9Jm5t5vebhMNAuc1A/XIXXqpcA==", + "version": "3.0.10", + "resolved": "https://mirrors.tencent.com/npm/expo-image/-/expo-image-3.0.10.tgz", + "integrity": "sha512-i4qNCEf9Ur7vDqdfDdFfWnNCAF2efDTdahuDy9iELPS2nzMKBLeeGA2KxYEPuRylGCS96Rwm+SOZJu6INc2ADQ==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -7326,9 +7513,9 @@ } }, "node_modules/expo-modules-autolinking": { - "version": "3.0.15", - "resolved": "https://mirrors.tencent.com/npm/expo-modules-autolinking/-/expo-modules-autolinking-3.0.15.tgz", - "integrity": "sha512-B6c+x664ImrWd+PknEy5454gtY6P0cMxj4P50fvLYP4HimbYj9SzwoHqZ/Rxh9NwxnUkT2nappk/USYIcPoS/A==", + "version": "3.0.19", + "resolved": "https://mirrors.tencent.com/npm/expo-modules-autolinking/-/expo-modules-autolinking-3.0.19.tgz", + "integrity": "sha512-tSMYGnfZmAaN77X8iMLiaSgbCFnA7eh6s2ac09J2N2N0Rcf2RCE27jg0c0XenTMTWUcM4QvLhsNHof/WtlKqPw==", "license": "MIT", "dependencies": { "@expo/spawn-async": "^1.7.2", @@ -7343,9 +7530,9 @@ } }, "node_modules/expo-modules-core": { - "version": "3.0.21", - "resolved": "https://mirrors.tencent.com/npm/expo-modules-core/-/expo-modules-core-3.0.21.tgz", - "integrity": "sha512-KJRzm0FEt/lfPNG+C6UUq+ta9PO10QPwY1HGCNkzPiRCIMJmQP4xRYK4Z7AxiYEYsPqr5OdjRW55kGZ4c5pzgA==", + "version": "3.0.23", + "resolved": "https://mirrors.tencent.com/npm/expo-modules-core/-/expo-modules-core-3.0.23.tgz", + "integrity": "sha512-NYHi5LK/cdIyOjK9ZQAgfDPCOqER26cIbU3gzsce7YdnsmlNFR0qMfWOj9zAmaFBviC2kCkCOmitwk4357Td3Q==", "license": "MIT", "dependencies": { "invariant": "^2.2.4" @@ -7390,9 +7577,9 @@ } }, "node_modules/expo-router": { - "version": "6.0.12", - "resolved": "https://mirrors.tencent.com/npm/expo-router/-/expo-router-6.0.12.tgz", - "integrity": "sha512-GBfMHAbHoPv7aCfHOEgFNxcadw4euPyI/SqHNNtw+Sm+JtvauHP34wi7Bg25JxatHQ8EdhxAj6w0D8D6QRnayg==", + "version": "6.0.14", + "resolved": "https://mirrors.tencent.com/npm/expo-router/-/expo-router-6.0.14.tgz", + "integrity": "sha512-vizLO4SgnMEL+PPs2dXr+etEOuksjue7yUQBCtfCEdqoDkQlB0r35zI7rS34Wt53sxKWSlM2p+038qQEpxtiFw==", "license": "MIT", "dependencies": { "@expo/metro-runtime": "^6.1.2", @@ -7405,7 +7592,7 @@ "client-only": "^0.0.1", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "expo-server": "^1.0.1", + "expo-server": "^1.0.3", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", @@ -7424,7 +7611,7 @@ "@react-navigation/drawer": "^7.5.0", "@testing-library/react-native": ">= 12.0.0", "expo": "*", - "expo-constants": "^18.0.9", + "expo-constants": "^18.0.10", "expo-linking": "^8.0.8", "react": "*", "react-dom": "*", @@ -7643,9 +7830,9 @@ } }, "node_modules/expo-server": { - "version": "1.0.1", - "resolved": "https://mirrors.tencent.com/npm/expo-server/-/expo-server-1.0.1.tgz", - "integrity": "sha512-J3JlpzNXOkkr4BbapTrcv6klBQcw6NzrBBVIU7qkNE2eU3U1on9rp27wi0+cihjG/QgxSIqQVkrga5z3HWnH0A==", + "version": "1.0.3", + "resolved": "https://mirrors.tencent.com/npm/expo-server/-/expo-server-1.0.3.tgz", + "integrity": "sha512-SOwdzM/BFAL+vTFlUDJG6ljhyk6TyTl+LRK3ubGmN+Pf18ENRqKj37U8krc5vH926sAsB3IFcE8kJEYf4dG7PA==", "license": "MIT", "engines": { "node": ">=20.16.0" @@ -7704,12 +7891,12 @@ } }, "node_modules/expo-system-ui": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-6.0.7.tgz", - "integrity": "sha512-NT+/r/BOg08lFI9SZO2WFi9X1ZmawkVStknioWzQq6Mt4KinoMS6yl3eLbyOLM3LoptN13Ywfo4W5KHA6TV9Ow==", + "version": "6.0.8", + "resolved": "https://mirrors.tencent.com/npm/expo-system-ui/-/expo-system-ui-6.0.8.tgz", + "integrity": "sha512-DzJYqG2fibBSLzPDL4BybGCiilYOtnI1OWhcYFwoM4k0pnEzMBt1Vj8Z67bXglDDuz2HCQPGNtB3tQft5saKqQ==", "license": "MIT", "dependencies": { - "@react-native/normalize-colors": "0.81.4", + "@react-native/normalize-colors": "0.81.5", "debug": "^4.3.2" }, "peerDependencies": { @@ -7724,9 +7911,9 @@ } }, "node_modules/expo-task-manager": { - "version": "14.0.7", - "resolved": "https://mirrors.tencent.com/npm/expo-task-manager/-/expo-task-manager-14.0.7.tgz", - "integrity": "sha512-wZRksJg4+Me1wDYmv0wnGh5I30ZOkEpjdXECp/cTKbON1ISQgnaz+4B2eJtljvEPYC1ocBdpAGmz9N0CPtc4mg==", + "version": "14.0.8", + "resolved": "https://mirrors.tencent.com/npm/expo-task-manager/-/expo-task-manager-14.0.8.tgz", + "integrity": "sha512-HxhyvmulM8px+LQvqIKS85KVx2UodZf5RO+FE2ltpC4mQ5IFkX/ESqiK0grzDa4pVFLyxvs8LjuUKsfB5c39PQ==", "license": "MIT", "dependencies": { "unimodules-app-loader": "~6.0.7" @@ -7747,9 +7934,9 @@ } }, "node_modules/expo/node_modules/@expo/cli": { - "version": "54.0.11", - "resolved": "https://mirrors.tencent.com/npm/@expo/cli/-/cli-54.0.11.tgz", - "integrity": "sha512-ik9p8+JTOuVXS462+vFPV0qnWRBXIR1bPmoVKO8xQWw6Yk+K6UlU2GrM2ch7kA3JlSJE/MGsNyN8CB0zFZbVbQ==", + "version": "54.0.14", + "resolved": "https://mirrors.tencent.com/npm/@expo/cli/-/cli-54.0.14.tgz", + "integrity": "sha512-M7QW/GHx1FJg+CGgChGKerYXmCGWDskJ8S6w+8m49IBZ41CMDeWRH5snQkFoGCttF8WnzhGiX+nu69AFnEuDHQ==", "license": "MIT", "dependencies": { "@0no-co/graphql.web": "^1.0.8", @@ -7761,17 +7948,17 @@ "@expo/image-utils": "^0.8.7", "@expo/json-file": "^10.0.7", "@expo/mcp-tunnel": "~0.0.7", - "@expo/metro": "~54.0.0", - "@expo/metro-config": "~54.0.6", + "@expo/metro": "~54.1.0", + "@expo/metro-config": "~54.0.8", "@expo/osascript": "^2.3.7", "@expo/package-manager": "^1.9.8", "@expo/plist": "^0.4.7", - "@expo/prebuild-config": "^54.0.5", + "@expo/prebuild-config": "^54.0.6", "@expo/schema-utils": "^0.1.7", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", - "@react-native/dev-middleware": "0.81.4", + "@react-native/dev-middleware": "0.81.5", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", @@ -7785,7 +7972,7 @@ "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", - "expo-server": "^1.0.1", + "expo-server": "^1.0.3", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^10.4.2", @@ -7861,7 +8048,6 @@ "version": "7.7.3", "resolved": "https://mirrors.tencent.com/npm/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -8635,8 +8821,7 @@ "node_modules/hosted-git-info/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://mirrors.tencent.com/npm/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/html2canvas": { "version": "1.4.1", @@ -8957,12 +9142,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://mirrors.tencent.com/npm/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "license": "MIT" - }, "node_modules/is-async-function": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", @@ -9101,15 +9280,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://mirrors.tencent.com/npm/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://mirrors.tencent.com/npm/is-docker/-/is-docker-2.2.1.tgz", @@ -9725,12 +9895,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://mirrors.tencent.com/npm/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "license": "MIT" - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -9926,7 +10090,6 @@ "cpu": [ "arm64" ], - "license": "MPL-2.0", "optional": true, "os": [ "darwin" @@ -10046,7 +10209,6 @@ "cpu": [ "x64" ], - "license": "MPL-2.0", "optional": true, "os": [ "linux" @@ -10086,7 +10248,6 @@ "cpu": [ "arm64" ], - "license": "MPL-2.0", "optional": true, "os": [ "win32" @@ -10178,7 +10339,6 @@ "version": "2.2.0", "resolved": "https://mirrors.tencent.com/npm/log-symbols/-/log-symbols-2.2.0.tgz", "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "license": "MIT", "dependencies": { "chalk": "^2.0.1" }, @@ -10190,7 +10350,6 @@ "version": "3.2.1", "resolved": "https://mirrors.tencent.com/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -10216,7 +10375,6 @@ "version": "1.9.3", "resolved": "https://mirrors.tencent.com/npm/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -10224,8 +10382,7 @@ "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.3", "resolved": "https://mirrors.tencent.com/npm/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/log-symbols/node_modules/escape-string-regexp": { "version": "1.0.5", @@ -10240,7 +10397,6 @@ "version": "3.0.0", "resolved": "https://mirrors.tencent.com/npm/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", "engines": { "node": ">=4" } @@ -10249,7 +10405,6 @@ "version": "5.5.0", "resolved": "https://mirrors.tencent.com/npm/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -10398,9 +10553,9 @@ } }, "node_modules/metro": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro/-/metro-0.83.1.tgz", - "integrity": "sha512-UGKepmTxoGD4HkQV8YWvpvwef7fUujNtTgG4Ygf7m/M0qjvb9VuDmAsEU+UdriRX7F61pnVK/opz89hjKlYTXA==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro/-/metro-0.83.3.tgz", + "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.24.7", @@ -10418,24 +10573,24 @@ "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", - "hermes-parser": "0.29.1", + "hermes-parser": "0.32.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.83.1", - "metro-cache": "0.83.1", - "metro-cache-key": "0.83.1", - "metro-config": "0.83.1", - "metro-core": "0.83.1", - "metro-file-map": "0.83.1", - "metro-resolver": "0.83.1", - "metro-runtime": "0.83.1", - "metro-source-map": "0.83.1", - "metro-symbolicate": "0.83.1", - "metro-transform-plugins": "0.83.1", - "metro-transform-worker": "0.83.1", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-config": "0.83.3", + "metro-core": "0.83.3", + "metro-file-map": "0.83.3", + "metro-resolver": "0.83.3", + "metro-runtime": "0.83.3", + "metro-source-map": "0.83.3", + "metro-symbolicate": "0.83.3", + "metro-transform-plugins": "0.83.3", + "metro-transform-worker": "0.83.3", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", @@ -10452,39 +10607,54 @@ } }, "node_modules/metro-babel-transformer": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-babel-transformer/-/metro-babel-transformer-0.83.1.tgz", - "integrity": "sha512-r3xAD3964E8dwDBaZNSO2aIIvWXjIK80uO2xo0/pi3WI8XWT9h5SCjtGWtMtE5PRWw+t20TN0q1WMRsjvhC1rQ==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz", + "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.29.1", + "hermes-parser": "0.32.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">=20.19.4" } }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://mirrors.tencent.com/npm/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://mirrors.tencent.com/npm/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, "node_modules/metro-cache": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-cache/-/metro-cache-0.83.1.tgz", - "integrity": "sha512-7N/Ad1PHa1YMWDNiyynTPq34Op2qIE68NWryGEQ4TSE3Zy6a8GpsYnEEZE4Qi6aHgsE+yZHKkRczeBgxhnFIxQ==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-cache/-/metro-cache-0.83.3.tgz", + "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==", "license": "MIT", "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", - "metro-core": "0.83.1" + "metro-core": "0.83.3" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-cache-key": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-cache-key/-/metro-cache-key-0.83.1.tgz", - "integrity": "sha512-ZUs+GD5CNeDLxx5UUWmfg26IL+Dnbryd+TLqTlZnDEgehkIa11kUSvgF92OFfJhONeXzV4rZDRGNXoo6JT+8Gg==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-cache-key/-/metro-cache-key-0.83.3.tgz", + "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -10494,42 +10664,42 @@ } }, "node_modules/metro-config": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-config/-/metro-config-0.83.1.tgz", - "integrity": "sha512-HJhpZx3wyOkux/jeF1o7akFJzZFdbn6Zf7UQqWrvp7gqFqNulQ8Mju09raBgPmmSxKDl4LbbNeigkX0/nKY1QA==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-config/-/metro-config-0.83.3.tgz", + "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==", "license": "MIT", "dependencies": { "connect": "^3.6.5", - "cosmiconfig": "^5.0.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", - "metro": "0.83.1", - "metro-cache": "0.83.1", - "metro-core": "0.83.1", - "metro-runtime": "0.83.1" + "metro": "0.83.3", + "metro-cache": "0.83.3", + "metro-core": "0.83.3", + "metro-runtime": "0.83.3", + "yaml": "^2.6.1" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-core": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-core/-/metro-core-0.83.1.tgz", - "integrity": "sha512-uVL1eAJcMFd2o2Q7dsbpg8COaxjZBBGaXqO2OHnivpCdfanraVL8dPmY6It9ZeqWLOihUKZ2yHW4b6soVCzH/Q==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-core/-/metro-core-0.83.3.tgz", + "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.83.1" + "metro-resolver": "0.83.3" }, "engines": { "node": ">=20.19.4" } }, "node_modules/metro-file-map": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-file-map/-/metro-file-map-0.83.1.tgz", - "integrity": "sha512-Yu429lnexKl44PttKw3nhqgmpBR+6UQ/tRaYcxPeEShtcza9DWakCn7cjqDTQZtWR2A8xSNv139izJMyQ4CG+w==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-file-map/-/metro-file-map-0.83.3.tgz", + "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -10547,9 +10717,9 @@ } }, "node_modules/metro-minify-terser": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-minify-terser/-/metro-minify-terser-0.83.1.tgz", - "integrity": "sha512-kmooOxXLvKVxkh80IVSYO4weBdJDhCpg5NSPkjzzAnPJP43u6+usGXobkTWxxrAlq900bhzqKek4pBsUchlX6A==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz", + "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", @@ -10560,9 +10730,9 @@ } }, "node_modules/metro-resolver": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-resolver/-/metro-resolver-0.83.1.tgz", - "integrity": "sha512-t8j46kiILAqqFS5RNa+xpQyVjULxRxlvMidqUswPEk5nQVNdlJslqizDm/Et3v/JKwOtQGkYAQCHxP1zGStR/g==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-resolver/-/metro-resolver-0.83.3.tgz", + "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -10572,9 +10742,9 @@ } }, "node_modules/metro-runtime": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-runtime/-/metro-runtime-0.83.1.tgz", - "integrity": "sha512-3Ag8ZS4IwafL/JUKlaeM6/CbkooY+WcVeqdNlBG0m4S0Qz0om3rdFdy1y6fYBpl6AwXJwWeMuXrvZdMuByTcRA==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-runtime/-/metro-runtime-0.83.3.tgz", + "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", @@ -10585,9 +10755,9 @@ } }, "node_modules/metro-source-map": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-source-map/-/metro-source-map-0.83.1.tgz", - "integrity": "sha512-De7Vbeo96fFZ2cqmI0fWwVJbtHIwPZv++LYlWSwzTiCzxBDJORncN0LcT48Vi2UlQLzXJg+/CuTAcy7NBVh69A==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-source-map/-/metro-source-map-0.83.3.tgz", + "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.3", @@ -10595,9 +10765,9 @@ "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-symbolicate": "0.83.1", + "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", - "ob1": "0.83.1", + "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" }, @@ -10606,14 +10776,14 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-symbolicate/-/metro-symbolicate-0.83.1.tgz", - "integrity": "sha512-wPxYkONlq/Sv8Ji7vHEx5OzFouXAMQJjpcPW41ySKMLP/Ir18SsiJK2h4YkdKpYrTS1+0xf8oqF6nxCsT3uWtg==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz", + "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-source-map": "0.83.1", + "metro-source-map": "0.83.3", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" @@ -10626,9 +10796,9 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-transform-plugins/-/metro-transform-plugins-0.83.1.tgz", - "integrity": "sha512-1Y+I8oozXwhuS0qwC+ezaHXBf0jXW4oeYn4X39XWbZt9X2HfjodqY9bH9r6RUTsoiK7S4j8Ni2C91bUC+sktJQ==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz", + "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -10643,9 +10813,9 @@ } }, "node_modules/metro-transform-worker": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/metro-transform-worker/-/metro-transform-worker-0.83.1.tgz", - "integrity": "sha512-owCrhPyUxdLgXEEEAL2b14GWTPZ2zYuab1VQXcfEy0sJE71iciD7fuMcrngoufh7e7UHDZ56q4ktXg8wgiYA1Q==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz", + "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -10653,13 +10823,13 @@ "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", - "metro": "0.83.1", - "metro-babel-transformer": "0.83.1", - "metro-cache": "0.83.1", - "metro-cache-key": "0.83.1", - "metro-minify-terser": "0.83.1", - "metro-source-map": "0.83.1", - "metro-transform-plugins": "0.83.1", + "metro": "0.83.3", + "metro-babel-transformer": "0.83.3", + "metro-cache": "0.83.3", + "metro-cache-key": "0.83.3", + "metro-minify-terser": "0.83.3", + "metro-source-map": "0.83.3", + "metro-transform-plugins": "0.83.3", "nullthrows": "^1.1.1" }, "engines": { @@ -10672,6 +10842,21 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "license": "MIT" }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.32.0", + "resolved": "https://mirrors.tencent.com/npm/hermes-estree/-/hermes-estree-0.32.0.tgz", + "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.32.0", + "resolved": "https://mirrors.tencent.com/npm/hermes-parser/-/hermes-parser-0.32.0.tgz", + "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.32.0" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -10743,7 +10928,6 @@ "version": "1.2.0", "resolved": "https://mirrors.tencent.com/npm/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "license": "MIT", "engines": { "node": ">=4" } @@ -10944,7 +11128,6 @@ "version": "7.7.3", "resolved": "https://mirrors.tencent.com/npm/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -10971,9 +11154,9 @@ "license": "MIT" }, "node_modules/ob1": { - "version": "0.83.1", - "resolved": "https://mirrors.tencent.com/npm/ob1/-/ob1-0.83.1.tgz", - "integrity": "sha512-ngwqewtdUzFyycomdbdIhFLjePPSOt1awKMUXQ0L7iLHgWEPF3DsCerblzjzfAUHaXuvE9ccJymWQ/4PNNqvnQ==", + "version": "0.83.3", + "resolved": "https://mirrors.tencent.com/npm/ob1/-/ob1-0.83.3.tgz", + "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" @@ -11152,7 +11335,6 @@ "version": "2.0.1", "resolved": "https://mirrors.tencent.com/npm/onetime/-/onetime-2.0.1.tgz", "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "license": "MIT", "dependencies": { "mimic-fn": "^1.0.0" }, @@ -11215,7 +11397,6 @@ "version": "4.1.1", "resolved": "https://mirrors.tencent.com/npm/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "license": "MIT", "engines": { "node": ">=6" } @@ -11224,7 +11405,6 @@ "version": "3.2.1", "resolved": "https://mirrors.tencent.com/npm/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -11250,7 +11430,6 @@ "version": "1.9.3", "resolved": "https://mirrors.tencent.com/npm/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -11258,8 +11437,7 @@ "node_modules/ora/node_modules/color-name": { "version": "1.1.3", "resolved": "https://mirrors.tencent.com/npm/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/ora/node_modules/escape-string-regexp": { "version": "1.0.5", @@ -11274,7 +11452,6 @@ "version": "3.0.0", "resolved": "https://mirrors.tencent.com/npm/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", "engines": { "node": ">=4" } @@ -11283,7 +11460,6 @@ "version": "5.2.0", "resolved": "https://mirrors.tencent.com/npm/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "license": "MIT", "dependencies": { "ansi-regex": "^4.1.0" }, @@ -11295,7 +11471,6 @@ "version": "5.5.0", "resolved": "https://mirrors.tencent.com/npm/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -11379,19 +11554,6 @@ "node": ">=6" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://mirrors.tencent.com/npm/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/parse-png": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/parse-png/-/parse-png-2.1.0.tgz", @@ -11776,7 +11938,6 @@ "version": "1.2.8", "resolved": "https://mirrors.tencent.com/npm/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -11791,7 +11952,6 @@ "version": "2.0.1", "resolved": "https://mirrors.tencent.com/npm/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -11852,19 +12012,19 @@ "license": "MIT" }, "node_modules/react-native": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/react-native/-/react-native-0.81.4.tgz", - "integrity": "sha512-bt5bz3A/+Cv46KcjV0VQa+fo7MKxs17RCcpzjftINlen4ZDUl0I6Ut+brQ2FToa5oD0IB0xvQHfmsg2EDqsZdQ==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/react-native/-/react-native-0.81.5.tgz", + "integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==", "license": "MIT", "dependencies": { "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.81.4", - "@react-native/codegen": "0.81.4", - "@react-native/community-cli-plugin": "0.81.4", - "@react-native/gradle-plugin": "0.81.4", - "@react-native/js-polyfills": "0.81.4", - "@react-native/normalize-colors": "0.81.4", - "@react-native/virtualized-lists": "0.81.4", + "@react-native/assets-registry": "0.81.5", + "@react-native/codegen": "0.81.5", + "@react-native/community-cli-plugin": "0.81.5", + "@react-native/gradle-plugin": "0.81.5", + "@react-native/js-polyfills": "0.81.5", + "@react-native/normalize-colors": "0.81.5", + "@react-native/virtualized-lists": "0.81.5", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", @@ -12249,9 +12409,9 @@ } }, "node_modules/react-native/node_modules/@react-native/virtualized-lists": { - "version": "0.81.4", - "resolved": "https://mirrors.tencent.com/npm/@react-native/virtualized-lists/-/virtualized-lists-0.81.4.tgz", - "integrity": "sha512-hBM+rMyL6Wm1Q4f/WpqGsaCojKSNUBqAXLABNGoWm1vabZ7cSnARMxBvA/2vo3hLcoR4v7zDK8tkKm9+O0LjVA==", + "version": "0.81.5", + "resolved": "https://mirrors.tencent.com/npm/@react-native/virtualized-lists/-/virtualized-lists-0.81.5.tgz", + "integrity": "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw==", "license": "MIT", "dependencies": { "invariant": "^2.2.4", @@ -12588,7 +12748,6 @@ "version": "1.7.1", "resolved": "https://mirrors.tencent.com/npm/resolve/-/resolve-1.7.1.tgz", "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "license": "MIT", "dependencies": { "path-parse": "^1.0.5" } @@ -12793,8 +12952,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/safe-push-apply": { "version": "1.0.0", @@ -13721,7 +13879,6 @@ "version": "5.0.0", "resolved": "https://mirrors.tencent.com/npm/yallist/-/yallist-5.0.0.tgz", "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", "engines": { "node": ">=18" } @@ -15037,6 +15194,18 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://mirrors.tencent.com/npm/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index e37e7a7..1aa4d67 100644 --- a/package.json +++ b/package.json @@ -24,35 +24,35 @@ "@sentry/react-native": "~7.2.0", "@types/lodash": "^4.17.20", "dayjs": "^1.11.18", - "expo": "^54.0.13", + "expo": "54.0.21", "expo-apple-authentication": "~8.0.7", "expo-background-task": "~1.0.8", "expo-blur": "~15.0.7", "expo-camera": "~17.0.8", "expo-constants": "~18.0.9", "expo-font": "~14.0.9", - "expo-glass-effect": "^0.1.4", + "expo-glass-effect": "~0.1.5", "expo-haptics": "~15.0.7", - "expo-image": "~3.0.9", + "expo-image": "~3.0.10", "expo-image-picker": "~17.0.8", "expo-linear-gradient": "~15.0.7", "expo-linking": "~8.0.8", "expo-media-library": "^18.2.0", "expo-notifications": "~0.32.12", "expo-quick-actions": "^6.0.0", - "expo-router": "~6.0.12", + "expo-router": "~6.0.14", "expo-splash-screen": "~31.0.10", "expo-sqlite": "^16.0.8", "expo-status-bar": "~3.0.8", "expo-symbols": "~1.0.7", - "expo-system-ui": "~6.0.7", - "expo-task-manager": "~14.0.7", + "expo-system-ui": "~6.0.8", + "expo-task-manager": "~14.0.8", "expo-web-browser": "~15.0.7", "lodash": "^4.17.21", "lottie-react-native": "^7.3.4", "react": "19.1.0", "react-dom": "19.1.0", - "react-native": "0.81.4", + "react-native": "0.81.5", "react-native-chart-kit": "^6.12.0", "react-native-device-info": "^14.0.4", "react-native-gesture-handler": "~2.28.0", diff --git a/services/goalsApi.ts b/services/goalsApi.ts deleted file mode 100644 index c823a89..0000000 --- a/services/goalsApi.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - ApiResponse, - BatchGoalOperationRequest, - BatchGoalOperationResult, - CompleteGoalRequest, - CreateGoalRequest, - GetGoalCompletionsQuery, - GetGoalsQuery, - Goal, - GoalCompletion, - GoalDetailResponse, - GoalListItem, - GoalStats, - PaginatedResponse, - UpdateGoalRequest, -} from '@/types/goals'; -import { api } from './api'; - -// 目标管理API服务 - -/** - * 创建目标 - */ -export const createGoal = async (goalData: CreateGoalRequest): Promise => { - return api.post('/goals', goalData); -}; - -/** - * 获取目标列表 - */ -export const getGoals = async (query: GetGoalsQuery = {}): Promise> => { - const searchParams = new URLSearchParams(); - - Object.entries(query).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - searchParams.append(key, String(value)); - } - }); - - const queryString = searchParams.toString(); - const path = queryString ? `/goals?${queryString}` : '/goals'; - - return api.get>(path); -}; - -/** - * 获取目标详情 - */ -export const getGoalById = async (goalId: string): Promise> => { - return api.get>(`/goals/${goalId}`); -}; - -/** - * 更新目标 - */ -export const updateGoal = async (goalId: string, goalData: UpdateGoalRequest): Promise => { - return api.put(`/goals/${goalId}`, goalData); -}; - -/** - * 删除目标 - */ -export const deleteGoal = async (goalId: string): Promise> => { - return api.delete>(`/goals/${goalId}`); -}; - -/** - * 记录目标完成 - */ -export const completeGoal = async (goalId: string, completionData: CompleteGoalRequest = {}): Promise> => { - return api.post>(`/goals/${goalId}/complete`, completionData); -}; - -/** - * 获取目标完成记录 - */ -export const getGoalCompletions = async ( - goalId: string, - query: GetGoalCompletionsQuery = {} -): Promise>> => { - const searchParams = new URLSearchParams(); - - Object.entries(query).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - searchParams.append(key, String(value)); - } - }); - - const queryString = searchParams.toString(); - const path = queryString ? `/goals/${goalId}/completions?${queryString}` : `/goals/${goalId}/completions`; - - return api.get>>(path); -}; - -/** - * 获取目标统计信息 - */ -export const getGoalStats = async (): Promise> => { - return api.get>('/goals/stats/overview'); -}; - -/** - * 批量操作目标 - */ -export const batchOperateGoals = async (operationData: BatchGoalOperationRequest): Promise> => { - return api.post>('/goals/batch', operationData); -}; - - -// 导出所有API方法 -export const goalsApi = { - createGoal, - getGoals, - getGoalById, - updateGoal, - deleteGoal, - completeGoal, - getGoalCompletions, - getGoalStats, - batchOperateGoals, -}; - -export default goalsApi; \ No newline at end of file diff --git a/services/notifications.ts b/services/notifications.ts index 8cb56a7..d78ebb1 100644 --- a/services/notifications.ts +++ b/services/notifications.ts @@ -526,7 +526,6 @@ export const notificationService = NotificationService.getInstance(); // 预定义的推送通知类型 export const NotificationTypes = { WORKOUT_REMINDER: 'workout_reminder', - GOAL_ACHIEVEMENT: 'goal_achievement', MOOD_CHECKIN: 'mood_checkin', NUTRITION_REMINDER: 'nutrition_reminder', PROGRESS_UPDATE: 'progress_update', @@ -558,17 +557,7 @@ export const sendWorkoutReminder = (title: string, body: string, date?: Date) => } }; -export const sendGoalAchievement = (title: string, body: string) => { - const notification: NotificationData = { - title, - body, - data: { type: NotificationTypes.GOAL_ACHIEVEMENT }, - sound: true, - priority: 'high', - }; - - return notificationService.sendImmediateNotification(notification); -}; +// sendGoalAchievement 函数已删除,因为目标功能已移除 export const sendMoodCheckinReminder = (title: string, body: string, date?: Date) => { const notification: NotificationData = { diff --git a/services/tasksApi.ts b/services/tasksApi.ts deleted file mode 100644 index 5895681..0000000 --- a/services/tasksApi.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { - ApiResponse, - CompleteTaskRequest, - GetTasksQuery, - PaginatedResponse, - SkipTaskRequest, - Task, - TaskListItem, - TaskStats, -} from '@/types/goals'; -import { api } from './api'; - -// 任务管理API服务 - -/** - * 获取任务列表 - */ -export const getTasks = async (query: GetTasksQuery = {}): Promise> => { - const searchParams = new URLSearchParams(); - - Object.entries(query).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - searchParams.append(key, String(value)); - } - }); - - const queryString = searchParams.toString(); - const path = queryString ? `/goals/tasks?${queryString}` : '/goals/tasks'; - - return api.get>(path); -}; - -/** - * 获取特定目标的任务列表 - */ -export const getTasksByGoalId = async (goalId: string, query: GetTasksQuery = {}): Promise> => { - const searchParams = new URLSearchParams(); - - Object.entries(query).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - searchParams.append(key, String(value)); - } - }); - - const queryString = searchParams.toString(); - const path = queryString ? `/goals/${goalId}/tasks?${queryString}` : `/goals/${goalId}/tasks`; - - return api.get>(path); -}; - -/** - * 完成任务 - */ -export const completeTask = async (taskId: string, completionData: CompleteTaskRequest = {}): Promise => { - return api.post(`/goals/tasks/${taskId}/complete`, completionData); -}; - -/** - * 跳过任务 - */ -export const skipTask = async (taskId: string, skipData: SkipTaskRequest = {}): Promise => { - return api.post(`/goals/tasks/${taskId}/skip`, skipData); -}; - -/** - * 获取任务统计 - */ -export const getTaskStats = async (goalId?: string): Promise => { - const path = goalId ? `/goals/tasks/stats/overview?goalId=${goalId}` : '/goals/tasks/stats/overview'; - const response = await api.get>(path); - return response.data; -}; - -// 导出所有API方法 -export const tasksApi = { - getTasks, - getTasksByGoalId, - completeTask, - skipTask, - getTaskStats, -}; - -export default tasksApi; diff --git a/store/goalsSlice.ts b/store/goalsSlice.ts deleted file mode 100644 index 72517a6..0000000 --- a/store/goalsSlice.ts +++ /dev/null @@ -1,603 +0,0 @@ -import { goalsApi } from '@/services/goalsApi'; -import { - BatchGoalOperationRequest, - CompleteGoalRequest, - CreateGoalRequest, - GetGoalCompletionsQuery, - GetGoalsQuery, - GoalCompletion, - GoalDetailResponse, - GoalListItem, - GoalStats, - GoalStatus, - UpdateGoalRequest -} from '@/types/goals'; -import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; - -// 目标管理状态类型 -export interface GoalsState { - // 目标列表 - goals: GoalListItem[]; - goalsLoading: boolean; - goalsError: string | null; - goalsPagination: { - page: number; - pageSize: number; - total: number; - hasMore: boolean; - }; - - // 当前查看的目标详情 - currentGoal: GoalDetailResponse | null; - currentGoalLoading: boolean; - currentGoalError: string | null; - - // 目标完成记录 - completions: GoalCompletion[]; - completionsLoading: boolean; - completionsError: string | null; - completionsPagination: { - page: number; - pageSize: number; - total: number; - hasMore: boolean; - }; - - // 目标统计 - stats: GoalStats | null; - statsLoading: boolean; - statsError: string | null; - - // 创建/更新目标 - createLoading: boolean; - createError: string | null; - updateLoading: boolean; - updateError: string | null; - - // 批量操作 - batchLoading: boolean; - batchError: string | null; - - // 筛选和搜索 - filters: GetGoalsQuery; -} - -const initialState: GoalsState = { - goals: [], - goalsLoading: false, - goalsError: null, - goalsPagination: { - page: 1, - pageSize: 20, - total: 0, - hasMore: false, - }, - - currentGoal: null, - currentGoalLoading: false, - currentGoalError: null, - - completions: [], - completionsLoading: false, - completionsError: null, - completionsPagination: { - page: 1, - pageSize: 20, - total: 0, - hasMore: false, - }, - - stats: null, - statsLoading: false, - statsError: null, - - createLoading: false, - createError: null, - updateLoading: false, - updateError: null, - - batchLoading: false, - batchError: null, - - filters: { - page: 1, - pageSize: 20, - sortBy: 'createdAt', - sortOrder: 'desc', - }, -}; - -// 异步操作 - -/** - * 获取目标列表 - */ -export const fetchGoals = createAsyncThunk( - 'goals/fetchGoals', - async (query: GetGoalsQuery = {}, { rejectWithValue }) => { - try { - const response = await goalsApi.getGoals(query); - - console.log('fetchGoals response', response); - return { query, response }; - } catch (error: any) { - return rejectWithValue(error.message || '获取目标列表失败'); - } - } -); - -/** - * 加载更多目标 - */ -export const loadMoreGoals = createAsyncThunk( - 'goals/loadMoreGoals', - async (_, { getState, rejectWithValue }) => { - try { - const state = getState() as { goals: GoalsState }; - const { filters, goalsPagination } = state.goals; - - if (!goalsPagination.hasMore) { - return { goals: [], pagination: goalsPagination }; - } - - const query = { - ...filters, - page: goalsPagination.page + 1, - }; - - const response = await goalsApi.getGoals(query); - - console.log('response', response); - - return { query, response }; - } catch (error: any) { - return rejectWithValue(error.message || '加载更多目标失败'); - } - } -); - -/** - * 获取目标详情 - */ -export const fetchGoalDetail = createAsyncThunk( - 'goals/fetchGoalDetail', - async (goalId: string, { rejectWithValue }) => { - try { - const response = await goalsApi.getGoalById(goalId); - return response.data; - } catch (error: any) { - return rejectWithValue(error.message || '获取目标详情失败'); - } - } -); - -/** - * 创建目标 - */ -export const createGoal = createAsyncThunk( - 'goals/createGoal', - async (goalData: CreateGoalRequest, { rejectWithValue }) => { - try { - const response = await goalsApi.createGoal(goalData); - console.log('createGoal response', response); - return response; - } catch (error: any) { - return rejectWithValue(error.message || '创建目标失败'); - } - } -); - -/** - * 更新目标 - */ -export const updateGoal = createAsyncThunk( - 'goals/updateGoal', - async ({ goalId, goalData }: { goalId: string; goalData: UpdateGoalRequest }, { rejectWithValue }) => { - try { - const response = await goalsApi.updateGoal(goalId, goalData); - return response; - } catch (error: any) { - return rejectWithValue(error.message || '更新目标失败'); - } - } -); - -/** - * 删除目标 - */ -export const deleteGoal = createAsyncThunk( - 'goals/deleteGoal', - async (goalId: string, { rejectWithValue }) => { - try { - await goalsApi.deleteGoal(goalId); - return goalId; - } catch (error: any) { - return rejectWithValue(error.message || '删除目标失败'); - } - } -); - -/** - * 记录目标完成 - */ -export const completeGoal = createAsyncThunk( - 'goals/completeGoal', - async ({ goalId, completionData }: { goalId: string; completionData?: CompleteGoalRequest }, { rejectWithValue }) => { - try { - const response = await goalsApi.completeGoal(goalId, completionData); - return { goalId, completion: response.data }; - } catch (error: any) { - return rejectWithValue(error.message || '记录目标完成失败'); - } - } -); - -/** - * 获取目标完成记录 - */ -export const fetchGoalCompletions = createAsyncThunk( - 'goals/fetchGoalCompletions', - async ({ goalId, query }: { goalId: string; query?: GetGoalCompletionsQuery }, { rejectWithValue }) => { - try { - const response = await goalsApi.getGoalCompletions(goalId, query); - return { query, response: response.data }; - } catch (error: any) { - return rejectWithValue(error.message || '获取完成记录失败'); - } - } -); - -/** - * 获取目标统计 - */ -export const fetchGoalStats = createAsyncThunk( - 'goals/fetchGoalStats', - async (_, { rejectWithValue }) => { - try { - const response = await goalsApi.getGoalStats(); - return response.data; - } catch (error: any) { - return rejectWithValue(error.message || '获取目标统计失败'); - } - } -); - -/** - * 批量操作目标 - */ -export const batchOperateGoals = createAsyncThunk( - 'goals/batchOperateGoals', - async (operationData: BatchGoalOperationRequest, { rejectWithValue }) => { - try { - const response = await goalsApi.batchOperateGoals(operationData); - return { operation: operationData, results: response.data }; - } catch (error: any) { - return rejectWithValue(error.message || '批量操作失败'); - } - } -); - -// Redux Slice -const goalsSlice = createSlice({ - name: 'goals', - initialState, - reducers: { - // 设置筛选条件 - setFilters: (state, action: PayloadAction>) => { - state.filters = { ...state.filters, ...action.payload }; - }, - - // 重置筛选条件 - resetFilters: (state) => { - state.filters = { - page: 1, - pageSize: 20, - sortBy: 'createdAt', - sortOrder: 'desc', - }; - }, - - // 清除错误 - clearErrors: (state) => { - state.goalsError = null; - state.currentGoalError = null; - state.completionsError = null; - state.statsError = null; - state.createError = null; - state.updateError = null; - state.batchError = null; - }, - - // 清除当前目标详情 - clearCurrentGoal: (state) => { - state.currentGoal = null; - state.currentGoalError = null; - }, - - // 本地更新目标状态(用于乐观更新) - updateGoalStatus: (state, action: PayloadAction<{ goalId: string; status: GoalStatus }>) => { - const { goalId, status } = action.payload; - - // 更新目标列表中的状态 - const goalIndex = state.goals.findIndex(goal => goal.id === goalId); - if (goalIndex !== -1) { - state.goals[goalIndex].status = status; - } - - // 更新当前目标详情中的状态 - if (state.currentGoal && state.currentGoal.id === goalId) { - state.currentGoal.status = status; - } - }, - - // 本地增加完成次数(用于乐观更新) - incrementGoalCompletion: (state, action: PayloadAction<{ goalId: string; count?: number }>) => { - const { goalId, count = 1 } = action.payload; - - // 更新目标列表中的完成次数 - const goalIndex = state.goals.findIndex(goal => goal.id === goalId); - if (goalIndex !== -1) { - state.goals[goalIndex].completedCount += count; - // 重新计算进度百分比 - if (state.goals[goalIndex].targetCount && state.goals[goalIndex].targetCount > 0) { - state.goals[goalIndex].progressPercentage = Math.round( - (state.goals[goalIndex].completedCount / state.goals[goalIndex].targetCount) * 100 - ); - } - } - - // 更新当前目标详情中的完成次数 - if (state.currentGoal && state.currentGoal.id === goalId) { - state.currentGoal.completedCount += count; - if (state.currentGoal.targetCount && state.currentGoal.targetCount > 0) { - state.currentGoal.progressPercentage = Math.round( - (state.currentGoal.completedCount / state.currentGoal.targetCount) * 100 - ); - } - } - }, - }, - extraReducers: (builder) => { - builder - // 获取目标列表 - .addCase(fetchGoals.pending, (state) => { - state.goalsLoading = true; - state.goalsError = null; - }) - .addCase(fetchGoals.fulfilled, (state, action) => { - state.goalsLoading = false; - const { query, response } = action.payload; - - // 如果是第一页,替换数据;否则追加数据 - if (query.page === 1) { - state.goals = response.list; - } else { - state.goals = [...state.goals, ...response.list]; - } - - state.goalsPagination = { - page: response.page, - pageSize: response.pageSize, - total: response.total, - hasMore: response.page * response.pageSize < response.total, - }; - }) - .addCase(fetchGoals.rejected, (state, action) => { - state.goalsLoading = false; - state.goalsError = action.payload as string; - }) - - // 加载更多目标 - .addCase(loadMoreGoals.pending, (state) => { - state.goalsLoading = true; - }) - .addCase(loadMoreGoals.fulfilled, (state, action) => { - state.goalsLoading = false; - const { response } = action.payload; - - if (!response) { - return; - } - - state.goals = [...state.goals, ...response.list]; - state.goalsPagination = { - page: response.page, - pageSize: response.pageSize, - total: response.total, - hasMore: response.page * response.pageSize < response.total, - }; - }) - .addCase(loadMoreGoals.rejected, (state, action) => { - state.goalsLoading = false; - state.goalsError = action.payload as string; - }) - - // 获取目标详情 - .addCase(fetchGoalDetail.pending, (state) => { - state.currentGoalLoading = true; - state.currentGoalError = null; - }) - .addCase(fetchGoalDetail.fulfilled, (state, action) => { - state.currentGoalLoading = false; - state.currentGoal = action.payload; - }) - .addCase(fetchGoalDetail.rejected, (state, action) => { - state.currentGoalLoading = false; - state.currentGoalError = action.payload as string; - }) - - // 创建目标 - .addCase(createGoal.pending, (state) => { - state.createLoading = true; - state.createError = null; - }) - .addCase(createGoal.fulfilled, (state, action) => { - state.createLoading = false; - // 将新目标添加到列表开头 - const newGoal: GoalListItem = { - ...action.payload, - progressPercentage: action.payload.targetCount && action.payload.targetCount > 0 - ? Math.round((action.payload.completedCount / action.payload.targetCount) * 100) - : 0, - }; - state.goals.unshift(newGoal); - state.goalsPagination.total += 1; - }) - .addCase(createGoal.rejected, (state, action) => { - state.createLoading = false; - state.createError = action.payload as string; - }) - - // 更新目标 - .addCase(updateGoal.pending, (state) => { - state.updateLoading = true; - state.updateError = null; - }) - .addCase(updateGoal.fulfilled, (state, action) => { - state.updateLoading = false; - const updatedGoal = action.payload; - - console.log('updateGoal.fulfilled', updatedGoal); - - // 更新目标列表中的目标 - const goalIndex = state.goals.findIndex(goal => goal.id === updatedGoal.id); - if (goalIndex !== -1) { - state.goals[goalIndex] = { - ...state.goals[goalIndex], - ...updatedGoal, - }; - } - - // 更新当前目标详情 - if (state.currentGoal && state.currentGoal.id === updatedGoal.id) { - state.currentGoal = { - ...state.currentGoal, - ...updatedGoal, - }; - } - }) - .addCase(updateGoal.rejected, (state, action) => { - state.updateLoading = false; - state.updateError = action.payload as string; - }) - - // 删除目标 - .addCase(deleteGoal.fulfilled, (state, action) => { - const goalId = action.payload; - - // 从目标列表中移除 - state.goals = state.goals.filter(goal => goal.id !== goalId); - state.goalsPagination.total -= 1; - - // 如果删除的是当前查看的目标,清除详情 - if (state.currentGoal && state.currentGoal.id === goalId) { - state.currentGoal = null; - } - }) - - // 记录目标完成 - .addCase(completeGoal.fulfilled, (state, action) => { - const { goalId, completion } = action.payload; - - // 增加完成次数 - goalsSlice.caseReducers.incrementGoalCompletion(state, { - type: 'goals/incrementGoalCompletion', - payload: { goalId, count: completion.completionCount }, - }); - - // 将完成记录添加到列表开头 - state.completions.unshift(completion); - }) - - // 获取完成记录 - .addCase(fetchGoalCompletions.pending, (state) => { - state.completionsLoading = true; - state.completionsError = null; - }) - .addCase(fetchGoalCompletions.fulfilled, (state, action) => { - state.completionsLoading = false; - const { query, response } = action.payload; - - // 如果是第一页,替换数据;否则追加数据 - if (query?.page === 1) { - state.completions = response.list; - } else { - state.completions = [...state.completions, ...response.list]; - } - - state.completionsPagination = { - page: response.page, - pageSize: response.pageSize, - total: response.total, - hasMore: response.page * response.pageSize < response.total, - }; - }) - .addCase(fetchGoalCompletions.rejected, (state, action) => { - state.completionsLoading = false; - state.completionsError = action.payload as string; - }) - - // 获取目标统计 - .addCase(fetchGoalStats.pending, (state) => { - state.statsLoading = true; - state.statsError = null; - }) - .addCase(fetchGoalStats.fulfilled, (state, action) => { - state.statsLoading = false; - state.stats = action.payload; - }) - .addCase(fetchGoalStats.rejected, (state, action) => { - state.statsLoading = false; - state.statsError = action.payload as string; - }) - - // 批量操作 - .addCase(batchOperateGoals.pending, (state) => { - state.batchLoading = true; - state.batchError = null; - }) - .addCase(batchOperateGoals.fulfilled, (state, action) => { - state.batchLoading = false; - const { operation, results } = action.payload; - - // 根据操作类型更新状态 - results.forEach(result => { - if (result.success) { - const goalIndex = state.goals.findIndex(goal => goal.id === result.goalId); - if (goalIndex !== -1) { - switch (operation.action) { - case 'pause': - state.goals[goalIndex].status = 'paused'; - break; - case 'resume': - state.goals[goalIndex].status = 'active'; - break; - case 'complete': - state.goals[goalIndex].status = 'completed'; - break; - case 'delete': - state.goals = state.goals.filter(goal => goal.id !== result.goalId); - state.goalsPagination.total -= 1; - break; - } - } - } - }); - }) - .addCase(batchOperateGoals.rejected, (state, action) => { - state.batchLoading = false; - state.batchError = action.payload as string; - }); - }, -}); - -export const { - setFilters, - resetFilters, - clearErrors, - clearCurrentGoal, - updateGoalStatus, - incrementGoalCompletion, -} = goalsSlice.actions; - -export default goalsSlice.reducer; \ No newline at end of file diff --git a/store/index.ts b/store/index.ts index 234fb7a..a77645a 100644 --- a/store/index.ts +++ b/store/index.ts @@ -1,13 +1,9 @@ +import { persistActiveFastingSchedule } from '@/utils/fasting'; import { configureStore, createListenerMiddleware } from '@reduxjs/toolkit'; import challengesReducer from './challengesSlice'; import checkinReducer, { addExercise, autoSyncCheckin, removeExercise, replaceExercises, setNote, toggleExerciseCompleted } from './checkinSlice'; import circumferenceReducer from './circumferenceSlice'; import exerciseLibraryReducer from './exerciseLibrarySlice'; -import foodLibraryReducer from './foodLibrarySlice'; -import foodRecognitionReducer from './foodRecognitionSlice'; -import membershipReducer from './membershipSlice'; -import goalsReducer from './goalsSlice'; -import healthReducer from './healthSlice'; import fastingReducer, { clearActiveSchedule, completeActiveSchedule, @@ -15,15 +11,17 @@ import fastingReducer, { scheduleFastingPlan, setRecommendedSchedule, } from './fastingSlice'; +import foodLibraryReducer from './foodLibrarySlice'; +import foodRecognitionReducer from './foodRecognitionSlice'; +import healthReducer from './healthSlice'; +import membershipReducer from './membershipSlice'; import moodReducer from './moodSlice'; import nutritionReducer from './nutritionSlice'; import scheduleExerciseReducer from './scheduleExerciseSlice'; -import tasksReducer from './tasksSlice'; import trainingPlanReducer from './trainingPlanSlice'; import userReducer from './userSlice'; import waterReducer from './waterSlice'; import workoutReducer from './workoutSlice'; -import { persistActiveFastingSchedule } from '@/utils/fasting'; // 创建监听器中间件来处理自动同步 const listenerMiddleware = createListenerMiddleware(); @@ -99,11 +97,9 @@ export const store = configureStore({ challenges: challengesReducer, checkin: checkinReducer, circumference: circumferenceReducer, - goals: goalsReducer, health: healthReducer, mood: moodReducer, nutrition: nutritionReducer, - tasks: tasksReducer, trainingPlan: trainingPlanReducer, scheduleExercise: scheduleExerciseReducer, exerciseLibrary: exerciseLibraryReducer, diff --git a/store/tasksSlice.ts b/store/tasksSlice.ts deleted file mode 100644 index 15df5ec..0000000 --- a/store/tasksSlice.ts +++ /dev/null @@ -1,322 +0,0 @@ -import { tasksApi } from '@/services/tasksApi'; -import { - CompleteTaskRequest, - GetTasksQuery, - SkipTaskRequest, - TaskListItem, - TaskStats, -} from '@/types/goals'; -import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; - -// 任务管理状态类型 -export interface TasksState { - // 任务列表 - tasks: TaskListItem[]; - tasksLoading: boolean; - tasksError: string | null; - tasksPagination: { - page: number; - pageSize: number; - total: number; - hasMore: boolean; - }; - - // 任务统计 - stats: TaskStats | null; - statsLoading: boolean; - statsError: string | null; - - // 完成任务 - completeLoading: boolean; - completeError: string | null; - - // 跳过任务 - skipLoading: boolean; - skipError: string | null; - - // 筛选和搜索 - filters: GetTasksQuery; -} - -const initialState: TasksState = { - tasks: [], - tasksLoading: false, - tasksError: null, - tasksPagination: { - page: 1, - pageSize: 20, - total: 0, - hasMore: false, - }, - - stats: null, - statsLoading: false, - statsError: null, - - completeLoading: false, - completeError: null, - - skipLoading: false, - skipError: null, - - filters: { - page: 1, - pageSize: 20, - }, -}; - -// 异步操作 - -/** - * 获取任务列表 - */ -export const fetchTasks = createAsyncThunk( - 'tasks/fetchTasks', - async (query: GetTasksQuery = {}, { rejectWithValue }) => { - try { - console.log('fetchTasks', fetchTasks); - - const response = await tasksApi.getTasks(query); - console.log('fetchTasks response', response); - return { query, response }; - } catch (error: any) { - return rejectWithValue(error.message || '获取任务列表失败'); - } - } -); - -/** - * 加载更多任务 - */ -export const loadMoreTasks = createAsyncThunk( - 'tasks/loadMoreTasks', - async (_, { getState, rejectWithValue }) => { - try { - const state = getState() as { tasks: TasksState }; - const { filters, tasksPagination } = state.tasks; - - if (!tasksPagination.hasMore) { - return { tasks: [], pagination: tasksPagination }; - } - - const query = { - ...filters, - page: tasksPagination.page + 1, - }; - - const response = await tasksApi.getTasks(query); - console.log('loadMoreTasks response', response); - - return { query, response }; - } catch (error: any) { - return rejectWithValue(error.message || '加载更多任务失败'); - } - } -); - -/** - * 完成任务 - */ -export const completeTask = createAsyncThunk( - 'tasks/completeTask', - async ({ taskId, completionData }: { taskId: string; completionData?: CompleteTaskRequest }, { rejectWithValue }) => { - try { - const response = await tasksApi.completeTask(taskId, completionData); - console.log('completeTask response', response); - return response; - } catch (error: any) { - return rejectWithValue(error.message || '完成任务失败'); - } - } -); - -/** - * 跳过任务 - */ -export const skipTask = createAsyncThunk( - 'tasks/skipTask', - async ({ taskId, skipData }: { taskId: string; skipData?: SkipTaskRequest }, { rejectWithValue }) => { - try { - const response = await tasksApi.skipTask(taskId, skipData); - console.log('skipTask response', response); - return response; - } catch (error: any) { - return rejectWithValue(error.message || '跳过任务失败'); - } - } -); - -/** - * 获取任务统计 - */ -export const fetchTaskStats = createAsyncThunk( - 'tasks/fetchTaskStats', - async (goalId: string, { rejectWithValue }) => { - try { - const response = await tasksApi.getTaskStats(goalId); - console.log('fetchTaskStats response', response); - return response; - } catch (error: any) { - return rejectWithValue(error.message || '获取任务统计失败'); - } - } -); - -// Redux Slice -const tasksSlice = createSlice({ - name: 'tasks', - initialState, - reducers: { - // 清除错误 - clearErrors: (state) => { - state.tasksError = null; - state.completeError = null; - state.skipError = null; - state.statsError = null; - }, - - // 更新筛选条件 - updateFilters: (state, action: PayloadAction>) => { - state.filters = { ...state.filters, ...action.payload }; - }, - - // 重置筛选条件 - resetFilters: (state) => { - state.filters = { - page: 1, - pageSize: 20, - }; - }, - - // 乐观更新任务完成状态 - optimisticCompleteTask: (state, action: PayloadAction<{ taskId: string; count?: number }>) => { - const { taskId, count = 1 } = action.payload; - const task = state.tasks.find(t => t.id === taskId); - if (task) { - const newCount = Math.min(task.currentCount + count, task.targetCount); - task.currentCount = newCount; - task.progressPercentage = Math.round((newCount / task.targetCount) * 100); - - if (newCount >= task.targetCount) { - task.status = 'completed'; - task.completedAt = new Date().toISOString(); - } else if (newCount > 0) { - task.status = 'in_progress'; - } - } - }, - }, - extraReducers: (builder) => { - builder - // 获取任务列表 - .addCase(fetchTasks.pending, (state) => { - state.tasksLoading = true; - state.tasksError = null; - }) - .addCase(fetchTasks.fulfilled, (state, action) => { - state.tasksLoading = false; - const { query, response } = action.payload; - - // 如果是第一页,替换数据;否则追加数据 - state.tasks = response.list; - console.log('state.tasks', state.tasks); - - state.tasksPagination = { - page: response.page, - pageSize: response.pageSize, - total: response.total, - hasMore: response.page * response.pageSize < response.total, - }; - }) - .addCase(fetchTasks.rejected, (state, action) => { - state.tasksLoading = false; - state.tasksError = action.payload as string; - }) - - // 加载更多任务 - .addCase(loadMoreTasks.pending, (state) => { - state.tasksLoading = true; - }) - .addCase(loadMoreTasks.fulfilled, (state, action) => { - state.tasksLoading = false; - const { response } = action.payload; - - if (!response) { - return; - } - - state.tasks = [...state.tasks, ...response.list]; - state.tasksPagination = { - page: response.page, - pageSize: response.pageSize, - total: response.total, - hasMore: response.page * response.pageSize < response.total, - }; - }) - .addCase(loadMoreTasks.rejected, (state, action) => { - state.tasksLoading = false; - state.tasksError = action.payload as string; - }) - - // 完成任务 - .addCase(completeTask.pending, (state) => { - state.completeLoading = true; - state.completeError = null; - }) - .addCase(completeTask.fulfilled, (state, action) => { - state.completeLoading = false; - // 更新任务列表中的对应任务 - const updatedTask = action.payload; - const index = state.tasks.findIndex(t => t.id === updatedTask.id); - if (index !== -1) { - state.tasks[index] = updatedTask; - } - }) - .addCase(completeTask.rejected, (state, action) => { - state.completeLoading = false; - state.completeError = action.payload as string; - }) - - // 跳过任务 - .addCase(skipTask.pending, (state) => { - state.skipLoading = true; - state.skipError = null; - }) - .addCase(skipTask.fulfilled, (state, action) => { - state.skipLoading = false; - // 更新任务列表中的对应任务 - const updatedTask = action.payload; - const index = state.tasks.findIndex(t => t.id === updatedTask.id); - if (index !== -1) { - state.tasks[index] = updatedTask; - } - }) - .addCase(skipTask.rejected, (state, action) => { - state.skipLoading = false; - state.skipError = action.payload as string; - }) - - // 获取任务统计 - .addCase(fetchTaskStats.pending, (state) => { - state.statsLoading = true; - state.statsError = null; - }) - .addCase(fetchTaskStats.fulfilled, (state, action) => { - state.statsLoading = false; - state.stats = action.payload; - }) - .addCase(fetchTaskStats.rejected, (state, action) => { - state.statsLoading = false; - state.statsError = action.payload as string; - }); - }, -}); - -export const { - clearErrors, - updateFilters, - resetFilters, - optimisticCompleteTask, -} = tasksSlice.actions; - -export default tasksSlice.reducer; diff --git a/types/goals.ts b/types/goals.ts deleted file mode 100644 index e241f97..0000000 --- a/types/goals.ts +++ /dev/null @@ -1,251 +0,0 @@ -// 目标管理相关类型定义 - -export type RepeatType = 'daily' | 'weekly' | 'monthly'; - -export type GoalStatus = 'active' | 'paused' | 'completed' | 'cancelled'; - -export type GoalPriority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10; - -// 自定义重复规则 -export interface CustomRepeatRule { - weekdays?: number[]; // 0-6,0为周日 - dayOfMonth?: number[]; // 1-31 -} - -// 提醒设置 -export interface ReminderSettings { - enabled: boolean; - weekdays?: number[]; // 0-6,0为周日 - monthDays?: number[]; // 1-31,每月几号 - sound?: string; - vibration?: boolean; -} - -// 目标数据结构 -export interface Goal { - id: string; - userId: string; - title: string; - description?: string; - repeatType: RepeatType; - frequency: number; - customRepeatRule?: CustomRepeatRule; - startDate: string; // ISO date string - endDate?: string; // ISO date string - startTime: number; // HH:mm format - endTime: number; // HH:mm format - status: GoalStatus; - completedCount: number; - targetCount?: number; - category?: string; - priority: GoalPriority; - hasReminder: boolean; - reminderTime?: string; // HH:mm format - reminderSettings?: ReminderSettings; - createdAt?: string; - updatedAt?: string; -} - -// 目标完成记录 -export interface GoalCompletion { - id: string; - goalId: string; - userId: string; - completedAt: string; // ISO datetime string - completionCount: number; - notes?: string; - metadata?: Record; -} - -// 创建目标的请求数据 -export interface CreateGoalRequest { - title: string; - description?: string; - repeatType: RepeatType; - frequency: number; - customRepeatRule?: CustomRepeatRule; - startDate?: string; - endDate?: string; - startTime?: number; // 单位:分钟 - endTime?: number; // 单位:分钟 - targetCount?: number; - category?: string; - priority: GoalPriority; - hasReminder: boolean; - reminderTime?: string; - reminderSettings?: ReminderSettings; -} - -// 更新目标的请求数据 -export interface UpdateGoalRequest { - title?: string; - description?: string; - repeatType?: RepeatType; - frequency?: number; - customRepeatRule?: CustomRepeatRule; - startDate?: string; - endDate?: string; - targetCount?: number; - category?: string; - priority?: GoalPriority; - hasReminder?: boolean; - reminderTime?: string; - reminderSettings?: ReminderSettings; - status?: GoalStatus; -} - -// 记录目标完成的请求数据 -export interface CompleteGoalRequest { - completionCount?: number; - notes?: string; - completedAt?: string; -} - -// 获取目标列表的查询参数 -export interface GetGoalsQuery { - page?: number; - pageSize?: number; - status?: GoalStatus; - repeatType?: RepeatType; - category?: string; - search?: string; - startDate?: string; - endDate?: string; - sortBy?: 'createdAt' | 'updatedAt' | 'priority' | 'title' | 'startDate'; - sortOrder?: 'asc' | 'desc'; -} - -// 获取目标完成记录的查询参数 -export interface GetGoalCompletionsQuery { - page?: number; - pageSize?: number; - startDate?: string; - endDate?: string; -} - -// 批量操作目标的请求数据 -export interface BatchGoalOperationRequest { - goalIds: string[]; - action: 'pause' | 'resume' | 'complete' | 'delete'; -} - -// 批量操作结果 -export interface BatchGoalOperationResult { - goalId: string; - success: boolean; - error?: string; -} - -// 目标统计信息 -export interface GoalStats { - total: number; - active: number; - completed: number; - paused: number; - cancelled: number; - byCategory: Record; - byRepeatType: Record; - totalCompletions: number; - thisWeekCompletions: number; - thisMonthCompletions: number; -} - -// API响应格式 -export interface ApiResponse { - code: number; - message: string; - data: T; -} - -// 分页响应格式 -export interface PaginatedResponse { - page: number; - pageSize: number; - total: number; - list: T[]; -} - -// 目标详情响应(包含完成记录) -export interface GoalDetailResponse extends Goal { - progressPercentage: number; - daysRemaining?: number; - completions: GoalCompletion[]; -} - -// 目标列表项响应 -export interface GoalListItem extends Goal { - progressPercentage: number; - daysRemaining?: number; -} - -// 任务相关类型定义 - -export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'overdue' | 'skipped'; - -// 任务数据结构 -export interface Task { - id: string; - goalId: string; - userId: string; - title: string; - description?: string; - startDate: string; // ISO date string - endDate: string; // ISO date string - targetCount: number; - currentCount: number; - status: TaskStatus; - progressPercentage: number; - completedAt?: string; // ISO datetime string - notes?: string; - metadata?: Record; - daysRemaining: number; - isToday: boolean; - goal?: { - id: string; - title: string; - repeatType: RepeatType; - frequency: number; - category?: string; - }; -} - -// 获取任务列表的查询参数 -export interface GetTasksQuery { - goalId?: string; - status?: TaskStatus; - startDate?: string; - endDate?: string; - page?: number; - pageSize?: number; -} - -// 完成任务的请求数据 -export interface CompleteTaskRequest { - count?: number; - notes?: string; - completedAt?: string; -} - -// 跳过任务的请求数据 -export interface SkipTaskRequest { - reason?: string; -} - -// 任务统计信息 -export interface TaskStats { - total: number; - pending: number; - inProgress: number; - completed: number; - overdue: number; - skipped: number; - totalProgress: number; - todayTasks: number; - weekTasks: number; - monthTasks: number; -} - -// 任务列表项响应 -export interface TaskListItem extends Task { - // 继承Task的所有属性 -} \ No newline at end of file diff --git a/utils/guideHelpers.ts b/utils/guideHelpers.ts index 99e5058..8e886bc 100644 --- a/utils/guideHelpers.ts +++ b/utils/guideHelpers.ts @@ -1,18 +1,16 @@ import AsyncStorage from '@/utils/kvStore'; // 引导状态存储键 -const GUIDE_KEYS = { - GOALS_PAGE: '@guide_goals_page_completed', -} as const; +const GUIDE_KEYS = {} as const; /** * 检查用户是否已经完成特定引导 * @param guideKey 引导键名 * @returns Promise 是否已完成 */ -export const checkGuideCompleted = async (guideKey: keyof typeof GUIDE_KEYS): Promise => { +export const checkGuideCompleted = async (guideKey: string): Promise => { try { - const completed = await AsyncStorage.getItem(GUIDE_KEYS[guideKey]); + const completed = await AsyncStorage.getItem(guideKey); return completed === 'true'; } catch (error) { console.error('检查引导状态失败:', error); @@ -24,9 +22,9 @@ export const checkGuideCompleted = async (guideKey: keyof typeof GUIDE_KEYS): Pr * 标记引导为已完成 * @param guideKey 引导键名 */ -export const markGuideCompleted = async (guideKey: keyof typeof GUIDE_KEYS): Promise => { +export const markGuideCompleted = async (guideKey: string): Promise => { try { - await AsyncStorage.setItem(GUIDE_KEYS[guideKey], 'true'); + await AsyncStorage.setItem(guideKey, 'true'); } catch (error) { console.error('保存引导状态失败:', error); } @@ -37,9 +35,8 @@ export const markGuideCompleted = async (guideKey: keyof typeof GUIDE_KEYS): Pro */ export const resetAllGuides = async (): Promise => { try { - const keys = Object.values(GUIDE_KEYS); - await AsyncStorage.multiRemove(keys); - console.log('所有引导状态已重置'); + // 由于没有引导键,这个函数现在什么都不做 + console.log('所有引导状态已重置(无引导键)'); } catch (error) { console.error('重置引导状态失败:', error); } @@ -51,15 +48,8 @@ export const resetAllGuides = async (): Promise => { */ export const getAllGuideStatus = async (): Promise> => { try { - const result: Record = {}; - const keys = Object.values(GUIDE_KEYS); - - for (const key of keys) { - const completed = await AsyncStorage.getItem(key); - result[key] = completed === 'true'; - } - - return result; + // 由于没有引导键,返回空对象 + return {}; } catch (error) { console.error('获取引导状态失败:', error); return {}; diff --git a/utils/notificationHelpers.ts b/utils/notificationHelpers.ts index bd79e99..9adc7be 100644 --- a/utils/notificationHelpers.ts +++ b/utils/notificationHelpers.ts @@ -78,214 +78,7 @@ export class WorkoutNotificationHelpers { } } -/** - * 目标相关的通知辅助函数 - */ -export class GoalNotificationHelpers { - /** - * 发送目标达成通知 - */ - static async sendGoalAchievementNotification(userName: string, goalName: string) { - return notificationService.sendImmediateNotification({ - title: '目标达成', - body: `${userName},恭喜您达成了目标:${goalName}!`, - data: { type: 'goal_achievement', goalName }, - sound: true, - priority: 'high', - }); - } - - /** - * 发送目标进度更新通知 - */ - static async sendGoalProgressNotification(userName: string, goalName: string, progress: number) { - return notificationService.sendImmediateNotification({ - title: '目标进度', - body: `${userName},您的目标"${goalName}"已完成${progress}%!`, - data: { type: 'goal_progress', goalName, progress }, - sound: true, - priority: 'normal', - }); - } - - /** - * 安排目标提醒 - */ - static async scheduleGoalReminder(userName: string, goalName: string, deadline: Date) { - // 在截止日期前一天发送提醒 - const reminderDate = new Date(deadline); - reminderDate.setDate(reminderDate.getDate() - 1); - - return notificationService.scheduleNotificationAtDate( - { - title: '目标截止提醒', - body: `${userName},您的目标"${goalName}"明天就要截止了,加油!`, - data: { type: 'goal_deadline_reminder', goalName }, - sound: true, - priority: 'high', - }, - reminderDate - ); - } - - /** - * 根据目标设置创建定时推送 - * @param goalData 目标数据 - * @param userName 用户名 - * @returns 通知ID数组 - */ - static async scheduleGoalNotifications( - goalData: { - title: string; - repeatType: 'daily' | 'weekly' | 'monthly'; - frequency: number; - hasReminder: boolean; - reminderTime?: string; - customRepeatRule?: { - weekdays?: number[]; - dayOfMonth?: number[]; - }; - startTime?: number; - }, - userName: string - ): Promise { - const notificationIds: string[] = []; - - // 如果没有开启提醒,直接返回 - if (!goalData.hasReminder || !goalData.reminderTime) { - console.log('目标未开启提醒或未设置提醒时间'); - return notificationIds; - } - - try { - // 解析提醒时间 - const [hours, minutes] = goalData.reminderTime.split(':').map(Number); - - // 创建通知内容 - const notification: NotificationData = { - title: '目标提醒', - body: `${userName},该完成您的目标"${goalData.title}"了!`, - data: { - type: 'goal_reminder', - goalTitle: goalData.title, - repeatType: goalData.repeatType, - frequency: goalData.frequency - }, - sound: true, - priority: 'high', - }; - - // 根据重复类型创建不同的通知 - switch (goalData.repeatType) { - case 'daily': - // 每日重复 - 使用日历重复通知 - const dailyId = await notificationService.scheduleCalendarRepeatingNotification( - notification, - { - type: Notifications.SchedulableTriggerInputTypes.DAILY, - hour: hours, - minute: minutes, - } - ); - notificationIds.push(dailyId); - console.log(`已安排每日目标提醒,通知ID:${dailyId}`); - break; - - case 'weekly': - // 每周重复 - 为每个选中的星期几创建单独的通知 - if (goalData.customRepeatRule?.weekdays && goalData.customRepeatRule.weekdays.length > 0) { - for (const weekday of goalData.customRepeatRule.weekdays) { - const weeklyId = await notificationService.scheduleCalendarRepeatingNotification( - notification, - { - type: Notifications.SchedulableTriggerInputTypes.WEEKLY, - hour: hours, - minute: minutes, - weekdays: [weekday], - } - ); - notificationIds.push(weeklyId); - console.log(`已安排每周目标提醒,星期${weekday},通知ID:${weeklyId}`); - } - } else { - // 默认每周重复 - const weeklyId = await notificationService.scheduleCalendarRepeatingNotification( - notification, - { - type: Notifications.SchedulableTriggerInputTypes.WEEKLY, - hour: hours, - minute: minutes, - } - ); - notificationIds.push(weeklyId); - console.log(`已安排每周目标提醒,通知ID:${weeklyId}`); - } - break; - - case 'monthly': - // 每月重复 - 为每个选中的日期创建单独的通知 - if (goalData.customRepeatRule?.dayOfMonth && goalData.customRepeatRule.dayOfMonth.length > 0) { - for (const dayOfMonth of goalData.customRepeatRule.dayOfMonth) { - const monthlyId = await notificationService.scheduleCalendarRepeatingNotification( - notification, - { - type: Notifications.SchedulableTriggerInputTypes.MONTHLY, - hour: hours, - minute: minutes, - dayOfMonth: dayOfMonth, - } - ); - notificationIds.push(monthlyId); - console.log(`已安排每月目标提醒,${dayOfMonth}号,通知ID:${monthlyId}`); - } - } else { - // 默认每月重复 - const monthlyId = await notificationService.scheduleCalendarRepeatingNotification( - notification, - { - type: Notifications.SchedulableTriggerInputTypes.MONTHLY, - hour: hours, - minute: minutes, - dayOfMonth: 1, - } - ); - notificationIds.push(monthlyId); - console.log(`已安排每月目标提醒,通知ID:${monthlyId}`); - } - break; - } - - console.log(`目标"${goalData.title}"的定时推送已创建完成,共${notificationIds.length}个通知`); - return notificationIds; - - } catch (error) { - console.error('创建目标定时推送失败:', error); - throw error; - } - } - - - - /** - * 取消特定目标的所有通知 - */ - static async cancelGoalNotifications(goalTitle: string): Promise { - try { - const notifications = await notificationService.getAllScheduledNotifications(); - - for (const notification of notifications) { - if (notification.content.data?.type === 'goal_reminder' && - notification.content.data?.goalTitle === goalTitle) { - await notificationService.cancelNotification(notification.identifier); - console.log(`已取消目标"${goalTitle}"的通知:${notification.identifier}`); - } - } - } catch (error) { - console.error('取消目标通知失败:', error); - throw error; - } - } -} +// GoalNotificationHelpers 类已删除,因为目标功能已移除 export class ChallengeNotificationHelpers { static buildChallengesTabUrl(): string { diff --git a/utils/welcomeMessage.ts b/utils/welcomeMessage.ts index 2bad574..bd43f3f 100644 --- a/utils/welcomeMessage.ts +++ b/utils/welcomeMessage.ts @@ -46,7 +46,6 @@ export function generateWelcomeMessage(params: GenerateWelcomeMessageParams): We content: `你好,${name}!🐳\n\n我是你的小海豹Seal!发现你还没有完善健康档案呢~让我帮你开启个性化的健康管理之旅吧!\n\n完善档案后,我就能为你量身定制专属的营养方案、运动计划和生活建议啦!`, choices: [ { id: 'profile_setup', label: '完善我的健康档案', value: '我想要完善健康档案,建立个人健康数据', emoji: '📋', recommended: true }, - { id: 'health_goals', label: '了解健康目标设定', value: '我想了解如何设定合理的健康目标', emoji: '🎯' }, { id: 'nutrition_basics', label: '营养基础知识科普', value: '我想了解一些基础的营养知识', emoji: '🥗' }, { id: 'quick_start', label: '快速开始体验', value: '我想直接体验一下你的功能', emoji: '🚀' } ],