import CameraRoll from '@react-native-community/cameraroll'; import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs'; import {RouteProp} from '@react-navigation/core'; import {useFocusEffect} from '@react-navigation/native'; import {StackNavigationProp} from '@react-navigation/stack'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Modal, StyleSheet, TouchableOpacity, View} from 'react-native'; import {CameraType, FlashMode, RNCamera} from 'react-native-camera'; import {AnimatedCircularProgress} from 'react-native-circular-progress'; import CloseIcon from '../../assets/ionicons/close-outline.svg'; import {FlashButton, FlipButton, GalleryIcon} from '../../components'; import {MAX_VIDEO_RECORDING_DURATION, TAGG_PURPLE} from '../../constants'; import {MainStackParams} from '../../routes'; import {HeaderHeight, SCREEN_HEIGHT, SCREEN_WIDTH} from '../../utils'; import {showGIFFailureAlert, takePicture, takeVideo} from '../../utils/camera'; type CameraScreenRouteProps = RouteProp; export type CameraScreenNavigationProps = StackNavigationProp< MainStackParams, 'CameraScreen' >; interface CameraScreenProps { route: CameraScreenRouteProps; navigation: CameraScreenNavigationProps; } const CameraScreen: React.FC = ({route, navigation}) => { const {screenType, selectedCategory} = route.params; const cameraRef = useRef(null); const tabBarHeight = useBottomTabBarHeight(); const [cameraType, setCameraType] = useState('back'); const [flashMode, setFlashMode] = useState('off'); const [mostRecentPhoto, setMostRecentPhoto] = useState(''); const [recordingStarted, setRecordingStarted] = useState(false); const [showCaptureButtons, setShowCaptureButtons] = useState(false); const [showCamera, setShowCamera] = useState(true); const stopVideoRecording = async () => { if (await cameraRef.current?.isRecording()) { cameraRef.current?.stopRecording(); } }; useFocusEffect( useCallback(() => { navigation.dangerouslyGetParent()?.setOptions({ tabBarVisible: false, }); setRecordingStarted(false); setShowCaptureButtons(true); setShowCamera(true); return () => { setTimeout(() => { setShowCamera(false); }, 500); }; }, [navigation]), ); /* * Chooses the last picture from gallery to display as the gallery button icon */ useEffect(() => { CameraRoll.getPhotos({first: 1}) .then((lastPhoto) => { if (lastPhoto.edges.length > 0) { const image = lastPhoto.edges[0].node.image; setMostRecentPhoto(image.uri); } }) .catch((_err) => console.log('Unable to fetch preview photo for gallery'), ); }, []); const navigateToEditMedia = (uri: string) => { navigation.navigate('EditMedia', { screenType, media: { uri, isVideo: !( uri.endsWith('jpg') || uri.endsWith('JPG') || uri.endsWith('PNG') || uri.endsWith('png') || uri.endsWith('GIF') || uri.endsWith('gif') ), }, selectedCategory, }); }; const handleClose = () => { navigation.dangerouslyGetParent()?.setOptions({ tabBarVisible: true, }); navigation.goBack(); }; return ( {showCamera && ( { if (showCaptureButtons) { setCameraType(cameraType === 'front' ? 'back' : 'front'); } }} onRecordingStart={() => setRecordingStarted(true)} /> )} {showCaptureButtons && ( { await stopVideoRecording(); takeVideo(cameraRef, (vid) => navigateToEditMedia(vid.uri)); }} onPressOut={async () => { setShowCaptureButtons(false); if ( recordingStarted && (await cameraRef.current?.isRecording()) ) { cameraRef.current?.stopRecording(); } else { takePicture(cameraRef, (pic) => navigateToEditMedia(pic.uri)); } setRecordingStarted(false); }} onPress={async () => { if (showCaptureButtons) { setShowCaptureButtons(false); } takePicture(cameraRef, (pic) => navigateToEditMedia(pic.uri)); await stopVideoRecording(); }}> {recordingStarted && ( )} { const filename = media.filename; if ( filename && (filename.endsWith('gif') || filename.endsWith('GIF')) ) { showGIFFailureAlert(() => navigateToEditMedia(media.path)); } else { navigateToEditMedia(media.path); } }} /> )} ); }; const styles = StyleSheet.create({ camera: { flex: 1, justifyContent: 'space-between', }, container: { flex: 1, flexDirection: 'column', backgroundColor: 'black', }, flashView: { width: SCREEN_WIDTH, height: SCREEN_HEIGHT, backgroundColor: '#fff', opacity: 0.5, }, captureButtonVideoContainer: { alignSelf: 'center', backgroundColor: 'transparent', borderRadius: 100, borderWidth: 15, borderColor: 'rgba(255,255,255,0.3)', width: 93, height: 93, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, captureButtonContainer: { alignSelf: 'center', backgroundColor: 'transparent', borderRadius: 100, borderWidth: 4, borderColor: '#fff', width: 93, height: 93, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, captureButton: { backgroundColor: '#fff', width: 68, height: 68, borderRadius: 74, }, closeButton: { position: 'absolute', top: 0, paddingTop: HeaderHeight, zIndex: 1, marginLeft: '5%', }, bottomContainer: { position: 'absolute', width: SCREEN_WIDTH, flexDirection: 'row', justifyContent: 'center', }, bottomRightContainer: { flexDirection: 'column', justifyContent: 'center', alignItems: 'center', width: (SCREEN_WIDTH - 100) / 2, }, }); export default CameraScreen;