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