import React, { useCallback, useRef, useState } from "react"; import { Animated, Pressable, Text, View } from "react-native"; import * as Haptics from "expo-haptics"; import { startRecording, stopRecording } from "../../services/audio"; import { Audio } from "expo-av"; interface VoiceButtonProps { onVoiceMessage: (audioUri: string, durationMs: number) => void; } const VOICE_BUTTON_SIZE = 88; export function VoiceButton({ onVoiceMessage }: VoiceButtonProps) { const [isRecording, setIsRecording] = useState(false); const recordingRef = useRef(null); const scaleAnim = useRef(new Animated.Value(1)).current; const pulseAnim = useRef(new Animated.Value(1)).current; const pulseLoop = useRef(null); const startPulse = useCallback(() => { pulseLoop.current = Animated.loop( Animated.sequence([ Animated.timing(pulseAnim, { toValue: 1.15, duration: 600, useNativeDriver: true, }), Animated.timing(pulseAnim, { toValue: 1, duration: 600, useNativeDriver: true, }), ]) ); pulseLoop.current.start(); }, [pulseAnim]); const stopPulse = useCallback(() => { pulseLoop.current?.stop(); pulseAnim.setValue(1); }, [pulseAnim]); const handlePressIn = useCallback(async () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); Animated.spring(scaleAnim, { toValue: 0.92, useNativeDriver: true, }).start(); const recording = await startRecording(); if (recording) { recordingRef.current = recording; setIsRecording(true); startPulse(); } }, [scaleAnim, startPulse]); const handlePressOut = useCallback(async () => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); Animated.spring(scaleAnim, { toValue: 1, useNativeDriver: true, }).start(); stopPulse(); setIsRecording(false); if (recordingRef.current) { const result = await stopRecording(); recordingRef.current = null; if (result && result.durationMs > 500) { onVoiceMessage(result.uri, result.durationMs); } } }, [scaleAnim, stopPulse, onVoiceMessage]); return ( {/* Pulse ring — only visible while recording */} {/* Button */} {isRecording ? "🎙" : "🎤"} {isRecording ? "Release to send" : "Hold to talk"} ); }