diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index ee1595a..b5b0b14 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -43,7 +43,7 @@ export default function TabLayout() { case 'explore': return { icon: 'magnifyingglass.circle.fill', title: '发现' } as const; case 'coach': - return { icon: 'person.3.fill', title: 'Bot' } as const; + return { icon: 'person.3.fill', title: 'Seal' } as const; case 'statistics': return { icon: 'chart.pie.fill', title: '统计' } as const; case 'personal': @@ -131,7 +131,7 @@ export default function TabLayout() { { const isCoachSelected = pathname === '/coach'; return ( @@ -148,7 +148,7 @@ export default function TabLayout() { textAlign: 'center', flexShrink: 0, }}> - Bot + Seal )} @@ -160,6 +160,7 @@ export default function TabLayout() { name="explore" options={{ title: '发现', + href: null, tabBarIcon: ({ color }) => { const isHomeSelected = pathname === '/' || pathname === '/index'; return ( diff --git a/app/(tabs)/coach.tsx b/app/(tabs)/coach.tsx index ed909e9..351d7e6 100644 --- a/app/(tabs)/coach.tsx +++ b/app/(tabs)/coach.tsx @@ -25,12 +25,13 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Colors } from '@/constants/Colors'; import { getTabBarBottomPadding } from '@/constants/TabBar'; -import { useAppSelector } from '@/hooks/redux'; +import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { useCosUpload } from '@/hooks/useCosUpload'; import { deleteConversation, getConversationDetail, listConversations, type AiConversationListItem } from '@/services/aiCoach'; import { loadAiCoachSessionCache, saveAiCoachSessionCache } from '@/services/aiCoachSession'; import { api, getAuthToken, postTextStream } from '@/services/api'; +import { updateProfile } from '@/store/userSlice'; import dayjs from 'dayjs'; import { LinearGradient } from 'expo-linear-gradient'; import { ActionSheet } from '../../components/ui/ActionSheet'; @@ -124,7 +125,7 @@ export default function CoachScreen() { const { isLoggedIn, pushIfAuthedElseLogin } = useAuthGuard(); // 为了让页面更贴近品牌主题与更亮的观感,这里使用亮色系配色 const theme = Colors.light; - const botName = (params?.name || 'Bot').toString(); + const botName = (params?.name || 'Seal').toString(); const [input, setInput] = useState(''); const [isSending, setIsSending] = useState(false); const [isStreaming, setIsStreaming] = useState(false); @@ -174,7 +175,7 @@ export default function CoachScreen() { const generateWelcomeMessage = useCallback(() => { const hour = new Date().getHours(); const name = userProfile?.name || '朋友'; - const botName = (params?.name || '海豹助手').toString(); + const botName = (params?.name || 'Seal').toString(); // 时段问候 let timeGreeting = ''; @@ -199,7 +200,7 @@ export default function CoachScreen() { messages: [ `${timeGreeting},${name}!我是${botName},你的专属健康管理助手。新的一天开始了,让我们一起为你的健康目标努力吧!`, `${timeGreeting}!早晨是制定健康计划的最佳时机,我是${botName},可以帮你管理营养摄入、运动计划和生活作息。`, - `${timeGreeting},${name}!作为你的海豹助手,我很高兴能陪伴你的健康之旅。无论是饮食营养、健身锻炼还是生活管理,我都能为你提供专业建议。` + `${timeGreeting},${name}!作为你的Seal,我很高兴能陪伴你的健康之旅。无论是饮食营养、健身锻炼还是生活管理,我都能为你提供专业建议。` ] }, { @@ -215,7 +216,7 @@ export default function CoachScreen() { messages: [ `${timeGreeting},${name}!午餐时间很关键呢,合理的营养搭配能为下午提供充足能量。我是${botName},可以为你分析饮食营养和热量管理。`, `${timeGreeting}!忙碌的上午结束了,该关注一下身体需求啦。我是你的健康助手${botName},无论是饮食调整、运动安排还是休息建议,都可以找我。`, - `${timeGreeting},${name}!午间是调整状态的好时机。作为你的海豹助手,我建议关注饮食均衡和适度放松~` + `${timeGreeting},${name}!午间是调整状态的好时机。作为你的Seal,我建议关注饮食均衡和适度放松~` ] }, { @@ -231,7 +232,7 @@ export default function CoachScreen() { messages: [ `${timeGreeting},${name}!忙碌了一天,现在是时候关注身心平衡了。我是${botName},可以为你提供放松建议、营养补充和恢复方案。`, `${timeGreeting}!夜幕降临,这是一天中最适合总结和调整的时刻。我是你的健康伙伴${botName},让我们一起回顾今天的健康表现,规划明天的目标。`, - `${timeGreeting},${name}!晚间时光属于你自己,也是关爱身体的珍贵时间。作为你的海豹助手,我想陪你聊聊如何更好地管理健康生活。` + `${timeGreeting},${name}!晚间时光属于你自己,也是关爱身体的珍贵时间。作为你的Seal,我想陪你聊聊如何更好地管理健康生活。` ] }, { @@ -252,7 +253,7 @@ export default function CoachScreen() { }, { condition: () => userProfile && (!userProfile.pilatesPurposes || userProfile.pilatesPurposes.length === 0), - message: `${timeGreeting},${name}!作为你的海豹助手,我想更好地了解你的健康需求。告诉我你希望在营养摄入、身材管理、健身锻炼或生活管理方面实现什么目标吧~` + message: `${timeGreeting},${name}!作为你的Seal,我想更好地了解你的健康需求。告诉我你希望在营养摄入、身材管理、健身锻炼或生活管理方面实现什么目标吧~` } ]; @@ -1236,7 +1237,7 @@ export default function CoachScreen() { - 选择合适的方式记录您的饮食,海豹助手会根据您的饮食情况给出专业的营养建议。 + 选择合适的方式记录您的饮食,Seal会根据您的饮食情况给出专业的营养建议。 ); } @@ -1278,7 +1279,7 @@ export default function CoachScreen() { 发送记录 - 详细描述您的饮食内容和分量,有助于海豹助手给出更精准的营养分析和建议。 + 详细描述您的饮食内容和分量,有助于Seal给出更精准的营养分析和建议。 ); } @@ -1825,7 +1826,32 @@ export default function CoachScreen() { if (h && Math.abs(h - headerHeight) > 0.5) setHeaderHeight(h); }} > - {botName} + + {botName} + + {/* 使用次数显示 */} + { + // 临时测试:切换VIP状态 + const dispatch = useAppDispatch(); + dispatch(updateProfile({ + isVip: !userProfile?.isVip, + freeUsageCount: userProfile?.isVip ? 3 : 5, + maxUsageCount: userProfile?.isVip ? 5 : 10 + })); + }} + > + + + {userProfile?.isVip ? '不限' : `${userProfile?.freeUsageCount || 0}/${userProfile?.maxUsageCount || 0}`} + + + + {days.map((d, i) => { const selected = i === selectedIndex; + const isFutureDate = d.date.isAfter(dayjs(), 'day'); return ( onSelectDate(i)} - activeOpacity={0.8} + style={[ + styles.dayPill, + selected ? styles.dayPillSelected : styles.dayPillNormal, + isFutureDate && styles.dayPillDisabled + ]} + onPress={() => !isFutureDate && onSelectDate(i)} + activeOpacity={isFutureDate ? 1 : 0.8} + disabled={isFutureDate} > - {d.weekdayZh} - {d.dayOfMonth} + {d.weekdayZh} + {d.dayOfMonth} {selected && } @@ -319,9 +332,6 @@ export default function ExploreScreen() { - - - 步数 {stepCount != null ? ( @@ -367,9 +377,6 @@ export default function ExploreScreen() { - - - 睡眠 {sleepDuration != null ? ( @@ -443,6 +450,10 @@ const styles = StyleSheet.create({ dayPillSelected: { backgroundColor: lightColors.datePickerSelected, }, + dayPillDisabled: { + backgroundColor: '#F5F5F5', + opacity: 0.5, + }, dayLabel: { fontSize: 12, fontWeight: '700', @@ -452,6 +463,9 @@ const styles = StyleSheet.create({ dayLabelSelected: { color: '#FFFFFF', }, + dayLabelDisabled: { + color: '#9AA3AE', + }, dayDate: { fontSize: 12, fontWeight: '800', @@ -460,6 +474,9 @@ const styles = StyleSheet.create({ dayDateSelected: { color: '#FFFFFF', }, + dayDateDisabled: { + color: '#9AA3AE', + }, selectedDot: { width: 5, height: 5, diff --git a/assets/images/icons/iconFlash.png b/assets/images/icons/iconFlash.png new file mode 100644 index 0000000..38b7f5f Binary files /dev/null and b/assets/images/icons/iconFlash.png differ diff --git a/components/StressAnalysisModal.tsx b/components/StressAnalysisModal.tsx index 0545e93..12baef3 100644 --- a/components/StressAnalysisModal.tsx +++ b/components/StressAnalysisModal.tsx @@ -56,7 +56,7 @@ export function StressAnalysisModal({ visible, onClose, hrvValue, updateTime }: - - 好事发生 + + 鸭梨山大 活力满满 - - 鸭梨山大 + + 好事发生 diff --git a/components/StressMeter.tsx b/components/StressMeter.tsx index 0610e3c..a5066eb 100644 --- a/components/StressMeter.tsx +++ b/components/StressMeter.tsx @@ -1,4 +1,3 @@ -import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; import React, { useState } from 'react'; import { StyleSheet, Text, TouchableOpacity, View } from 'react-native'; @@ -19,9 +18,9 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP const getStressStatus = () => { if (value === null) { return '未知'; - } else if (value <= 30) { + } else if (value >= 70) { return '放松'; - } else if (value <= 70) { + } else if (value >= 30) { return '正常'; } else { return '紧张'; @@ -46,7 +45,7 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP }; // 计算进度条位置(0-100%) - // 压力指数越高,进度条越满 + // 压力指数越高,进度条越满(红色区域越多) const progressPercentage = value !== null ? Math.max(0, Math.min(100, value)) : 0; // 在组件内部添加状态 @@ -67,9 +66,6 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP {/* 头部区域 */} - - - 压力 {getStatusEmoji()} @@ -87,7 +83,7 @@ export function StressMeter({ value, updateTime, style, hrvValue }: StressMeterP {/* 渐变背景进度条 */}