/** * WaveAnimation — flowing wave bars used in "My Wave" header * Simulates audio wave / signal motion with staggered sine animation */ import { useEffect } from 'react'; import { View, StyleSheet } from 'react-native'; import Animated, { useSharedValue, useAnimatedStyle, withRepeat, withSequence, withTiming, Easing, cancelAnimation, } from 'react-native-reanimated'; import { Colors } from '../constants/theme'; interface Props { active?: boolean; barCount?: number; height?: number; color?: string; } const PHASES = [0, 0.4, 0.8, 0.2, 0.6, 0.1, 0.7, 0.3, 0.9, 0.5, 0.15, 0.55, 0.85, 0.25, 0.65]; const BASE_DURATION = 900; function WaveBar({ active, maxH, phase, color }: { active: boolean; maxH: number; phase: number; color: string; }) { const h = useSharedValue(maxH * 0.15); useEffect(() => { if (active) { const delay = Math.round(phase * BASE_DURATION); h.value = withSequence( withTiming(maxH * 0.15, { duration: delay }), withRepeat( withSequence( withTiming(maxH, { duration: BASE_DURATION, easing: Easing.inOut(Easing.sin) }), withTiming(maxH * 0.1, { duration: BASE_DURATION, easing: Easing.inOut(Easing.sin) }), ), -1, false, ) ); } else { cancelAnimation(h); h.value = withTiming(maxH * 0.12, { duration: 400 }); } }, [active]); const style = useAnimatedStyle(() => ({ height: h.value, backgroundColor: color, borderRadius: 3, flex: 1, marginHorizontal: 1.5, })); return ; } export default function WaveAnimation({ active = true, barCount = 40, height = 56, color }: Props) { const bars = Array.from({ length: barCount }, (_, i) => i); const barColor = color ?? Colors.accent; return ( {bars.map((i) => ( ))} ); } const s = StyleSheet.create({ wrap: { flexDirection: 'row', alignItems: 'flex-end', overflow: 'hidden' }, });