Skip to content

Instantly share code, notes, and snippets.

@fobos531
Created August 19, 2021 16:18
Show Gist options
  • Save fobos531/d69c7a859d2546765a0b65d41a3d528c to your computer and use it in GitHub Desktop.
Save fobos531/d69c7a859d2546765a0b65d41a3d528c to your computer and use it in GitHub Desktop.
import React, { useRef, useState, useEffect } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Pressable } from 'react-native';
import { RNCamera } from 'react-native-camera';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { StackNavigationProp } from '@react-navigation/stack';
import { useIsFocused } from '@react-navigation/native';
import LinearGradient from 'react-native-linear-gradient';
import { useReactiveVar } from '@apollo/client';
import ModalContainer from '@components/create-story/CreateModal';
import { SuccessModal } from '@components/create-story';
import { Icon } from '@components/common';
import { ShutterIcon, SwithCameraIcon, ShutterSuccessIcon } from '@assets/icons/create-story/';
import { CloseStoryIcon } from '@assets/icons/story-view';
import { StopRecordingIcon } from '@assets/icons/index';
import { StoryStackParamList } from '@navigation/stacks/StoryStack';
import screen from '@navigation/screens';
import colors from '@constants/colors';
import { useStory, storyVar } from '@graphql/local/story';
import dayjs from 'dayjs';
type CreateNavigationProp = StackNavigationProp<StoryStackParamList, screen.CREATE>;
export interface CreateProps {
navigation: CreateNavigationProp;
}
const Create: React.FunctionComponent<CreateProps> = ({ navigation }) => {
const [activeCamera, setActiveCamera] = useState<'front' | 'back'>('back');
const [isRecording, setIsRecording] = useState<boolean>(false);
const [longPressed, setLongPressed] = useState<boolean>(false);
const [duration, setDuration] = useState<number>(0);
const insets = useSafeAreaInsets();
const camera = useRef<RNCamera>(null);
const isFocused = useIsFocused();
const { addSlides, setCaptured } = useStory(storyVar);
const story = useReactiveVar(storyVar);
let timer: any;
const startRecording = () => {
// Mark that we started recording
setIsRecording(true);
// Actually start recording
// handleRecordVideo();
const startTimer = () => {
timer = setInterval(() => {
// console.log('IN INTERVAL - time', dayjs().diff(timeStartedRecording, 'second').toString());
setDuration((old) => old + 1);
}, 1000);
};
console.log('TIMER REFERENCE', timer);
startTimer();
};
useEffect(() => {
console.log('DURATION', dayjs().startOf('day').second(duration).format('mm:ss'));
console.log('IS RECORDING', isRecording);
if (isRecording) {
} else {
}
}, [duration, isRecording]);
const handleSwitchCamera = () => {
if (activeCamera === 'back') {
setActiveCamera('front');
} else {
setActiveCamera('back');
}
};
const handleTakePicture = async () => {
// Take picture and store it in the state
const data = await camera.current?.takePictureAsync({ pauseAfterCapture: true });
if (!data) {
console.log('An error occured');
return;
}
addSlides([
{
mediaType: 'image',
mediaUri: data.uri,
},
]);
setCaptured(true);
};
const handleRecordVideo = async () => {
if (camera.current) {
try {
const promise = camera.current?.recordAsync({
quality: RNCamera.Constants.VideoQuality['1080p'],
});
if (promise) {
const data = await promise;
console.log('VIDEO DATA', data);
// Example: VIDEO DATA {"deviceOrientation": 1,
//"isRecordingInterrupted": true,
//"uri": "file:///data/user/0/com.uxdotapp.restory/cache/Camera/baba8b91-fb52-4a1e-b4e9-afffc333dc51.mp4",
//"videoOrientation": 1}
// addSlides([
// {
// mediaType: 'image',
// mediaUri: data.uri,
// },
// ]);
}
} catch (err) {
console.log('ERROR OCCURED', err);
}
}
};
return (
<View style={[styles.flex, styles.blackBackground]}>
{story.captured && <SuccessModal />}
{/* {isFocused && <ModalContainer />} */}
{isFocused && <RNCamera ref={camera} type={activeCamera} style={styles.flex} />}
<View style={styles.overlayContainer}>
<View style={[styles.topOverlay, { marginTop: insets.top }]}>
<TouchableOpacity onPress={handleSwitchCamera}>
<SwithCameraIcon />
</TouchableOpacity>
<View style={styles.recordingContainer}>
<View style={styles.recordingDot} />
<Text style={styles.text}>{dayjs().startOf('day').second(duration).format('mm:ss')}</Text>
</View>
<TouchableOpacity onPress={navigation.goBack}>
<Icon icon={CloseStoryIcon} width={36} height={36} strokeWidth={2} />
</TouchableOpacity>
</View>
<LinearGradient
colors={colors.darkGradient}
start={{ x: 0.5, y: 1 }}
end={{ x: 0.5, y: 0 }}
style={[styles.bottomOverlay, { paddingBottom: insets.bottom + 20 }]}>
<Pressable onPress={() => console.log('taken photo')}>
<Icon icon={story.captured ? ShutterSuccessIcon : ShutterIcon} color="none" width={70} height={70} />
</Pressable>
<Pressable
onPress={() => {
if (longPressed) {
// Start recording
console.log('LONG PRESSED');
startRecording();
setLongPressed(false);
} else if (isRecording) {
setIsRecording(false);
clearInterval(timer);
} else {
// Take regular picture
handleTakePicture();
}
}}
onPressIn={() => {
// Since onPress is always fired after onPressOut (which is always fired)
// we need a different way to differentiate between a long press and a regular press
// onPressIn will be fired only after a press of 500ms, so that's where we mark the
// longPressed variable as true
setLongPressed(true);
}}
onPressOut={() => {
// setIsRecording(false);
}}
unstable_pressDelay={500}>
<Icon icon={isRecording ? StopRecordingIcon : ShutterIcon} color="none" width={70} height={70} />
</Pressable>
<TouchableOpacity style={styles.galleryContainer} onPress={() => navigation.push(screen.GALLERY)}>
<Text style={styles.text}>GALLERY</Text>
</TouchableOpacity>
</LinearGradient>
</View>
</View>
);
};
const styles = StyleSheet.create({
flex: {
flex: 1,
},
blackBackground: {
backgroundColor: colors.black,
},
overlayContainer: {
position: 'absolute',
height: '100%',
width: '100%',
justifyContent: 'space-between',
},
topOverlay: {
width: '100%',
paddingTop: 25,
paddingHorizontal: 30,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
bottomOverlay: {
alignItems: 'center',
},
galleryContainer: {
position: 'absolute',
left: 20,
bottom: 30,
},
text: {
color: colors.white,
letterSpacing: 1,
},
recordingContainer: {
flexDirection: 'row',
alignItems: 'center',
},
recordingDot: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: 'red',
marginRight: 5,
},
});
export default Create;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment