import { useRef, useEffect } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, Animated } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useColors } from '../../lib/theme'; export function formatVoiceDuration(s: number): string { const m = Math.floor(s / 60); const sec = (s % 60).toString().padStart(2, '0'); return `${m}:${sec}`; } export function VoiceBars({ count, baseColor, active }: { count: number; baseColor: string; active: boolean }) { const anims = useRef(Array.from({ length: count }, () => new Animated.Value(3))).current; const runningRef = useRef(false); useEffect(() => { if (active && !runningRef.current) { runningRef.current = true; const animations = anims.map((a, i) => Animated.loop( Animated.sequence([ Animated.timing(a, { toValue: 3 + Math.random() * 14, duration: 400 + (i % 5) * 90, useNativeDriver: false }), Animated.timing(a, { toValue: 3, duration: 400 + (i % 5) * 90, useNativeDriver: false }), ]) ) ); animations.forEach((a) => a.start()); return () => { animations.forEach((a) => a.stop()); runningRef.current = false; }; } else if (!active) { anims.forEach((a) => Animated.timing(a, { toValue: 3, duration: 150, useNativeDriver: false }).start()); runningRef.current = false; } }, [active]); return ( {anims.map((a, i) => ( ))} ); } type Props = { duration: number; level: number; trashFlash: boolean; onCancel: () => void; onSend: () => void; /** Icon for the send button. Default: 'arrow-up' (coach). DM uses 'checkmark'. */ sendIcon?: 'arrow-up' | 'checkmark'; /** Accent color for the send button. Defaults to brandOrange. */ accentColor?: string; }; export function VoiceRecordingBar({ duration, level, trashFlash, onCancel, onSend, sendIcon = 'arrow-up', accentColor }: Props) { const colors = useColors(); const accent = accentColor ?? colors.brandOrange; return ( 0.1} /> {formatVoiceDuration(duration)} ); } const styles = StyleSheet.create({ bar: { flex: 1, height: 44, flexDirection: 'row', alignItems: 'center', gap: 8, borderWidth: StyleSheet.hairlineWidth, borderRadius: 22, paddingHorizontal: 6, }, sideBtn: { width: 36, height: 36, borderRadius: 18, alignItems: 'center', justifyContent: 'center', }, center: { flex: 1, flexDirection: 'row', alignItems: 'center', gap: 6, }, liveDot: { width: 7, height: 7, borderRadius: 3.5, }, timer: { fontSize: 12, fontFamily: 'Nunito_600SemiBold', fontVariant: ['tabular-nums'], minWidth: 32, }, });