/** * SpectrumBars — animated equalizer bars for MiniPlayer / Player */ import { useEffect } from 'react'; import { View, StyleSheet } from 'react-native'; import Animated, { useSharedValue, useAnimatedStyle, withRepeat, withSequence, withTiming, Easing, cancelAnimation, } from 'react-native-reanimated'; interface Props { playing: boolean; color?: string; barCount?: number; height?: number; } const DURATIONS = [420, 350, 500, 380, 460]; const HEIGHTS = [0.4, 0.7, 0.55, 0.85, 0.5]; function Bar({ playing, color, maxH, duration, minRatio }: { playing: boolean; color: string; maxH: number; duration: number; minRatio: number; }) { const h = useSharedValue(maxH * minRatio); useEffect(() => { if (playing) { h.value = withRepeat( withSequence( withTiming(maxH, { duration, easing: Easing.inOut(Easing.ease) }), withTiming(maxH * 0.2, { duration, easing: Easing.inOut(Easing.ease) }), ), -1, true, ); } else { cancelAnimation(h); h.value = withTiming(maxH * 0.25, { duration: 300 }); } }, [playing]); const style = useAnimatedStyle(() => ({ height: h.value, backgroundColor: color, borderRadius: 2, width: 3, })); return ; } export default function SpectrumBars({ playing, color = '#ffffff', barCount = 4, height = 18 }: Props) { const bars = Array.from({ length: barCount }, (_, i) => i); return ( {bars.map((i) => ( ))} ); } const s = StyleSheet.create({ wrap: { flexDirection: 'row', alignItems: 'flex-end', gap: 2 }, });