'use client'; import React, { useCallback, useState } from 'react'; import { Platform, StyleSheet, TextInput, View } from 'react-native'; import { RecordingPresets, useAudioRecorder } from 'expo-audio'; interface Props { setIsHello: (isHello: boolean) => void, setInputValue: (inputValue: string) => void, inputValue: string, createNewConversation: (user_text: string) => void, conversationId: string | null, getConversation: ({ user_text, session_id }: { user_text: string, session_id: string }) => void } export default function AudioRecordPlay(props: Props) { const { setIsHello, setInputValue, inputValue, createNewConversation, conversationId, getConversation } = props; const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY); const [isRecording, setIsRecording] = useState(false); const [isVoiceStart, setIsVoiceStart] = useState(false); const [elapsedTime, setElapsedTime] = useState(0); const [timerInterval, setTimerInterval] = useState(0); const formatTime = (ms: number): string => { const totalSeconds = ms / 1000; const minutes = Math.floor(totalSeconds / 60); const seconds = Math.floor(totalSeconds % 60); const milliseconds = Math.floor(ms % 1000); return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}.${String(milliseconds).padStart(3, '0')}`; }; // 开始录音 const record = async () => { await audioRecorder.prepareToRecordAsync(); const startTime = Date.now(); // 每 10ms 更新一次时间 const interval = setInterval(() => { const elapsed = Date.now() - startTime; setElapsedTime(elapsed); }, 10); setTimerInterval(interval); setIsVoiceStart(true) audioRecorder.record(); setIsRecording(true); }; const stopRecording = async () => { // The recording will be available on `audioRecorder.uri`. if (timerInterval) clearInterval(timerInterval); setTimerInterval(0); await audioRecorder.stop(); setIsRecording(false); }; // useEffect(() => { // (async () => { // const status = await AudioModule.requestRecordingPermissionsAsync(); // if (!status.granted) { // Alert.alert('Permission to access microphone was denied'); // } // })(); // }, []); // 使用 useCallback 缓存回调函数 const handleChangeText = useCallback((text: string) => { setInputValue(text); }, []); // 使用 useCallback 缓存 handleSubmit const handleSubmit = useCallback(() => { const text = inputValue.trim(); if (text) { if (!conversationId) { createNewConversation(text); setIsHello(false); } else { getConversation({ session_id: conversationId, user_text: text }); } setInputValue(''); } }, [conversationId]); // 使用 useCallback 缓存 handleKeyPress const handleKeyPress = useCallback((e: any) => { if (Platform.OS === 'web' && e.nativeEvent.key !== 'Enter') { return; } handleSubmit(); }, [handleSubmit]); return ( {/* console.log('Left icon pressed')} className={`absolute left-2 top-1/2 -translate-y-1/2 p-2 bg-white rounded-full ${isVoiceStart ? "opacity-100" : "opacity-0"}`} // 使用绝对定位将按钮放在输入框内右侧 > */} { setInputValue(text); }} onSubmitEditing={handleSubmit} editable={!isVoiceStart} // 调起的键盘类型 returnKeyType="send" /> {/* {isVoiceStart ? : } */} ); } const styles = StyleSheet.create({ container: { justifyContent: 'center', backgroundColor: '#fff', }, title: { fontSize: 20, fontWeight: 'bold', marginBottom: 20, textAlign: 'center', }, recordButton: { padding: 15, borderRadius: 8, alignItems: 'center', marginBottom: 20, }, startButton: { backgroundColor: '#ff6b6b', }, stopButton: { backgroundColor: '#4CAF50', }, buttonText: { color: 'white', fontSize: 16, }, listTitle: { fontWeight: 'bold', marginBottom: 10, }, emptyText: { fontStyle: 'italic', color: '#888', marginBottom: 10, }, recordingItem: { padding: 10, borderBottomWidth: 1, borderBottomColor: '#eee', }, uriText: { fontSize: 12, color: '#777', }, leftIcon: { padding: 10, paddingLeft: 15, }, input: { borderColor: '#FF9500', borderWidth: 1, borderRadius: 25, paddingHorizontal: 20, paddingVertical: 12, fontSize: 16, width: '100%', // 确保输入框宽度撑满 paddingRight: 50 }, voiceButton: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#FF9500', justifyContent: 'center', alignItems: 'center', marginRight: 8, // 添加一点右边距 }, });