parent
9505429c5a
commit
23cc71a3a3
Before Width: | Height: | Size: 13 KiB |
@ -1,180 +0,0 @@
|
|||||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
|
||||||
import { View, Text, TouchableOpacity, StyleSheet, Image, Touchable } from "react-native";
|
|
||||||
import * as FileSystem from "expo-file-system";
|
|
||||||
import { AVPlaybackStatus, AVPlaybackStatusSuccess, Audio } from "expo-av";
|
|
||||||
import { create } from "zustand";
|
|
||||||
import useStore from "../utils/state";
|
|
||||||
import { Animated } from "react-native";
|
|
||||||
import * as Haptics from "expo-haptics";
|
|
||||||
import useSoundEffect from "../utils/useSoundEffect";
|
|
||||||
|
|
||||||
import { useNavigation } from "@react-navigation/native";
|
|
||||||
|
|
||||||
interface RecordButtonProps {
|
|
||||||
playPip: () => void;
|
|
||||||
playPop: () => void;
|
|
||||||
recording: Audio.Recording | null;
|
|
||||||
setRecording: (recording: Audio.Recording | null) => void;
|
|
||||||
ws: WebSocket | null;
|
|
||||||
backgroundColorAnim: Animated.Value;
|
|
||||||
buttonBackgroundColorAnim: Animated.Value;
|
|
||||||
setIsPressed: (isPressed: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
middle: {
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
padding: 10,
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
circle: {
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
borderRadius: 50,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
},
|
|
||||||
qr: {
|
|
||||||
position: "absolute",
|
|
||||||
top: 30,
|
|
||||||
left: 10,
|
|
||||||
padding: 10,
|
|
||||||
zIndex: 100,
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
height: 40,
|
|
||||||
width: 40,
|
|
||||||
},
|
|
||||||
topBar: {
|
|
||||||
height: 40,
|
|
||||||
backgroundColor: "#000",
|
|
||||||
paddingTop: 50,
|
|
||||||
},
|
|
||||||
|
|
||||||
button: {
|
|
||||||
width: 100,
|
|
||||||
height: 100,
|
|
||||||
borderRadius: 50,
|
|
||||||
justifyContent: "center",
|
|
||||||
alignItems: "center",
|
|
||||||
},
|
|
||||||
buttonTextDefault: {
|
|
||||||
color: "black",
|
|
||||||
fontSize: 16,
|
|
||||||
},
|
|
||||||
buttonTextRecording: {
|
|
||||||
color: "white",
|
|
||||||
fontSize: 16,
|
|
||||||
},
|
|
||||||
statusText: {
|
|
||||||
position: "absolute",
|
|
||||||
bottom: 20,
|
|
||||||
alignSelf: "center",
|
|
||||||
fontSize: 12,
|
|
||||||
fontWeight: "bold",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const RecordButton = ({ playPip, playPop, recording, setRecording, ws, backgroundColorAnim, buttonBackgroundColorAnim, setIsPressed}: RecordButtonProps) => {
|
|
||||||
const [permissionResponse, requestPermission] = Audio.usePermissions();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log("Permission Response:", permissionResponse);
|
|
||||||
if (permissionResponse?.status !== "granted") {
|
|
||||||
console.log("Requesting permission..");
|
|
||||||
requestPermission();
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const startRecording = useCallback(async () => {
|
|
||||||
if (recording) {
|
|
||||||
console.log("A recording is already in progress.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
console.log("🌶️🌶️🌶️🌶️🌶️🌶️🌶️🌶️🌶️🌶️");
|
|
||||||
|
|
||||||
console.log(permissionResponse);
|
|
||||||
|
|
||||||
if (
|
|
||||||
permissionResponse !== null &&
|
|
||||||
permissionResponse.status !== `granted`
|
|
||||||
) {
|
|
||||||
console.log("Requesting permission..");
|
|
||||||
await requestPermission();
|
|
||||||
}
|
|
||||||
|
|
||||||
await Audio.setAudioModeAsync({
|
|
||||||
allowsRecordingIOS: true,
|
|
||||||
playsInSilentModeIOS: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Starting recording..");
|
|
||||||
const newRecording = new Audio.Recording();
|
|
||||||
await newRecording.prepareToRecordAsync(
|
|
||||||
Audio.RecordingOptionsPresets.HIGH_QUALITY
|
|
||||||
);
|
|
||||||
await newRecording.startAsync();
|
|
||||||
|
|
||||||
setRecording(newRecording);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Failed to start recording", err);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const stopRecording = useCallback(async () => {
|
|
||||||
console.log("Stopping recording..");
|
|
||||||
|
|
||||||
if (recording) {
|
|
||||||
await recording.stopAndUnloadAsync();
|
|
||||||
await Audio.setAudioModeAsync({
|
|
||||||
allowsRecordingIOS: false,
|
|
||||||
});
|
|
||||||
const uri = recording.getURI();
|
|
||||||
// console.log("recording uri at ", uri);
|
|
||||||
setRecording(null);
|
|
||||||
|
|
||||||
if (ws && uri) {
|
|
||||||
const response = await fetch(uri);
|
|
||||||
// console.log("fetched audio file", response);
|
|
||||||
const blob = await response.blob();
|
|
||||||
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.readAsArrayBuffer(blob);
|
|
||||||
reader.onloadend = () => {
|
|
||||||
const audioBytes = reader.result;
|
|
||||||
if (audioBytes) {
|
|
||||||
ws.send(audioBytes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [recording]);
|
|
||||||
|
|
||||||
const toggleRecording = (shouldPress: boolean) => {
|
|
||||||
Animated.timing(backgroundColorAnim, {
|
|
||||||
toValue: shouldPress ? 1 : 0,
|
|
||||||
duration: 400,
|
|
||||||
useNativeDriver: false, // 'backgroundColor' does not support native driver
|
|
||||||
}).start();
|
|
||||||
Animated.timing(buttonBackgroundColorAnim, {
|
|
||||||
toValue: shouldPress ? 1 : 0,
|
|
||||||
duration: 400,
|
|
||||||
useNativeDriver: false, // 'backgroundColor' does not support native driver
|
|
||||||
}).start();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RecordButton;
|
|
@ -0,0 +1,151 @@
|
|||||||
|
import React, { useEffect, useCallback } from "react";
|
||||||
|
import { TouchableOpacity, StyleSheet } from "react-native";
|
||||||
|
import { Audio } from "expo-av";
|
||||||
|
import { Animated } from "react-native";
|
||||||
|
import * as Haptics from "expo-haptics";
|
||||||
|
|
||||||
|
interface RecordButtonProps {
|
||||||
|
playPip: () => void;
|
||||||
|
playPop: () => void;
|
||||||
|
recording: Audio.Recording | null;
|
||||||
|
setRecording: (recording: Audio.Recording | null) => void;
|
||||||
|
ws: WebSocket | null;
|
||||||
|
buttonBackgroundColorAnim: Animated.Value;
|
||||||
|
backgroundColorAnim: Animated.Value;
|
||||||
|
backgroundColor: Animated.AnimatedInterpolation<string | number>;
|
||||||
|
buttonBackgroundColor: Animated.AnimatedInterpolation<string | number>;
|
||||||
|
setIsPressed: (isPressed: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
circle: {
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
borderRadius: 50,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
borderRadius: 50,
|
||||||
|
justifyContent: "center",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const RecordButton: React.FC<RecordButtonProps> = ({
|
||||||
|
playPip,
|
||||||
|
playPop,
|
||||||
|
recording,
|
||||||
|
setRecording,
|
||||||
|
ws,
|
||||||
|
backgroundColorAnim,
|
||||||
|
buttonBackgroundColorAnim,
|
||||||
|
backgroundColor,
|
||||||
|
buttonBackgroundColor,
|
||||||
|
setIsPressed,
|
||||||
|
}: RecordButtonProps) => {
|
||||||
|
const [permissionResponse, requestPermission] = Audio.usePermissions();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (permissionResponse?.status !== "granted") {
|
||||||
|
requestPermission();
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const startRecording = useCallback(async () => {
|
||||||
|
if (recording) {
|
||||||
|
console.log("A recording is already in progress.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (
|
||||||
|
permissionResponse !== null &&
|
||||||
|
permissionResponse.status !== `granted`
|
||||||
|
) {
|
||||||
|
await requestPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Audio.setAudioModeAsync({
|
||||||
|
allowsRecordingIOS: true,
|
||||||
|
playsInSilentModeIOS: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const newRecording = new Audio.Recording();
|
||||||
|
await newRecording.prepareToRecordAsync(
|
||||||
|
Audio.RecordingOptionsPresets.HIGH_QUALITY
|
||||||
|
);
|
||||||
|
await newRecording.startAsync();
|
||||||
|
|
||||||
|
setRecording(newRecording);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Failed to start recording", err);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const stopRecording = useCallback(async () => {
|
||||||
|
if (recording) {
|
||||||
|
await recording.stopAndUnloadAsync();
|
||||||
|
await Audio.setAudioModeAsync({
|
||||||
|
allowsRecordingIOS: false,
|
||||||
|
});
|
||||||
|
const uri = recording.getURI();
|
||||||
|
setRecording(null);
|
||||||
|
|
||||||
|
if (ws && uri) {
|
||||||
|
const response = await fetch(uri);
|
||||||
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsArrayBuffer(blob);
|
||||||
|
reader.onloadend = () => {
|
||||||
|
const audioBytes = reader.result;
|
||||||
|
if (audioBytes) {
|
||||||
|
ws.send(audioBytes);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [recording]);
|
||||||
|
|
||||||
|
const toggleRecording = (shouldPress: boolean) => {
|
||||||
|
Animated.timing(backgroundColorAnim, {
|
||||||
|
toValue: shouldPress ? 1 : 0,
|
||||||
|
duration: 400,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}).start();
|
||||||
|
Animated.timing(buttonBackgroundColorAnim, {
|
||||||
|
toValue: shouldPress ? 1 : 0,
|
||||||
|
duration: 400,
|
||||||
|
useNativeDriver: false,
|
||||||
|
}).start();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.button}
|
||||||
|
onPressIn={() => {
|
||||||
|
playPip();
|
||||||
|
setIsPressed(true);
|
||||||
|
toggleRecording(true);
|
||||||
|
startRecording();
|
||||||
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
|
||||||
|
}}
|
||||||
|
onPressOut={() => {
|
||||||
|
playPop();
|
||||||
|
setIsPressed(false);
|
||||||
|
toggleRecording(false);
|
||||||
|
stopRecording();
|
||||||
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Animated.View
|
||||||
|
style={[styles.circle, { backgroundColor: buttonBackgroundColor }]}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RecordButton;
|
Loading…
Reference in new issue