Skip to content

Instantly share code, notes, and snippets.

@alithom123
Last active October 6, 2020 19:08
Show Gist options
  • Save alithom123/49aa5aef520f69092234ed67286b2049 to your computer and use it in GitHub Desktop.
Save alithom123/49aa5aef520f69092234ed67286b2049 to your computer and use it in GitHub Desktop.
import React, { useState, useEffect, useContext, useRef } from "react"
import {
Text,
View,
TouchableOpacity,
Button,
StyleSheet,
Modal,
SafeAreaView,
Dimensions,
} from "react-native"
import { DevContext } from "../../context/context"
import { KCDefaultButton } from "../../components"
import { Camera } from "expo-camera"
import { Video } from "expo-av"
import theme from "../../constants/theme"
import { apiUploadContribution } from "../../api"
import { AuthContext } from "../../context/context"
import {
EvilIcons,
SimpleLineIcons,
Octicons,
MaterialIcons,
MaterialCommunityIcons,
Feather,
} from "@expo/vector-icons"
import { ThemeConsumer } from "react-native-elements"
export default AddVideoSimple = ({ navigation, route }) => {
const card = route.params.card
const { seeBgMode, getRandomColor } = useContext(DevContext)
const { user } = useContext(AuthContext)
const [hasPermission, setHasPermission] = useState(null)
const [type, setType] = useState(Camera.Constants.Type.back)
const [videoSource, setVideoSource] = useState(null)
const [isRecording, setIsRecording] = useState(false)
const [instructions, setInstructions] = useState(
`You'll have up to 60s to record your message.\n\n${card.instructions}`
)
const [modalVisible, setModalVisible] = useState(false)
const [sixtySecondTimer, setSixtySecondTimer] = useState(60)
//! You need a card variable in here.
// const [sixtySecondTimer, setSixtySecondTimer] = useState(60) // TODO:
// const [threeSecondTimer, setThreeSecondTimer] = useState(3) // TODO:
const cameraRef = useRef()
// let sixtyTimer = null
// TODO: MENTOR. Need help on these timers. I don't understand why they're not working.
/* const startSixtySecondTimer = () => {
console.log("startSixtySecondTimer")
sixtyTimer = setInterval(() => {
console.log(`another 1s in 60`)
setSixtySecondTimer(sixtySecondTimer - 1)
}, 1000)
} */
/* const stopSixtySecondTimer = () => {
console.log(`canceling 60s timer`)
clearInterval(sixtyTimer)
} */
/* useEffect(() => {
console.log("in useEffect")
if (sixtySecondTimer) {
console.log(`resetting instructions`)
setInstructions(`You have ${sixtySecondTimer}s left.`)
}
}, [sixtySecondTimer]) */
const takePicture = async () => {
if (cameraRef.current) {
const options = { quality: 0.5, base64: true, skipProcessing: true }
const data = await cameraRef.current.takePictureAsync(options)
const source = data.uri
if (source) {
await cameraRef.current.pausePreview()
// setIsPreview(true)
console.log("picture source", source)
}
}
}
function countdown() {
console.log(timeRemaining)
console.log("timer in countdown = ", timer)
timeRemaining--
setSixtySecondTimer(timeRemaining)
if (timeRemaining == 0) {
// clearInterval(timer) //? This needs to happen in stopRecordingVideo() ... how do I pass it there?
stopVideoRecording() // within this scope timer IS defined. But when you call stopVideoRecording from outside this function timer is undefined.
setSixtySecondTimer(60)
}
}
// console.log(`setting timer to null? Doesn't this happen on every render?`)
let timer
console.log(`timer = `, timer)
let timeRemaining
const recordVideo = async () => {
timeRemaining = 10
timer = setInterval(countdown, 1000)
console.log(`in recordVideo timer = `, timer)
console.log(`recordVideo`)
if (cameraRef.current) {
try {
const videoRecordPromise = cameraRef.current.recordAsync()
if (videoRecordPromise) {
// startSixtySecondTimer()
setIsRecording(true)
// setIsVideoRecording(true)
// setInstructions(`timeRemaining`)
const data = await videoRecordPromise
const source = data.uri
if (source) {
// setIsPreview(true)
console.log("video source", source)
setModalVisible(true)
setVideoSource(source)
}
}
} catch (error) {
console.warn(error)
setModalVisible(true) //! Temporary
setVideoSource({}) //! Temporary
}
}
}
const stopVideoRecording = () => {
console.log("stopVideoRecording")
if (cameraRef.current) {
console.log("running")
// setIsPreview(false)
// setIsVideoRecording(false)
setIsRecording(false)
clearInterval(timer) //? This didn't work.
console.log(`trying to clear timer = `, timer)
cameraRef.current.stopRecording()
// stopSixtySecondTimer()
}
}
const handleAcceptVideo = () => {
const asyncWrap = async () => {
try {
console.log("in here")
const response = await apiUploadContribution(
"wrongnamedfield.mov",
videoSource,
card.id,
user.id,
"video",
"This is my video contribution!",
"Hello from Ali",
0 //! order, I want to get rid of this
)
console.log(`response from video upload`, response)
let updatedCard
if (response.data.doc) {
updatedCard = response.data.doc
}
console.log(`updatedCard`, updatedCard)
// navigation.navigate("ActiveStackShare", { card: updatedCard, videoUri: videoSource })
navigation.navigate("ActiveStackPreview", { card: updatedCard })
} catch (error) {
console.log("Error on handleAcceptVideo", error)
}
}
asyncWrap()
}
const handleRejectVideo = () => {
setModalVisible(false)
}
useEffect(() => {
;(async () => {
const { status } = await Camera.requestPermissionsAsync()
setHasPermission(status === "granted")
})()
}, [])
if (hasPermission === null) {
return <View />
}
if (hasPermission === false) {
return <Text>No access to camera</Text>
}
return (
<View style={styles.screen}>
<Modal
animationType="slide"
transparent={false}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.")
}}
>
<SafeAreaView style={styles.modal}>
<Video
source={{ uri: videoSource }}
shouldPlay={true}
useNativeControls={true}
// onReadyForDisplay={{ naturalSize: { orientation: "landscape", width: 100, height: 100 } }}
style={styles.videoPlaybackScreen}
/>
<View style={styles.acceptVideoControls}>
<KCDefaultButton
title="Accept"
style={styles.acceptButton}
onPress={handleAcceptVideo}
/>
<KCDefaultButton
title="Cancel"
style={styles.rejectButton}
// onPress={() => setModalVisible(false)}
onPress={handleRejectVideo}
/>
</View>
</SafeAreaView>
</Modal>
<Camera ref={cameraRef} style={{ flex: 1, backgroundColor: "purple" }} type={type}>
<View
style={{
flex: 1,
padding: 20,
// margin: 10,
// backgroundColor: "blue",
// opacity: 0.2,
flexDirection: "column",
}}
>
<View style={styles.recordDotContainer}>
{isRecording ? <View style={styles.recordDot} /> : null}
</View>
{!isRecording ? (
<TouchableOpacity
style={{
// flex: 0.1,
// backgroundColor: "red",
opacity: 0.5,
// alignSelf: "flex-end",
alignItems: "center",
}}
onPress={() => {
navigation.navigate("ActiveStackShare", { card })
}}
>
<Text style={{ fontSize: 18, marginVertical: 10, color: "white" }}> Skip </Text>
</TouchableOpacity>
) : null}
</View>
<View style={styles.instructionsBar}>
<Text style={styles.instructionsBarText}>{instructions}</Text>
</View>
<View style={styles.videoControlBar}>
<TouchableOpacity
onPress={() => {
console.log(`hitting flip button button`)
type == Camera.Constants.Type.back
? setType(Camera.Constants.Type.front)
: setType(Camera.Constants.Type.back)
}}
>
<Feather name={"rotate-ccw"} size={24} />
</TouchableOpacity>
<TouchableOpacity
// onPress={takePicture} // TODO: Click to record, not hold
// onLongPress={recordVideo}
// onPressOut={stopVideoRecording}
onPress={isRecording ? stopVideoRecording : recordVideo}
>
<View style={styles.recordButtonOuterCircle}>
<View style={styles.recordButtonInnerCircle}></View>
</View>
</TouchableOpacity>
{/* <Button title="Record"></Button> */}
<TouchableOpacity
onPress={() => {
navigation.goBack()
}}
>
{/* <Feather name={"x"} size={24} /> */}
<Text style={{ width: 30 }}>{`${sixtySecondTimer}s`}</Text>
</TouchableOpacity>
</View>
</Camera>
</View>
)
}
const styles = StyleSheet.create({
screen: { flex: 1 },
videoControlBar: {
flexDirection: "row",
justifyContent: "space-around",
alignItems: "center",
backgroundColor: theme.COLORS.PURPLE,
height: "15%",
},
instructionsBar: {
alignItems: "center",
// margin: 20,
padding: 25,
// borderStyle: "solid",
// borderColor: "red",
// borderWidth: 1,
backgroundColor: "black",
opacity: 0.5,
// backgroundColor: "transparent",
},
instructionsBarText: {
color: "white",
textAlign: "center",
},
recordButtonOuterCircle: {
width: 64,
height: 64,
borderWidth: 4,
borderColor: "white",
// backgroundColor: "purple",
borderRadius: 32,
justifyContent: "center",
alignItems: "center",
},
recordButtonInnerCircle: {
width: 52,
height: 52,
backgroundColor: theme.COLORS.RED,
borderRadius: 26,
},
modal: {
// height: "100%",
flex: 1,
backgroundColor: theme.COLORS.GREY,
// height: 400,
},
videoPlaybackScreen: {
flex: 1,
backgroundColor: "blue",
// width: Dimensions.get("window").width,
// height: Dimensions.get("window").height,
// height: 600,
// height: "100%",
// width: "100%",
},
acceptVideoControls: {
flexDirection: "row",
justifyContent: "space-around",
// flex: 1,
// height: "15%",
},
acceptButton: {
flex: 1,
backgroundColor: theme.COLORS.GREEN,
},
rejectButton: {
flex: 1,
backgroundColor: theme.COLORS.RED,
},
recordDot: {
borderRadius: 3,
height: 6,
width: 6,
backgroundColor: "#ff0000",
marginHorizontal: 5,
alignSelf: "flex-end",
},
recordDotContainer: {
// backgroundColor: "green",
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment