Skip to content

Instantly share code, notes, and snippets.

@amandeepmittal
Created June 25, 2021 18:23
Show Gist options
  • Save amandeepmittal/8401a1b07429db386628f7c639d2cd8b to your computer and use it in GitHub Desktop.
Save amandeepmittal/8401a1b07429db386628f7c639d2cd8b to your computer and use it in GitHub Desktop.
import React, { useState, useRef, useEffect } from 'react';
import {
StyleSheet,
Dimensions,
View,
Text,
TouchableOpacity
} from 'react-native';
import { Camera } from 'expo-camera';
import { Video } from "expo-av";
import { AntDesign, MaterialIcons } from '@expo/vector-icons';
const WINDOW_HEIGHT = Dimensions.get('window').height;
const CAPTURE_SIZE = Math.floor(WINDOW_HEIGHT * 0.08);
export function SnapComponent() {
const cameraRef = useRef();
const [hasPermission, setHasPermission] = useState(null);
const [cameraType, setCameraType] = useState(Camera.Constants.Type.back);
const [isPreview, setIsPreview] = useState(false);
const [isCameraReady, setIsCameraReady] = useState(false);
const [isVideoRecording, setIsVideoRecording] = useState(false);
const [videoSource, setVideoSource] = useState(null);
useEffect(() => {
onHandlePermission();
}, []);
const onHandlePermission = async () => {
const { status } = await Camera.requestPermissionsAsync();
setHasPermission(status === 'granted');
};
const onCameraReady = () => {
setIsCameraReady(true);
};
const switchCamera = () => {
if (isPreview) {
return;
}
setCameraType(prevCameraType =>
prevCameraType === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back
);
};
const onSnap = async () => {
if (cameraRef.current) {
const options = { quality: 0.7, base64: true };
const data = await cameraRef.current.takePictureAsync(options);
const source = data.base64;
if (source) {
await cameraRef.current.pausePreview();
setIsPreview(true);
}
}
};
const recordVideo = async () => {
if (cameraRef.current) {
try {
const videoRecordPromise = cameraRef.current.recordAsync();
if (videoRecordPromise) {
setIsVideoRecording(true);
const data = await videoRecordPromise;
const source = data.uri;
if (source) {
setIsPreview(true);
console.log("video source", source);
setVideoSource(source);
}
}
} catch (error) {
console.warn(error);
}
}
};
const stopVideoRecording = () => {
if (cameraRef.current) {
setIsPreview(false);
setIsVideoRecording(false);
cameraRef.current.stopRecording();
}
};
const cancelPreview = async () => {
await cameraRef.current.resumePreview();
setIsPreview(false);
setVideoSource(null);
};
const renderVideoPlayer = () => (
<Video
source={{ uri: videoSource }}
shouldPlay={true}
style={styles.media}
/>
);
const renderVideoRecordIndicator = () => (
<View style={styles.recordIndicatorContainer}>
<View style={styles.recordDot} />
<Text style={styles.recordTitle}>{"Recording..."}</Text>
</View>
);
if (hasPermission === null) {
return <View />;
}
if (hasPermission === false) {
return <Text style={styles.text}>No access to camera</Text>;
}
return (
<View style={styles.container}>
<Camera
ref={cameraRef}
style={styles.container}
type={cameraType}
onCameraReady={onCameraReady}
/>
{isVideoRecording && renderVideoRecordIndicator()}
{videoSource && renderVideoPlayer()}
<View style={styles.container}>
{isPreview && (
<TouchableOpacity onPress={cancelPreview} style={styles.closeButton}>
<AntDesign name='close' size={32} color='#fff' />
</TouchableOpacity>
)}
{!videoSource && !isPreview && (
<View style={styles.bottomButtonsContainer}>
<TouchableOpacity disabled={!isCameraReady} onPress={switchCamera}>
<MaterialIcons name='flip-camera-ios' size={28} color='white' />
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.7}
disabled={!isCameraReady}
onPress={onSnap}
style={styles.capture}
onLongPress={recordVideo}
onPressOut={stopVideoRecording}
/>
</View>
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject
},
text: {
color: '#fff'
},
bottomButtonsContainer: {
position: 'absolute',
flexDirection: 'row',
bottom: 28,
width: '100%',
alignItems: 'center',
justifyContent: 'center'
},
closeButton: {
position: 'absolute',
top: 35,
right: 20,
height: 50,
width: 50,
borderRadius: 25,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#5A45FF',
opacity: 0.7
},
capture: {
backgroundColor: '#5A45FF',
borderRadius: 5,
height: CAPTURE_SIZE,
width: CAPTURE_SIZE,
borderRadius: Math.floor(CAPTURE_SIZE / 2),
marginBottom: 28,
marginHorizontal: 30,
borderWidth: 2,
borderColor: '#fff'
},
recordIndicatorContainer: {
flexDirection: "row",
position: "absolute",
top: 25,
alignSelf: "center",
justifyContent: "center",
alignItems: "center",
backgroundColor: "transparent",
opacity: 0.7,
},
recordTitle: {
fontSize: 14,
color: "#ffffff",
textAlign: "center",
},
recordDot: {
borderRadius: 3,
height: 6,
width: 6,
backgroundColor: "#ff0000",
marginHorizontal: 5,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment