railbird-gql/component/video/capture-button.tsx
2024-01-30 17:05:43 -08:00

112 lines
3.0 KiB
TypeScript

import React, { useCallback, useRef, useState } from 'react';
import { TouchableOpacity, StyleSheet, View, StyleProp, ViewStyle } from 'react-native';
import { CameraRoll } from "@react-native-camera-roll/camera-roll";
import { Camera } from 'react-native-vision-camera/lib/typescript/Camera';
import { VideoFile } from 'react-native-vision-camera/lib/typescript/VideoFile';
interface RecordingButtonProps {
style: StyleProp<ViewStyle>;
camera: React.RefObject<Camera>;
// eslint-disable-next-line no-unused-vars
onMediaCaptured: (media: VideoFile, mediaType: string) => void;
enabled: boolean;
}
export const RecordingButton: React.FC<RecordingButtonProps> = ({ style, camera, onMediaCaptured, enabled }) => {
const isRecording = useRef(false)
// UseRef won't trigger a re-render
const [, setRecordingState] = useState(false);
const onStoppedRecording = useCallback(() => {
isRecording.current = false
setRecordingState(false)
console.log('stopped recording video!')
}, [])
const stopRecording = useCallback(async () => {
try {
if (camera.current === null) {
throw new Error('Camera ref is null!') // Error handling could be more graceful
}
console.log('calling stopRecording()...')
await camera.current.stopRecording()
console.log('called stopRecording()!')
} catch (e) {
console.error('failed to stop recording!', e)
}
}, [camera])
const startRecording = useCallback(() => {
try {
if (camera.current === null) {
throw new Error('Camera ref is null!') // Error handling could be more graceful
}
console.log('calling startRecording()...')
camera.current.startRecording({
onRecordingError: (error) => {
console.error('Recording failed!', error)
onStoppedRecording()
},
onRecordingFinished: async (video) => {
onMediaCaptured(video, 'video')
const path = video.path
await CameraRoll.saveAsset(`file://${path}`, {
type: 'video',
})
onStoppedRecording()
},
})
console.log('called startRecording()!')
isRecording.current = true
setRecordingState(true)
} catch (e) {
console.error('failed to start recording!', e, 'camera')
}
}, [camera, onMediaCaptured, onStoppedRecording])
const handlePress = () => {
if (isRecording.current) {
stopRecording();
} else {
startRecording();
}
};
return (
<TouchableOpacity
style={[styles.captureButton, style]}
onPress={handlePress}
disabled={!enabled}
>
<View style={isRecording.current ? styles.recordingSquare : styles.innerCircle} />
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
captureButton: {
height: 80,
width: 80,
borderRadius: 40,
borderWidth: 3,
borderColor: 'white',
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
},
innerCircle: {
height: 70,
width: 70,
borderRadius: 35,
backgroundColor: '#FF3B30',
},
recordingSquare: {
height: 40,
width: 40,
borderRadius: 10,
backgroundColor: '#FF3B30',
},
});
export default RecordingButton;