import { PlanCard } from '@/components/PlanCard'; import { SearchBox } from '@/components/SearchBox'; import { ThemedText } from '@/components/ThemedText'; import { ThemedView } from '@/components/ThemedView'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; // Removed WorkoutCard import since we no longer use the horizontal carousel import { useAuthGuard } from '@/hooks/useAuthGuard'; import { getChineseGreeting } from '@/utils/date'; import { useRouter } from 'expo-router'; import React from 'react'; import { Animated, Image, PanResponder, Pressable, SafeAreaView, ScrollView, StyleSheet, useWindowDimensions, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; // 移除旧的“热门活动”滑动数据,改为固定的“热点功能”卡片 export default function HomeScreen() { const router = useRouter(); const { pushIfAuthedElseLogin } = useAuthGuard(); const theme = (useColorScheme() ?? 'light') as 'light' | 'dark'; const colorTokens = Colors[theme]; const insets = useSafeAreaInsets(); const { width: windowWidth, height: windowHeight } = useWindowDimensions(); // Draggable coach badge state const pan = React.useRef(new Animated.ValueXY()).current; const [coachSize, setCoachSize] = React.useState({ width: 0, height: 0 }); const hasInitPos = React.useRef(false); const startRef = React.useRef({ x: 0, y: 0 }); const dragState = React.useRef({ moved: false }); const clamp = (value: number, min: number, max: number) => Math.max(min, Math.min(max, value)); const panResponder = React.useMemo(() => PanResponder.create({ onStartShouldSetPanResponder: () => true, onMoveShouldSetPanResponder: (_evt, gesture) => Math.abs(gesture.dx) + Math.abs(gesture.dy) > 2, onPanResponderGrant: () => { dragState.current.moved = false; // @ts-ignore access current value const currentX = (pan.x as any)._value ?? 0; // @ts-ignore access current value const currentY = (pan.y as any)._value ?? 0; startRef.current = { x: currentX, y: currentY }; }, onPanResponderMove: (_evt, gesture) => { if (!dragState.current.moved && (Math.abs(gesture.dx) + Math.abs(gesture.dy) > 4)) { dragState.current.moved = true; } const nextX = startRef.current.x + gesture.dx; const nextY = startRef.current.y + gesture.dy; pan.setValue({ x: nextX, y: nextY }); }, onPanResponderRelease: (_evt, gesture) => { const minX = 8; const minY = insets.top + 2; const maxX = Math.max(minX, windowWidth - coachSize.width - 8); const maxY = Math.max(minY, windowHeight - coachSize.height - (insets.bottom + 8)); const rawX = startRef.current.x + gesture.dx; const rawY = startRef.current.y + gesture.dy; const clampedX = clamp(rawX, minX, maxX); const clampedY = clamp(rawY, minY, maxY); // Snap horizontally to nearest side (left/right only) const distLeft = Math.abs(clampedX - minX); const distRight = Math.abs(maxX - clampedX); const snapX = distLeft <= distRight ? minX : maxX; Animated.spring(pan, { toValue: { x: snapX, y: clampedY }, useNativeDriver: false, bounciness: 6 }).start(() => { if (!dragState.current.moved) { // Treat as tap // @ts-ignore - expo-router string ok router.push('/ai-coach-chat?name=Iris' as any); } }); }, }), [coachSize.height, coachSize.width, insets.bottom, insets.top, pan, windowHeight, windowWidth, router]); return ( {/* Floating Coach Badge */} { const { width, height } = e.nativeEvent.layout; if (width !== coachSize.width || height !== coachSize.height) { setCoachSize({ width, height }); } if (!hasInitPos.current && width > 0 && windowWidth > 0) { const initX = windowWidth - width - 14; const initY = insets.top + 2; // 默认更靠上,避免遮挡搜索框 pan.setValue({ x: initX, y: initY }); hasInitPos.current = true; } }} style={[ styles.coachBadge, { transform: [{ translateX: pan.x }, { translateY: pan.y }], backgroundColor: colorTokens.heroSurfaceTint, borderColor: 'rgba(187,242,70,0.35)', shadowColor: '#000', shadowOpacity: 0.08, shadowRadius: 10, shadowOffset: { width: 0, height: 4 }, elevation: 3, position: 'absolute', left: 0, top: 0, }, ]} > Iris 在线 {/* Header Section */} {getChineseGreeting()} 🔥 新学员,欢迎你 {/* Search Box */} {/* Hot Features Section */} 热点功能 router.push('/ai-posture-assessment')} > AI体态评估 3分钟获取体态报告 开始评估 router.push('/ai-coach-chat?name=Sarah' as any)} > 在线教练 认证教练 · 1对1即时解答 立即咨询 {/* Today Plan Section */} 为你推荐 pushIfAuthedElseLogin('/challenge')}> pushIfAuthedElseLogin('/training-plan')}> pushIfAuthedElseLogin('/checkin')}> {/* Add some spacing at the bottom */} ); } const styles = StyleSheet.create({ safeArea: { flex: 1, backgroundColor: '#F7F8FA', }, container: { flex: 1, backgroundColor: '#F7F8FA', }, header: { paddingHorizontal: 24, paddingTop: 16, paddingBottom: 8, }, coachOverlayWrap: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 10, }, greeting: { fontSize: 16, color: '#8A8A8E', fontWeight: '400', marginBottom: 6, }, userName: { fontSize: 30, fontWeight: 'bold', color: '#1A1A1A', lineHeight: 36, }, coachBadge: { flexDirection: 'row', alignItems: 'center', // RN 不完全支持 gap,这里用 margin 实现 paddingHorizontal: 10, paddingVertical: 8, borderRadius: 20, borderWidth: 1, backgroundColor: '#FFFFFF00', }, coachAvatar: { width: 26, height: 26, borderRadius: 13, }, coachMeta: { marginLeft: 8, }, coachName: { fontSize: 13, fontWeight: '700', color: '#192126', }, coachStatusRow: { flexDirection: 'row', alignItems: 'center', marginTop: 2, }, statusDot: { width: 6, height: 6, borderRadius: 3, backgroundColor: '#22C55E', marginRight: 4, }, coachStatusText: { fontSize: 11, color: '#6B7280', }, sectionContainer: { marginTop: 24, }, sectionTitle: { fontSize: 24, fontWeight: 'bold', color: '#1A1A1A', paddingHorizontal: 24, marginBottom: 18, }, featureGrid: { paddingHorizontal: 24, flexDirection: 'row', justifyContent: 'space-between', }, featureCard: { width: '48%', borderRadius: 16, padding: 16, backgroundColor: '#FFFFFF', // iOS shadow shadowColor: '#000', shadowOpacity: 0.08, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, // Android shadow elevation: 4, }, featureCardPrimary: { backgroundColor: '#EEF2FF', // 柔和的靛蓝背景 }, featureCardSecondary: { backgroundColor: '#F0FDFA', // 柔和的青绿背景 }, featureIcon: { fontSize: 28, marginBottom: 8, }, featureTitle: { fontSize: 18, fontWeight: '700', color: '#0F172A', marginBottom: 6, }, featureSubtitle: { fontSize: 12, color: '#6B7280', lineHeight: 16, marginBottom: 12, }, featureCta: { alignSelf: 'flex-start', backgroundColor: '#0F172A', paddingHorizontal: 10, paddingVertical: 6, borderRadius: 999, }, featureCtaText: { color: '#FFFFFF', fontSize: 12, fontWeight: '600', }, planList: { paddingHorizontal: 24, }, // 移除旧的滑动样式 bottomSpacing: { height: 120, }, });