Files
tabatago/app/(tabs)/index.tsx
Millian Lamiaux 31bdb1586f feat: timer engine + full-screen timer UI
Implement the core timer feature following the src/features/ architecture:

- useTimerEngine hook: drift-free Date.now() delta countdown (100ms tick),
  explicit state machine (IDLE → GET_READY → WORK → REST → COMPLETE),
  event emitter for external consumers (PHASE_CHANGED, ROUND_COMPLETED,
  COUNTDOWN_TICK, SESSION_COMPLETE), auto-pause on AppState interruption
  (phone calls, background), expo-keep-awake during session
- TimerDisplay component: full-screen animated UI with 600ms color
  transitions between phases, pulse animation on countdown, flash red
  on last 3 seconds, round progress dots, IDLE/active/COMPLETE views
- TimerControls component: stop/pause-resume/skip buttons with Ionicons
- Timer route (app/timer.tsx): fullScreenModal wiring hook → display
- Home screen: dark theme with START button navigating to /timer
- Project docs: CLAUDE.md (constitution), PRD v1.1, skill files
- Shared constants: PHASE_COLORS, TIMER_DEFAULTS, formatTime utility
- Types: TimerPhase, TimerState, TimerConfig, TimerActions, TimerEvent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 19:05:25 +01:00

68 lines
1.5 KiB
TypeScript

import { Pressable, StyleSheet, Text, View } from 'react-native'
import { useRouter } from 'expo-router'
import { StatusBar } from 'expo-status-bar'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
export default function HomeScreen() {
const router = useRouter()
const insets = useSafeAreaInsets()
return (
<View style={[styles.container, { paddingTop: insets.top + 24 }]}>
<StatusBar style="light" />
<Text style={styles.title}>TABATAGO</Text>
<Text style={styles.subtitle}>Entraînement Tabata</Text>
<Pressable
style={({ pressed }) => [
styles.startButton,
pressed && styles.startButtonPressed,
]}
onPress={() => router.push('/timer')}
>
<Text style={styles.startButtonText}>START</Text>
</Pressable>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#1E1E2E',
alignItems: 'center',
justifyContent: 'center',
gap: 12,
},
title: {
fontSize: 44,
fontWeight: '900',
color: '#FFFFFF',
letterSpacing: 6,
},
subtitle: {
fontSize: 18,
color: 'rgba(255, 255, 255, 0.6)',
fontWeight: '500',
},
startButton: {
width: 160,
height: 160,
borderRadius: 80,
backgroundColor: '#F97316',
alignItems: 'center',
justifyContent: 'center',
marginTop: 60,
},
startButtonPressed: {
opacity: 0.7,
},
startButtonText: {
fontSize: 32,
fontWeight: '900',
color: '#FFFFFF',
letterSpacing: 4,
},
})