From c35570a269cc4073072568c6bc847802625eb00d Mon Sep 17 00:00:00 2001 From: Xiaoyang Qiao Date: Thu, 2 Apr 2020 22:09:10 -0700 Subject: [PATCH 1/6] add MediaLibrary API to save the video --- package.json | 1 + .../RecordStack/RecordScreen/RecordScreen.tsx | 32 +++++++++++++++++-- yarn.lock | 5 +++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7d6e7467..da71aa22 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "expo-camera": "~8.0.0", "expo-constants": "~8.0.0", "expo-font": "~8.0.0", + "expo-media-library": "~8.0.0", "expo-web-browser": "~8.0.0", "express-session": "^1.17.0", "mem": "^6.0.1", diff --git a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx index 5da1a5ca..08eb7581 100644 --- a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx @@ -1,8 +1,11 @@ import React, { useState, useEffect } from 'react' -import { Text, View, TouchableOpacity, Image, StatusBar, Alert } from 'react-native' +import { Text, View, TouchableOpacity, Image, StatusBar} from 'react-native' import { Camera } from 'expo-camera' import styles from './styles' +import * as Permissions from 'expo-permissions' +import * as MediaLibrary from 'expo-media-library' import { NavigationScreenProp, NavigationState, NavigationParams } from 'react-navigation' +import CreatingVideoScreen from '../../EditStack/CreatingVideoScreen/CreatingVideoScreen' interface Props { question: string, @@ -16,6 +19,7 @@ export default function RecordScreen(props: Props) { const [camera, setCamera] = useState() const [isRecording, setIsRecording] = useState(false) const [cameraDirection, setCameraDirection] = useState(Camera.Constants.Type.front) + const [uri, setUri] = useState('') useEffect(() => { (async () => { @@ -65,12 +69,36 @@ export default function RecordScreen(props: Props) { { + const recordingConfig = { + quality : Camera.Constants.VideoQuality['720p'], + maxDuration : 120 * 60, + } + if(camera) { if (isRecording) { setIsRecording(false) camera.stopRecording() + + const status = Permissions.askAsync(Permissions.CAMERA) + if (status === 'granted') { + const asset = MediaLibrary.createAssetAsync(uri) + const assetInfo = MediaLibrary.getAssetInfoAsync(asset) + console.log(assetInfo) + } else { + console.log('Uh oh! The user has not granted us permission.') + } + + console.log('stop recording...') } else { - const video = camera.recordAsync() + camera.recordAsync(recordingConfig).then(async data => { + console.log(data.uri) + setUri(data.uri) + // let saveResult = await FileSystem.moveAsync({ + // from: data.uri, + // to: `${FileSystem.documentDirectory}videos/Video_Record`, + // }); + }) + console.log('start recording...') setIsRecording(true) } } diff --git a/yarn.lock b/yarn.lock index 817bde68..a29edb63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4238,6 +4238,11 @@ expo-location@~8.0.0: dependencies: invariant "^2.2.4" +expo-media-library@~8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/expo-media-library/-/expo-media-library-8.0.0.tgz#d763a2f39a81348d357171be5ea486679c2edb86" + integrity sha512-7TIcJjmQq+sH3deIVjwyQYa3nVsLZZUj6fQYA3R+DrFNRT6ehmd1Lai0klTa7ma3pflPEC4Uv2zOyf53alvD2w== + expo-permissions@~8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/expo-permissions/-/expo-permissions-8.0.0.tgz#5a45e8451dd7ff37c9e6ce5e2447818372547813" From 21e5d02629e53ae509a93e9c9a1923fcf10676c6 Mon Sep 17 00:00:00 2001 From: Xiaoyang Qiao Date: Thu, 2 Apr 2020 22:30:44 -0700 Subject: [PATCH 2/6] modify the get permission function --- package.json | 1 + src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index da71aa22..c2d25679 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "expo-constants": "~8.0.0", "expo-font": "~8.0.0", "expo-media-library": "~8.0.0", + "expo-permissions": "~8.0.0", "expo-web-browser": "~8.0.0", "express-session": "^1.17.0", "mem": "^6.0.1", diff --git a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx index 08eb7581..3d957cac 100644 --- a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx @@ -79,7 +79,7 @@ export default function RecordScreen(props: Props) { setIsRecording(false) camera.stopRecording() - const status = Permissions.askAsync(Permissions.CAMERA) + const status = Permissions.askAsync(Permissions.CAMERA_ROLL) if (status === 'granted') { const asset = MediaLibrary.createAssetAsync(uri) const assetInfo = MediaLibrary.getAssetInfoAsync(asset) From df1c04878e38291532761926d88c3fb62f454171 Mon Sep 17 00:00:00 2001 From: Xiaoyang Qiao Date: Thu, 2 Apr 2020 22:55:59 -0700 Subject: [PATCH 3/6] update the save video methods --- .../Main/RecordStack/RecordScreen/RecordScreen.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx index 3d957cac..3bd02b0c 100644 --- a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx @@ -78,25 +78,27 @@ export default function RecordScreen(props: Props) { if (isRecording) { setIsRecording(false) camera.stopRecording() - + // get permission to access camera_roll const status = Permissions.askAsync(Permissions.CAMERA_ROLL) if (status === 'granted') { + // Method 1 const asset = MediaLibrary.createAssetAsync(uri) const assetInfo = MediaLibrary.getAssetInfoAsync(asset) console.log(assetInfo) + + // Method 2 + // let saveResult = await FileSystem.moveAsync({ + // from: uri, + // to: `${FileSystem.documentDirectory}videos/Video_Record`, + // }); } else { console.log('Uh oh! The user has not granted us permission.') } - console.log('stop recording...') } else { camera.recordAsync(recordingConfig).then(async data => { console.log(data.uri) setUri(data.uri) - // let saveResult = await FileSystem.moveAsync({ - // from: data.uri, - // to: `${FileSystem.documentDirectory}videos/Video_Record`, - // }); }) console.log('start recording...') setIsRecording(true) From a3bf3e021a17a4c1585d51fddc583e06b50bae33 Mon Sep 17 00:00:00 2001 From: Xiaoyang Qiao Date: Sat, 4 Apr 2020 00:11:40 -0700 Subject: [PATCH 4/6] start to work --- .../RecordStack/RecordScreen/RecordScreen.tsx | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx index 3bd02b0c..c53c3f78 100644 --- a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx @@ -19,13 +19,13 @@ export default function RecordScreen(props: Props) { const [camera, setCamera] = useState() const [isRecording, setIsRecording] = useState(false) const [cameraDirection, setCameraDirection] = useState(Camera.Constants.Type.front) - const [uri, setUri] = useState('') + const [video, setVideo] = useState() useEffect(() => { (async () => { - const { status } = await Camera.requestPermissionsAsync() - setHasPermission(status === 'granted') - + const { status: cameraPermission } = await Camera.requestPermissionsAsync() + const { status: cameraRollPermission } = await Permissions.askAsync(Permissions.CAMERA_ROLL) + setHasPermission(cameraPermission === 'granted' && cameraRollPermission === 'granted') })() }, []) @@ -68,43 +68,29 @@ export default function RecordScreen(props: Props) { { + onPress={ async () => { const recordingConfig = { quality : Camera.Constants.VideoQuality['720p'], maxDuration : 120 * 60, } - + if(camera) { if (isRecording) { setIsRecording(false) camera.stopRecording() - // get permission to access camera_roll - const status = Permissions.askAsync(Permissions.CAMERA_ROLL) - if (status === 'granted') { - // Method 1 - const asset = MediaLibrary.createAssetAsync(uri) - const assetInfo = MediaLibrary.getAssetInfoAsync(asset) - console.log(assetInfo) - - // Method 2 - // let saveResult = await FileSystem.moveAsync({ - // from: uri, - // to: `${FileSystem.documentDirectory}videos/Video_Record`, - // }); - } else { - console.log('Uh oh! The user has not granted us permission.') - } + MediaLibrary.createAssetAsync(video.uri) console.log('stop recording...') } else { camera.recordAsync(recordingConfig).then(async data => { console.log(data.uri) - setUri(data.uri) + setVideo(data) }) console.log('start recording...') setIsRecording(true) } } - }} + } + } style={styles.recordOutline} > From 905d1433a06679afdfe2673650ea0fbc58aa99ca Mon Sep 17 00:00:00 2001 From: Xiaoyang Qiao Date: Sat, 4 Apr 2020 01:08:05 -0700 Subject: [PATCH 5/6] successuly save videos to local camera roll --- .../RecordStack/RecordScreen/RecordScreen.tsx | 67 ++++++++++++------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx index c53c3f78..321408c5 100644 --- a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx @@ -5,7 +5,6 @@ import styles from './styles' import * as Permissions from 'expo-permissions' import * as MediaLibrary from 'expo-media-library' import { NavigationScreenProp, NavigationState, NavigationParams } from 'react-navigation' -import CreatingVideoScreen from '../../EditStack/CreatingVideoScreen/CreatingVideoScreen' interface Props { question: string, @@ -19,7 +18,35 @@ export default function RecordScreen(props: Props) { const [camera, setCamera] = useState() const [isRecording, setIsRecording] = useState(false) const [cameraDirection, setCameraDirection] = useState(Camera.Constants.Type.front) - const [video, setVideo] = useState() + const [video, setVideo] = useState(null) + + async function saveVideo(){ + const asset = await MediaLibrary.createAssetAsync(video.uri) + if (asset) { + setVideo(null) + } + } + + async function stopRecord(){ + setIsRecording(false) + camera.stopRecording() + } + + async function startRecord(){ + if (camera) { + setIsRecording(true) + const data = await camera.recordAsync() + setVideo(data) + } + } + + async function toogleRecord(){ + if (isRecording) { + stopRecord() + } else { + startRecord() + } + } useEffect(() => { (async () => { @@ -67,30 +94,20 @@ export default function RecordScreen(props: Props) { + {video && ( + saveVideo()} + style={{ + padding: 20, + width: '100%', + backgroundColor: '#fff' + }} + > + save + + )} { - const recordingConfig = { - quality : Camera.Constants.VideoQuality['720p'], - maxDuration : 120 * 60, - } - - if(camera) { - if (isRecording) { - setIsRecording(false) - camera.stopRecording() - MediaLibrary.createAssetAsync(video.uri) - console.log('stop recording...') - } else { - camera.recordAsync(recordingConfig).then(async data => { - console.log(data.uri) - setVideo(data) - }) - console.log('start recording...') - setIsRecording(true) - } - } - } - } + onPress={()=>toogleRecord()} style={styles.recordOutline} > From ab3653888020ddc42b3708ae0c92cfef5e0b9c51 Mon Sep 17 00:00:00 2001 From: Xiaoyang Qiao Date: Sat, 4 Apr 2020 21:03:53 -0700 Subject: [PATCH 6/6] add styles to buttons when recording and saving videos --- .../RecordStack/RecordScreen/RecordScreen.tsx | 42 +++++++++---------- .../Main/RecordStack/RecordScreen/styles.tsx | 28 +++++++++++-- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx index 321408c5..85351db5 100644 --- a/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/RecordScreen.tsx @@ -72,10 +72,18 @@ export default function RecordScreen(props: Props) { > )} - goBack()} style={styles.whiteButtonOutline} > - + )} - {video && ( - saveVideo()} - style={{ - padding: 20, - width: '100%', - backgroundColor: '#fff' - }} - > - save - - )} - toogleRecord()} style={styles.recordOutline} > - + - + )} - { setCameraDirection(cameraDirection === Camera.Constants.Type.front ? Camera.Constants.Type.back : Camera.Constants.Type.front) }} > - + )} diff --git a/src/screens/Main/RecordStack/RecordScreen/styles.tsx b/src/screens/Main/RecordStack/RecordScreen/styles.tsx index faecc3d4..59142103 100644 --- a/src/screens/Main/RecordStack/RecordScreen/styles.tsx +++ b/src/screens/Main/RecordStack/RecordScreen/styles.tsx @@ -23,6 +23,13 @@ const styles = StyleSheet.create({ borderRadius: 48, alignSelf: 'center', }, + isRecordingButton: { + backgroundColor: '#FF3B30', + width: 16, + height: 16, + borderRadius: 4, + alignSelf: 'center', + }, recordOutline: { display: 'flex', justifyContent: 'center', @@ -50,7 +57,6 @@ const styles = StyleSheet.create({ borderWidth: 4, borderColor: '#fff', }, - middleSection: { display: 'flex', flexDirection: 'column', @@ -58,11 +64,9 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'flex-start', alignSelf: 'center', - }, overlay: { position: 'absolute', - }, infoText: { backgroundColor: 'rgba(51,51,51,0.4)', @@ -94,6 +98,24 @@ const styles = StyleSheet.create({ bottomSection: { flex: 1, }, + saveButton: { + backgroundColor: '#E5186E', + transform: [ { rotateZ: '270deg'}], + width: 79, + height: 48, + justifyContent: 'center', + left: '75%', + top: '15%', + borderRadius: 24, + right: -Dimensions.get('window').width + (Dimensions.get('window').width * 0.25) + }, + saveText: { + textAlign: 'center', + color: '#fff', + fontSize: 18, + lineHeight: 21, + fontFamily: 'roboto-regular' + } }) export default styles \ No newline at end of file