diff --git a/components/VoiceFAB.tsx b/components/VoiceFAB.tsx index 8baebe5..476ea7c 100644 --- a/components/VoiceFAB.tsx +++ b/components/VoiceFAB.tsx @@ -35,6 +35,8 @@ export function VoiceFAB({ onPress, style, disabled = false, isListening = false // Animation values const scale = useRef(new Animated.Value(1)).current; const opacity = useRef(new Animated.Value(1)).current; + const pulseScale = useRef(new Animated.Value(1)).current; + const pulseOpacity = useRef(new Animated.Value(0)).current; // Hide FAB when call is active useEffect(() => { @@ -68,6 +70,51 @@ export function VoiceFAB({ onPress, style, disabled = false, isListening = false } }, [isCallActive, scale, opacity]); + // Pulse animation when listening + useEffect(() => { + if (isListening && !isCallActive) { + // Start pulsing animation + const pulseAnimation = Animated.loop( + Animated.sequence([ + Animated.parallel([ + Animated.timing(pulseScale, { + toValue: 1.8, + duration: 1000, + useNativeDriver: true, + }), + Animated.timing(pulseOpacity, { + toValue: 0, + duration: 1000, + useNativeDriver: true, + }), + ]), + Animated.parallel([ + Animated.timing(pulseScale, { + toValue: 1, + duration: 0, + useNativeDriver: true, + }), + Animated.timing(pulseOpacity, { + toValue: 0.6, + duration: 0, + useNativeDriver: true, + }), + ]), + ]) + ); + pulseAnimation.start(); + + return () => { + pulseAnimation.stop(); + pulseScale.setValue(1); + pulseOpacity.setValue(0); + }; + } else { + pulseScale.setValue(1); + pulseOpacity.setValue(0); + } + }, [isListening, isCallActive, pulseScale, pulseOpacity]); + // Press animation with haptic feedback const handlePressIn = () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); @@ -103,6 +150,18 @@ export function VoiceFAB({ onPress, style, disabled = false, isListening = false style, ]} > + {/* Pulse ring when listening */} + {isListening && ( + + )}