/** * TabataFit Activity Screen * React Native + SwiftUI Islands — wired to shared data */ import { View, StyleSheet, ScrollView, Dimensions, Text as RNText } from 'react-native' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { LinearGradient } from 'expo-linear-gradient' import { BlurView } from 'expo-blur' import Ionicons from '@expo/vector-icons/Ionicons' import { Host, Gauge, Text, HStack, VStack, Chart, List, } from '@expo/ui/swift-ui' import { useMemo } from 'react' import { useActivityStore, getWeeklyActivity } from '@/src/shared/stores' import { getWorkoutById } from '@/src/shared/data' import { ACHIEVEMENTS } from '@/src/shared/data' import { StyledText } from '@/src/shared/components/StyledText' import { BRAND, DARK, TEXT as TEXT_COLORS, GLASS, GRADIENTS, } from '@/src/shared/constants/colors' import { SPACING, LAYOUT } from '@/src/shared/constants/spacing' import { RADIUS } from '@/src/shared/constants/borderRadius' const { width: SCREEN_WIDTH } = Dimensions.get('window') const FONTS = { LARGE_TITLE: 34, TITLE_2: 22, SUBHEADLINE: 15, CAPTION_1: 12, } // ═══════════════════════════════════════════════════════════════════════════ // MAIN SCREEN // ═══════════════════════════════════════════════════════════════════════════ export default function ActivityScreen() { const insets = useSafeAreaInsets() const streak = useActivityStore((s) => s.streak) const history = useActivityStore((s) => s.history) const totalWorkouts = history.length const totalMinutes = useMemo(() => history.reduce((sum, r) => sum + r.durationMinutes, 0), [history]) const totalCalories = useMemo(() => history.reduce((sum, r) => sum + r.calories, 0), [history]) const recentWorkouts = useMemo(() => history.slice(0, 3), [history]) const weeklyActivity = useMemo(() => getWeeklyActivity(history), [history]) // Check achievements const unlockedAchievements = ACHIEVEMENTS.filter(a => { switch (a.type) { case 'workouts': return totalWorkouts >= a.requirement case 'streak': return streak.longest >= a.requirement case 'minutes': return totalMinutes >= a.requirement case 'calories': return totalCalories >= a.requirement default: return false } }) const displayAchievements = ACHIEVEMENTS.slice(0, 5).map(a => ({ ...a, unlocked: unlockedAchievements.some(u => u.id === a.id), })) // Format recent workout dates const formatDate = (timestamp: number) => { const now = Date.now() const diff = now - timestamp if (diff < 86400000) return 'Today' if (diff < 172800000) return 'Yesterday' return Math.floor(diff / 86400000) + ' days ago' } return ( {/* Header */} Activity {/* Streak Banner */} {(streak.current || 0) + ' Day Streak'} {streak.current > 0 ? 'Keep it going!' : 'Start your streak today!'} {/* SwiftUI Island: Stats Gauges */} Workouts Minutes Calories Best Streak {/* SwiftUI Island: This Week Chart */} This Week ({ x: d.date, y: d.completed ? 1 : 0, color: d.completed ? BRAND.PRIMARY : '#333333', }))} barStyle={{ cornerRadius: 4 }} style={{ height: 160 }} /> {/* SwiftUI Island: Recent Workouts */} {recentWorkouts.length > 0 && ( Recent {recentWorkouts.map((result) => { const workout = getWorkoutById(result.workoutId) return ( {workout?.title ?? 'Workout'} {formatDate(result.completedAt)} {result.durationMinutes + ' min'} {result.calories + ' cal'} ) })} )} {/* Achievements */} Achievements {displayAchievements.map((achievement) => ( {achievement.title} ))} ) } // ═══════════════════════════════════════════════════════════════════════════ // STYLES // ═══════════════════════════════════════════════════════════════════════════ const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: DARK.BASE, }, scrollView: { flex: 1, }, scrollContent: { paddingHorizontal: LAYOUT.SCREEN_PADDING, }, // Streak Banner streakBanner: { height: 80, borderRadius: RADIUS.GLASS_CARD, overflow: 'hidden', marginBottom: SPACING[6], marginTop: SPACING[4], }, streakContent: { flex: 1, flexDirection: 'row', alignItems: 'center', paddingHorizontal: SPACING[5], gap: SPACING[4], }, streakText: { flex: 1, }, // Stats Island statsIsland: { marginBottom: SPACING[8], }, // Chart Island chartIsland: { marginTop: SPACING[2], }, // Section section: { marginBottom: SPACING[6], }, // Achievements achievementsGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACING[3], }, achievementBadge: { width: (SCREEN_WIDTH - LAYOUT.SCREEN_PADDING * 2 - SPACING[3] * 2) / 3, aspectRatio: 1, borderRadius: RADIUS.LG, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.1)', overflow: 'hidden', }, achievementLocked: { opacity: 0.5, }, achievementIcon: { width: 48, height: 48, borderRadius: 24, backgroundColor: 'rgba(255, 107, 53, 0.15)', alignItems: 'center', justifyContent: 'center', marginBottom: SPACING[2], }, achievementIconLocked: { backgroundColor: 'rgba(255, 255, 255, 0.05)', }, })