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 && (
+
+ )}