diff --git a/native/media/camera-modal.react.js b/native/media/camera-modal.react.js --- a/native/media/camera-modal.react.js +++ b/native/media/camera-modal.react.js @@ -221,6 +221,16 @@ ]); } +async function cleanUpPendingPhotoCapture(pendingPhotoCapture: PhotoCapture) { + const path = pathFromURI(pendingPhotoCapture.uri); + if (!path) { + return; + } + try { + await filesystem.unlink(path); + } catch (e) {} +} + type RNCameraStatus = 'READY' | 'PENDING_AUTHORIZATION' | 'NOT_AUTHORIZED'; type TouchableOpacityInstance = React.AbstractComponent< @@ -271,6 +281,10 @@ +pendingPhotoCapture: ?PhotoCapture, +setPendingPhotoCapture: (?PhotoCapture) => void, +camera: { current: ?RNCamera }, + +takePhoto: () => Promise, + +close: () => void, + +sendPhoto: () => Promise, + +clearPendingImage: () => void, }; class CameraModal extends React.PureComponent { @@ -545,23 +559,11 @@ !this.props.pendingPhotoCapture && prevProps.pendingPhotoCapture ) { - void CameraModal.cleanUpPendingPhotoCapture( - prevProps.pendingPhotoCapture, - ); + void cleanUpPendingPhotoCapture(prevProps.pendingPhotoCapture); this.sendButtonProgress.setValue(0); } } - static async cleanUpPendingPhotoCapture(pendingPhotoCapture: PhotoCapture) { - const path = pathFromURI(pendingPhotoCapture.uri); - if (!path) { - return; - } - try { - await filesystem.unlink(path); - } catch (e) {} - } - get containerStyle(): AnimatedViewStyle { const { overlayContext } = this.props; if (!overlayContext) { @@ -605,7 +607,7 @@ {this.renderCameraContent(status)} { - const { overlayContext, navigation } = this.props; - if (overlayContext && navigation.goBackOnce) { - navigation.goBackOnce(); - } else { - navigation.goBack(); - } - }; - - takePhoto = async () => { - const camera = this.props.camera.current; - invariant(camera, 'camera ref should be set'); - this.props.setStagingMode(true); - - // We avoid flipping this.props.useFrontCamera if we discover we don't - // actually have a back camera since it causes a bit of lag, but this - // means there are cases where it is false but we are actually using the - // front camera - const { hasCamerasOnBothSides, defaultUseFrontCamera } = - this.props.deviceCameraInfo; - const usingFrontCamera = - this.props.useFrontCamera || - (!hasCamerasOnBothSides && defaultUseFrontCamera); - - const startTime = Date.now(); - const photoPromise = camera.takePictureAsync({ - pauseAfterCapture: Platform.OS === 'android', - mirrorImage: usingFrontCamera, - fixOrientation: true, - }); - - if (Platform.OS === 'ios') { - camera.pausePreview(); - } - const { uri, width, height } = await photoPromise; - const filename = filenameFromPathOrURI(uri); - invariant( - filename, - `unable to parse filename out of react-native-camera URI ${uri}`, - ); - - const now = Date.now(); - const pendingPhotoCapture = { - step: 'photo_capture', - uri, - dimensions: { width, height }, - filename, - time: now - startTime, - captureTime: now, - selectTime: 0, - sendTime: 0, - retries: 0, - }; - - this.props.setAutoFocusPointOfInterest(undefined); - this.props.setZoom(0); - this.props.setPendingPhotoCapture(pendingPhotoCapture); - }; - - sendPhoto = async () => { - const { pendingPhotoCapture } = this.props; - if (!pendingPhotoCapture) { - return; - } - - const now = Date.now(); - const capture = { - ...pendingPhotoCapture, - selectTime: now, - sendTime: now, - }; - - this.close(); - - this.props.handlePhotoCapture(capture); - }; - - clearPendingImage = () => { - invariant(this.props.camera.current, 'camera ref should be set'); - this.props.camera.current.resumePreview(); - this.props.setStagingMode(false); - this.props.setPendingPhotoCapture(); - }; } const styles = StyleSheet.create({ @@ -1081,6 +999,8 @@ const overlayContext = React.useContext(OverlayContext); const dispatch = useDispatch(); + const { navigation, handlePhotoCapture } = props; + const isActive = !overlayContext || !overlayContext.isDismissing; React.useEffect(() => { @@ -1217,6 +1137,89 @@ const cameraRef = React.useRef(); + const takePhoto = React.useCallback(async () => { + const camera = cameraRef.current; + invariant(camera, 'camera ref should be set'); + setStagingMode(true); + + // We avoid flipping useFrontCamera if we discover we don't + // actually have a back camera since it causes a bit of lag, but this + // means there are cases where it is false but we are actually using the + // front camera + const { + hasCamerasOnBothSides: hasCamerasOnBothSidesFromDeviceInfo, + defaultUseFrontCamera, + } = deviceCameraInfo; + const usingFrontCamera = + useFrontCamera || + (!hasCamerasOnBothSidesFromDeviceInfo && defaultUseFrontCamera); + + const startTime = Date.now(); + const photoPromise = camera.takePictureAsync({ + pauseAfterCapture: Platform.OS === 'android', + mirrorImage: usingFrontCamera, + fixOrientation: true, + }); + + if (Platform.OS === 'ios') { + camera.pausePreview(); + } + const { uri, width, height } = await photoPromise; + const filename = filenameFromPathOrURI(uri); + invariant( + filename, + `unable to parse filename out of react-native-camera URI ${uri}`, + ); + + const now = Date.now(); + const nextPendingPhotoCapture = { + step: 'photo_capture', + uri, + dimensions: { width, height }, + filename, + time: now - startTime, + captureTime: now, + selectTime: 0, + sendTime: 0, + retries: 0, + }; + + setAutoFocusPointOfInterest(undefined); + setZoom(0); + setPendingPhotoCapture(nextPendingPhotoCapture); + }, [deviceCameraInfo, useFrontCamera]); + + const close = React.useCallback(() => { + if (overlayContext && navigation.goBackOnce) { + navigation.goBackOnce(); + } else { + navigation.goBack(); + } + }, [navigation, overlayContext]); + + const sendPhoto = React.useCallback(async () => { + if (!pendingPhotoCapture) { + return; + } + + const now = Date.now(); + const capture = { + ...pendingPhotoCapture, + selectTime: now, + sendTime: now, + }; + + close(); + handlePhotoCapture(capture); + }, [close, handlePhotoCapture, pendingPhotoCapture]); + + const clearPendingImage = React.useCallback(() => { + invariant(cameraRef.current, 'camera ref should be set'); + cameraRef.current.resumePreview(); + setStagingMode(false); + setPendingPhotoCapture(); + }, []); + return ( ); });