aboutsummaryrefslogtreecommitdiff
path: root/src/screens/moments/CameraScreen.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/screens/moments/CameraScreen.tsx')
-rw-r--r--src/screens/moments/CameraScreen.tsx215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/screens/moments/CameraScreen.tsx b/src/screens/moments/CameraScreen.tsx
new file mode 100644
index 00000000..c6ed1116
--- /dev/null
+++ b/src/screens/moments/CameraScreen.tsx
@@ -0,0 +1,215 @@
+import CameraRoll from '@react-native-community/cameraroll';
+import {useBottomTabBarHeight} from '@react-navigation/bottom-tabs';
+import {RouteProp, useFocusEffect} from '@react-navigation/core';
+import {StackNavigationProp} from '@react-navigation/stack';
+import React, {createRef, useCallback, useEffect, useState} from 'react';
+import {StyleSheet, TouchableOpacity, View} from 'react-native';
+import {CameraType, FlashMode, RNCamera} from 'react-native-camera';
+import CloseIcon from '../../assets/ionicons/close-outline.svg';
+import {
+ FlashButton,
+ FlipButton,
+ GalleryIcon,
+ SaveButton,
+ TaggSquareButton,
+} from '../../components';
+import {MainStackParams} from '../../routes';
+import {HeaderHeight, normalize, SCREEN_WIDTH} from '../../utils';
+import {takePicture} from '../../utils/camera';
+
+type CameraScreenRouteProps = RouteProp<MainStackParams, 'CameraScreen'>;
+export type CameraScreenNavigationProps = StackNavigationProp<
+ MainStackParams,
+ 'CameraScreen'
+>;
+interface CameraScreenProps {
+ route: CameraScreenRouteProps;
+ navigation: CameraScreenNavigationProps;
+}
+const CameraScreen: React.FC<CameraScreenProps> = ({route, navigation}) => {
+ const {title, screenType} = route.params;
+ const cameraRef = createRef<RNCamera>();
+ const tabBarHeight = useBottomTabBarHeight();
+ const [cameraType, setCameraType] = useState<keyof CameraType>('front');
+ const [flashMode, setFlashMode] = useState<keyof FlashMode>('off');
+ const [capturedImage, setCapturedImage] = useState<string>('');
+ const [mostRecentPhoto, setMostRecentPhoto] = useState<string>('');
+ const [showSaveButton, setShowSaveButton] = useState<boolean>(false);
+
+ /*
+ * Removes bottom navigation bar on current screen and add it back when navigating away
+ */
+ useFocusEffect(
+ useCallback(() => {
+ navigation.dangerouslyGetParent()?.setOptions({
+ tabBarVisible: false,
+ });
+ return () => {
+ navigation.dangerouslyGetParent()?.setOptions({
+ tabBarVisible: true,
+ });
+ };
+ }, [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'),
+ );
+ }, [capturedImage]);
+
+ /*
+ * Appears once a picture has been captured to navigate to the caption screen
+ */
+ const handleNext = () => {
+ navigation.navigate('CaptionScreen', {
+ screenType,
+ title,
+ image: {
+ filename: capturedImage,
+ path: capturedImage,
+ },
+ });
+ };
+
+ /*
+ * If picture is not taken yet, exists from camera screen to profile view
+ * If picture is taken, exists from captured image's preview to camera
+ * */
+ const handleClose = () => {
+ if (showSaveButton) {
+ cameraRef.current?.resumePreview();
+ setShowSaveButton(false);
+ setCapturedImage('');
+ } else {
+ navigation.goBack();
+ }
+ };
+
+ return (
+ <View style={styles.container}>
+ <TouchableOpacity style={styles.closeButton} onPress={handleClose}>
+ <CloseIcon height={25} width={25} color={'white'} />
+ </TouchableOpacity>
+ <FlashButton flashMode={flashMode} setFlashMode={setFlashMode} />
+ <RNCamera
+ ref={cameraRef}
+ style={styles.camera}
+ type={cameraType}
+ flashMode={flashMode}
+ />
+ <View style={[styles.bottomContainer, {bottom: tabBarHeight}]}>
+ {showSaveButton ? (
+ <SaveButton capturedImageURI={capturedImage} />
+ ) : (
+ <FlipButton cameraType={cameraType} setCameraType={setCameraType} />
+ )}
+ <TouchableOpacity
+ onPress={() =>
+ takePicture(cameraRef, setShowSaveButton, setCapturedImage)
+ }
+ style={styles.captureButtonContainer}>
+ <View style={styles.captureButton} />
+ </TouchableOpacity>
+ <View style={styles.bottomRightContainer}>
+ {capturedImage ? (
+ <TaggSquareButton
+ onPress={handleNext}
+ title={'Next'}
+ buttonStyle={'large'}
+ buttonColor={'blue'}
+ labelColor={'white'}
+ style={styles.nextButton}
+ labelStyle={styles.nextButtonLabel}
+ />
+ ) : (
+ <GalleryIcon
+ mostRecentPhotoUri={mostRecentPhoto}
+ screenType={screenType}
+ title={title}
+ />
+ )}
+ </View>
+ </View>
+ </View>
+ );
+};
+
+const styles = StyleSheet.create({
+ camera: {
+ flex: 1,
+ justifyContent: 'space-between',
+ },
+ container: {
+ flex: 1,
+ flexDirection: 'column',
+ backgroundColor: 'black',
+ },
+ preview: {
+ flex: 1,
+ justifyContent: 'flex-end',
+ alignItems: '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,
+ },
+ nextButton: {
+ zIndex: 1,
+ width: normalize(100),
+ height: normalize(37),
+ borderRadius: 10,
+ },
+ nextButtonLabel: {
+ fontWeight: '700',
+ fontSize: normalize(15),
+ lineHeight: normalize(17.8),
+ letterSpacing: normalize(1.3),
+ textAlign: 'center',
+ },
+});
+
+export default CameraScreen;