Compare commits

...

2 Commits

Author SHA1 Message Date
simistern
55ff9809ac Fixed hooks sample to be in line with @mauriciords implementation 2020-02-12 18:58:17 -05:00
simistern
e5b2f4e7d5 converted basic sample to hooks 2019-12-24 14:25:26 -05:00
4 changed files with 604 additions and 586 deletions

View File

@ -1,5 +1,5 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import React from 'react'; import React, {useState, useReducer, useRef} from 'react';
import { import {
StyleSheet, StyleSheet,
Text, Text,
@ -30,61 +30,87 @@ const wbOrder = {
const landmarkSize = 2; const landmarkSize = 2;
export default class CameraScreen extends React.Component { const stateReducer = (state, action) => {
state = { switch (action.type) {
flash: 'off', case 'toggleFlash':
zoom: 0, return { state.flash === flashModeOrder[ state.flash] }
autoFocus: 'on', break;
autoFocusPoint: { case 'toggleZoom':
normalized: { x: 0.5, y: 0.5 }, // normalized values required for autoFocusPointOfInterest return { state.flash === flashModeOrder[ state.flash] }
drawRectPosition: { break;
x: Dimensions.get('window').width * 0.5 - 32, default:
y: Dimensions.get('window').height * 0.5 - 32, break;
}, }
}
const initialState = {
flash: 'off',
zoom: 0,
autoFocus: 'on',
depth: 0,
type: 'back',
whiteBalance: 'auto',
ratio: '16:9',
isRecording: false,
canDetectFaces: false,
canDetectText: false,
canDetectBarcode: false,
faces: [],
textBlocks: [],
barcodes: [],
recordOptions: {
mute: false,
maxDuration: 5,
quality: RNCamera.Constants.VideoQuality['288p'],
},
autoFocusPoint: {
normalized: { x: 0.5, y: 0.5 }, // normalized values required for autoFocusPointOfInterest
drawRectPosition: {
x: Dimensions.get('window').width * 0.5 - 32,
y: Dimensions.get('window').height * 0.5 - 32,
}, },
depth: 0, },
type: 'back',
whiteBalance: 'auto',
ratio: '16:9',
recordOptions: {
mute: false,
maxDuration: 5,
quality: RNCamera.Constants.VideoQuality['288p'],
},
isRecording: false,
canDetectFaces: false,
canDetectText: false,
canDetectBarcode: false,
faces: [],
textBlocks: [],
barcodes: [],
};
toggleFacing() { };
this.setState({
type: this.state.type === 'back' ? 'front' : 'back',
});
const CameraScreen = () => {
const [state, setState] = useState(initialState);
const [recordOptions, togglerecordOptions] = useReducer(reducer, initialState.recordOptions);
const [autoFocusPoint, touchToFocus] = useReducer(reducer, initialState.autoFocusPoint);
const cameraRef = useRef(null);
toggleFacing =() =>{
setState({
...state,
type: type === 'back' ? 'front' : 'back',
})
} }
toggleFlash() { toggleFlash =() => {
this.setState({ setState({
flash: flashModeOrder[this.state.flash], ...state,
}); flash: flashModeOrder[flash]
})
} }
toggleWB() { toggleWB =() => {
this.setState({ setState({
whiteBalance: wbOrder[this.state.whiteBalance], ...state,
}); whiteBalance: wbOrder[whiteBalance]
})
} }
toggleFocus() { toggleFocus =() =>{
this.setState({ setState({
autoFocus: this.state.autoFocus === 'on' ? 'off' : 'on', ...state,
}); autoFocus: autoFocus === 'on' ? 'off' : 'on'
})
} }
touchToFocus(event) { touchToFocus =(event) => {
const { pageX, pageY } = event.nativeEvent; const { pageX, pageY } = event.nativeEvent;
const screenWidth = Dimensions.get('window').width; const screenWidth = Dimensions.get('window').width;
const screenHeight = Dimensions.get('window').height; const screenHeight = Dimensions.get('window').height;
@ -97,49 +123,56 @@ export default class CameraScreen extends React.Component {
x = pageY / screenHeight; x = pageY / screenHeight;
y = -(pageX / screenWidth) + 1; y = -(pageX / screenWidth) + 1;
} }
return {
this.setState({
autoFocusPoint: { autoFocusPoint: {
normalized: { x, y }, normalized: { x, y },
drawRectPosition: { x: pageX, y: pageY }, drawRectPosition: { x: pageX, y: pageY },
}, },
};
}
zoomOut =() =>{
setState({
...state,
zoom: state.zoom - 0.1 < 0 ? 0 : state.zoom - 0.1,
})
}
zoomIn =() => {
setState({
...state,
zoom: state.zoom + 0.1 > 1 ? 1 : state.zoom + 0.1,
}); });
} }
zoomOut() { setFocusDepth = (depth) => {
this.setState({ setState({
zoom: this.state.zoom - 0.1 < 0 ? 0 : this.state.zoom - 0.1, ...state,
}); depth: depth
}
zoomIn() {
this.setState({
zoom: this.state.zoom + 0.1 > 1 ? 1 : this.state.zoom + 0.1,
});
}
setFocusDepth(depth) {
this.setState({
depth,
}); });
} }
takePicture = async function() { takePicture = async function() {
if (this.camera) { if (cameraRef) {
const data = await this.camera.takePictureAsync(); const data = await cameraRef.takePictureAsync();
console.warn('takePicture ', data); console.warn('takePicture ', data);
} }
}; };
takeVideo = async function() { takeVideo = async function() {
if (this.camera) { if (cameraRef) {
try { try {
const promise = this.camera.recordAsync(this.state.recordOptions); const promise = cameraRef.recordAsync( state.recordOptions);
if (promise) { if (promise) {
this.setState({ isRecording: true }); setState({
...state,
isRecording: true
});
const data = await promise; const data = await promise;
this.setState({ isRecording: false }); setState({
...state,
isRecording: false
});
console.warn('takeVideo', data); console.warn('takeVideo', data);
} }
} catch (e) { } catch (e) {
@ -148,9 +181,19 @@ export default class CameraScreen extends React.Component {
} }
}; };
toggle = value => () => this.setState(prevState => ({ [value]: !prevState[value] })); toggle = value => () => {
setState({
...state,
[value]: !prevState[value]
})
};
facesDetected = ({ faces }) => this.setState({ faces }); facesDetected = ({ faces }) => {
setState({
...state,
faces: faces
})
};
renderFace = ({ bounds, faceID, rollAngle, yawAngle }) => ( renderFace = ({ bounds, faceID, rollAngle, yawAngle }) => (
<View <View
@ -175,7 +218,7 @@ export default class CameraScreen extends React.Component {
</View> </View>
); );
renderLandmarksOfFace(face) { renderLandmarksOfFace =(face) => {
const renderLandmark = position => const renderLandmark = position =>
position && ( position && (
<View <View
@ -207,19 +250,19 @@ export default class CameraScreen extends React.Component {
renderFaces = () => ( renderFaces = () => (
<View style={styles.facesContainer} pointerEvents="none"> <View style={styles.facesContainer} pointerEvents="none">
{this.state.faces.map(this.renderFace)} { state.faces.map(() => renderFace())}
</View> </View>
); );
renderLandmarks = () => ( renderLandmarks = () => (
<View style={styles.facesContainer} pointerEvents="none"> <View style={styles.facesContainer} pointerEvents="none">
{this.state.faces.map(this.renderLandmarksOfFace)} { state.faces.map(() => renderLandmarksOfFace())}
</View> </View>
); );
renderTextBlocks = () => ( renderTextBlocks = () => (
<View style={styles.facesContainer} pointerEvents="none"> <View style={styles.facesContainer} pointerEvents="none">
{this.state.textBlocks.map(this.renderTextBlock)} { state.textBlocks.map(() => renderTextBlock())}
</View> </View>
); );
@ -243,14 +286,22 @@ export default class CameraScreen extends React.Component {
textRecognized = object => { textRecognized = object => {
const { textBlocks } = object; const { textBlocks } = object;
this.setState({ textBlocks }); setState({
...state,
textBlocks: textBlocks
});
}; };
barcodeRecognized = ({ barcodes }) => this.setState({ barcodes }); barcodeRecognized = ({ barcodes }) => {
setState({
...stat,
barcodes
})
};
renderBarcodes = () => ( renderBarcodes = () => (
<View style={styles.facesContainer} pointerEvents="none"> <View style={styles.facesContainer} pointerEvents="none">
{this.state.barcodes.map(this.renderBarcode)} { state.barcodes.map( renderBarcode)}
</View> </View>
); );
@ -271,30 +322,30 @@ export default class CameraScreen extends React.Component {
</React.Fragment> </React.Fragment>
); );
renderCamera() { renderCamera = () => {
const { canDetectFaces, canDetectText, canDetectBarcode } = this.state; const { canDetectFaces, canDetectText, canDetectBarcode } = state;
const drawFocusRingPosition = { const drawFocusRingPosition = {
top: this.state.autoFocusPoint.drawRectPosition.y - 32, top: state.autoFocusPoint.drawRectPosition.y - 32,
left: this.state.autoFocusPoint.drawRectPosition.x - 32, left: state.autoFocusPoint.drawRectPosition.x - 32,
}; };
return ( return (
<RNCamera <RNCamera
ref={ref => { ref={ref => {
this.camera = ref; cameraRef = ref;
}} }}
style={{ style={{
flex: 1, flex: 1,
justifyContent: 'space-between', justifyContent: 'space-between',
}} }}
type={this.state.type} type={ state.type}
flashMode={this.state.flash} flashMode={ state.flash}
autoFocus={this.state.autoFocus} autoFocus={ state.autoFocus}
autoFocusPointOfInterest={this.state.autoFocusPoint.normalized} autoFocusPointOfInterest={ state.autoFocusPoint.normalized}
zoom={this.state.zoom} zoom={ state.zoom}
whiteBalance={this.state.whiteBalance} whiteBalance={ state.whiteBalance}
ratio={this.state.ratio} ratio={ state.ratio}
focusDepth={this.state.depth} focusDepth={ state.depth}
androidCameraPermissionOptions={{ androidCameraPermissionOptions={{
title: 'Permission to use camera', title: 'Permission to use camera',
message: 'We need your permission to use your camera', message: 'We need your permission to use your camera',
@ -306,13 +357,13 @@ export default class CameraScreen extends React.Component {
? RNCamera.Constants.FaceDetection.Landmarks.all ? RNCamera.Constants.FaceDetection.Landmarks.all
: undefined : undefined
} }
onFacesDetected={canDetectFaces ? this.facesDetected : null} onFacesDetected={canDetectFaces ? facesDetected() : null}
onTextRecognized={canDetectText ? this.textRecognized : null} onTextRecognized={canDetectText ? textRecognized() : null}
onGoogleVisionBarcodesDetected={canDetectBarcode ? this.barcodeRecognized : null} onGoogleVisionBarcodesDetected={canDetectBarcode ? barcodeRecognized() : null}
> >
<View style={StyleSheet.absoluteFill}> <View style={StyleSheet.absoluteFill}>
<View style={[styles.autoFocusBox, drawFocusRingPosition]} /> <View style={[styles.autoFocusBox, drawFocusRingPosition]} />
<TouchableWithoutFeedback onPress={this.touchToFocus.bind(this)}> <TouchableWithoutFeedback onPress={() => touchToFocus()}>
<View style={{ flex: 1 }} /> <View style={{ flex: 1 }} />
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
</View> </View>
@ -332,14 +383,14 @@ export default class CameraScreen extends React.Component {
justifyContent: 'space-around', justifyContent: 'space-around',
}} }}
> >
<TouchableOpacity style={styles.flipButton} onPress={this.toggleFacing.bind(this)}> <TouchableOpacity style={styles.flipButton} onPress={() => toggleFacing()}>
<Text style={styles.flipText}> FLIP </Text> <Text style={styles.flipText}> FLIP </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.flipButton} onPress={this.toggleFlash.bind(this)}> <TouchableOpacity style={styles.flipButton} onPress={() => toggleFlash()}>
<Text style={styles.flipText}> FLASH: {this.state.flash} </Text> <Text style={styles.flipText}> FLASH: { state.flash} </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.flipButton} onPress={this.toggleWB.bind(this)}> <TouchableOpacity style={styles.flipButton} onPress={() => toggleWB()}>
<Text style={styles.flipText}> WB: {this.state.whiteBalance} </Text> <Text style={styles.flipText}> WB: { state.whiteBalance} </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<View <View
@ -349,17 +400,17 @@ export default class CameraScreen extends React.Component {
justifyContent: 'space-around', justifyContent: 'space-around',
}} }}
> >
<TouchableOpacity onPress={this.toggle('canDetectFaces')} style={styles.flipButton}> <TouchableOpacity onPress={()=> toggle('canDetectFaces')} style={styles.flipButton}>
<Text style={styles.flipText}> <Text style={styles.flipText}>
{!canDetectFaces ? 'Detect Faces' : 'Detecting Faces'} {!canDetectFaces ? 'Detect Faces' : 'Detecting Faces'}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={this.toggle('canDetectText')} style={styles.flipButton}> <TouchableOpacity onPress={()=> toggle('canDetectText')} style={styles.flipButton}>
<Text style={styles.flipText}> <Text style={styles.flipText}>
{!canDetectText ? 'Detect Text' : 'Detecting Text'} {!canDetectText ? 'Detect Text' : 'Detecting Text'}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={this.toggle('canDetectBarcode')} style={styles.flipButton}> <TouchableOpacity onPress={()=> toggle('canDetectBarcode')} style={styles.flipButton}>
<Text style={styles.flipText}> <Text style={styles.flipText}>
{!canDetectBarcode ? 'Detect Barcode' : 'Detecting Barcode'} {!canDetectBarcode ? 'Detect Barcode' : 'Detecting Barcode'}
</Text> </Text>
@ -377,9 +428,9 @@ export default class CameraScreen extends React.Component {
> >
<Slider <Slider
style={{ width: 150, marginTop: 15, alignSelf: 'flex-end' }} style={{ width: 150, marginTop: 15, alignSelf: 'flex-end' }}
onValueChange={this.setFocusDepth.bind(this)} onValueChange={() => setFocusDepth()}
step={0.1} step={0.1}
disabled={this.state.autoFocus === 'on'} disabled={ state.autoFocus === 'on'}
/> />
</View> </View>
<View <View
@ -396,20 +447,20 @@ export default class CameraScreen extends React.Component {
{ {
flex: 0.3, flex: 0.3,
alignSelf: 'flex-end', alignSelf: 'flex-end',
backgroundColor: this.state.isRecording ? 'white' : 'darkred', backgroundColor: state.isRecording ? 'white' : 'darkred',
}, },
]} ]}
onPress={this.state.isRecording ? () => {} : this.takeVideo.bind(this)} onPress={ state.isRecording ? () => {} : () => takeVideo()}
> >
{this.state.isRecording ? ( { state.isRecording ? (
<Text style={styles.flipText}> </Text> <Text style={styles.flipText}> </Text>
) : ( ) : (
<Text style={styles.flipText}> REC </Text> <Text style={styles.flipText}> REC </Text>
)} )}
</TouchableOpacity> </TouchableOpacity>
</View> </View>
{this.state.zoom !== 0 && ( { state.zoom !== 0 && (
<Text style={[styles.flipText, styles.zoomText]}>Zoom: {this.state.zoom}</Text> <Text style={[styles.flipText, styles.zoomText]}>Zoom: { state.zoom}</Text>
)} )}
<View <View
style={{ style={{
@ -421,43 +472,44 @@ export default class CameraScreen extends React.Component {
> >
<TouchableOpacity <TouchableOpacity
style={[styles.flipButton, { flex: 0.1, alignSelf: 'flex-end' }]} style={[styles.flipButton, { flex: 0.1, alignSelf: 'flex-end' }]}
onPress={this.zoomIn.bind(this)} onPress={() => zoomIn()}
> >
<Text style={styles.flipText}> + </Text> <Text style={styles.flipText}> + </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[styles.flipButton, { flex: 0.1, alignSelf: 'flex-end' }]} style={[styles.flipButton, { flex: 0.1, alignSelf: 'flex-end' }]}
onPress={this.zoomOut.bind(this)} onPress={() => zoomOut()}
> >
<Text style={styles.flipText}> - </Text> <Text style={styles.flipText}> - </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[styles.flipButton, { flex: 0.25, alignSelf: 'flex-end' }]} style={[styles.flipButton, { flex: 0.25, alignSelf: 'flex-end' }]}
onPress={this.toggleFocus.bind(this)} onPress={() => toggleFocus()}
> >
<Text style={styles.flipText}> AF : {this.state.autoFocus} </Text> <Text style={styles.flipText}> AF : { state.autoFocus} </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[styles.flipButton, styles.picButton, { flex: 0.3, alignSelf: 'flex-end' }]} style={[styles.flipButton, styles.picButton, { flex: 0.3, alignSelf: 'flex-end' }]}
onPress={this.takePicture.bind(this)} onPress={() => takePicture()}
> >
<Text style={styles.flipText}> SNAP </Text> <Text style={styles.flipText}> SNAP </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>
{!!canDetectFaces && this.renderFaces()} {!!canDetectFaces && renderFaces()}
{!!canDetectFaces && this.renderLandmarks()} {!!canDetectFaces && renderLandmarks()}
{!!canDetectText && this.renderTextBlocks()} {!!canDetectText && renderTextBlocks()}
{!!canDetectBarcode && this.renderBarcodes()} {!!canDetectBarcode && renderBarcodes()}
</RNCamera> </RNCamera>
); );
} }
return (
render() { <View style={styles.container}>{() => renderCamera()}</View>
return <View style={styles.container}>{this.renderCamera()}</View>; );
}
} }
export default CameraScreen;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,

View File

@ -1,5 +1,5 @@
// @flow // @flow
import React from 'react'; import React, { useState, useCallback, useMemo, useRef, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
findNodeHandle, findNodeHandle,
@ -342,159 +342,258 @@ const mapValues = (input, mapper) => {
return result; return result;
}; };
export default class Camera extends React.Component<PropsType, StateType> { export const Constants = {
static Constants = { Type: CameraManager.Type,
Type: CameraManager.Type, FlashMode: CameraManager.FlashMode,
FlashMode: CameraManager.FlashMode, AutoFocus: CameraManager.AutoFocus,
AutoFocus: CameraManager.AutoFocus, WhiteBalance: CameraManager.WhiteBalance,
WhiteBalance: CameraManager.WhiteBalance, VideoQuality: CameraManager.VideoQuality,
VideoQuality: CameraManager.VideoQuality, VideoCodec: CameraManager.VideoCodec,
VideoCodec: CameraManager.VideoCodec, BarCodeType: CameraManager.BarCodeType,
BarCodeType: CameraManager.BarCodeType, GoogleVisionBarcodeDetection: CameraManager.GoogleVisionBarcodeDetection,
GoogleVisionBarcodeDetection: CameraManager.GoogleVisionBarcodeDetection, FaceDetection: CameraManager.FaceDetection,
FaceDetection: CameraManager.FaceDetection, CameraStatus,
CameraStatus, RecordAudioPermissionStatus: RecordAudioPermissionStatusEnum,
RecordAudioPermissionStatus: RecordAudioPermissionStatusEnum, VideoStabilization: CameraManager.VideoStabilization,
VideoStabilization: CameraManager.VideoStabilization, Orientation: {
Orientation: { auto: 'auto',
auto: 'auto', landscapeLeft: 'landscapeLeft',
landscapeLeft: 'landscapeLeft', landscapeRight: 'landscapeRight',
landscapeRight: 'landscapeRight', portrait: 'portrait',
portrait: 'portrait', portraitUpsideDown: 'portraitUpsideDown',
portraitUpsideDown: 'portraitUpsideDown', },
};
export const ConversionTables = {
type: CameraManager.Type,
flashMode: CameraManager.FlashMode,
exposure: CameraManager.Exposure,
autoFocus: CameraManager.AutoFocus,
whiteBalance: CameraManager.WhiteBalance,
faceDetectionMode: (CameraManager.FaceDetection || {}).Mode,
faceDetectionLandmarks: (CameraManager.FaceDetection || {}).Landmarks,
faceDetectionClassifications: (CameraManager.FaceDetection || {}).Classifications,
googleVisionBarcodeType: (CameraManager.GoogleVisionBarcodeDetection || {}).BarcodeType,
videoStabilizationMode: CameraManager.VideoStabilization || {},
};
export default function Camera(props) {
let _cameraRef = useRef((ref) => setReference(ref));
let _cameraHandle: ?number;
let _lastEvents: { [string]: string };
let _lastEventsTimes: { [string]: Date };
let _isMounted: boolean;
const [isAuthorized, setIsAuthorized] = useState<boolean>(false);
const [isAuthorizationChecked, setIsAuthorizationChecked] = useState<boolean>(false);
const [recordAudioPermissionStatus, setRecordAudioPermissionStatus] = useState(
RecordAudioPermissionStatusEnum.PENDING_AUTHORIZATION,
);
const convertProp = useMemo((value: *, key: string) => {
if (typeof value === 'string' && Camera.ConversionTables[key]) {
return Camera.ConversionTables[key][value];
}
return value;
}, []);
const convertNativeProps = useCallback(
(nativeProps: PropsType) => () => {
const { children, ...props } = nativeProps;
const newProps = mapValues(props, convertProp);
if (props.onBarCodeRead) {
newProps.barCodeScannerEnabled = true;
}
if (props.onGoogleVisionBarcodesDetected) {
newProps.googleVisionBarcodeDetectorEnabled = true;
}
if (props.onFacesDetected) {
newProps.faceDetectorEnabled = true;
}
if (props.onTextRecognized) {
newProps.textRecognizerEnabled = true;
}
if (Platform.OS === 'ios') {
delete newProps.googleVisionBarcodeMode;
delete newProps.ratio;
}
return newProps;
}, },
}; [],
);
// Values under keys from this object will be transformed to native options const hasFaCC = useMemo(() => typeof props.children === 'function', [props.children]);
static ConversionTables = { const setReference = useCallback(
type: CameraManager.Type, (ref) => {
flashMode: CameraManager.FlashMode, if (ref) {
exposure: CameraManager.Exposure, _cameraHandle = findNodeHandle(ref);
autoFocus: CameraManager.AutoFocus, } else {
whiteBalance: CameraManager.WhiteBalance, _cameraRef = null;
faceDetectionMode: (CameraManager.FaceDetection || {}).Mode, _cameraHandle = null;
faceDetectionLandmarks: (CameraManager.FaceDetection || {}).Landmarks, }
faceDetectionClassifications: (CameraManager.FaceDetection || {}).Classifications,
googleVisionBarcodeType: (CameraManager.GoogleVisionBarcodeDetection || {}).BarcodeType,
videoStabilizationMode: CameraManager.VideoStabilization || {},
};
static propTypes = {
...ViewPropTypes,
zoom: PropTypes.number,
maxZoom: PropTypes.number,
ratio: PropTypes.string,
focusDepth: PropTypes.number,
onMountError: PropTypes.func,
onCameraReady: PropTypes.func,
onAudioInterrupted: PropTypes.func,
onAudioConnected: PropTypes.func,
onStatusChange: PropTypes.func,
onBarCodeRead: PropTypes.func,
onPictureTaken: PropTypes.func,
onPictureSaved: PropTypes.func,
onGoogleVisionBarcodesDetected: PropTypes.func,
onFacesDetected: PropTypes.func,
onTextRecognized: PropTypes.func,
onSubjectAreaChanged: PropTypes.func,
trackingEnabled: PropTypes.bool,
faceDetectionMode: PropTypes.number,
faceDetectionLandmarks: PropTypes.number,
faceDetectionClassifications: PropTypes.number,
barCodeTypes: PropTypes.arrayOf(PropTypes.string),
googleVisionBarcodeType: PropTypes.number,
googleVisionBarcodeMode: PropTypes.number,
type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
cameraId: PropTypes.string,
flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
exposure: PropTypes.number,
whiteBalance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
autoFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
autoFocusPointOfInterest: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
permissionDialogTitle: PropTypes.string,
permissionDialogMessage: PropTypes.string,
androidCameraPermissionOptions: Rationale,
androidRecordAudioPermissionOptions: Rationale,
notAuthorizedView: PropTypes.element,
pendingAuthorizationView: PropTypes.element,
captureAudio: PropTypes.bool,
keepAudioSession: PropTypes.bool,
useCamera2Api: PropTypes.bool,
playSoundOnCapture: PropTypes.bool,
videoStabilizationMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
pictureSize: PropTypes.string,
mirrorVideo: PropTypes.bool,
rectOfInterest: PropTypes.any,
defaultVideoQuality: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
static defaultProps: Object = {
zoom: 0,
maxZoom: 0,
ratio: '4:3',
focusDepth: 0,
type: CameraManager.Type.back,
cameraId: null,
autoFocus: CameraManager.AutoFocus.on,
flashMode: CameraManager.FlashMode.off,
exposure: -1,
whiteBalance: CameraManager.WhiteBalance.auto,
faceDetectionMode: (CameraManager.FaceDetection || {}).fast,
barCodeTypes: Object.values(CameraManager.BarCodeType),
googleVisionBarcodeType: ((CameraManager.GoogleVisionBarcodeDetection || {}).BarcodeType || {})
.None,
googleVisionBarcodeMode: ((CameraManager.GoogleVisionBarcodeDetection || {}).BarcodeMode || {})
.NORMAL,
faceDetectionLandmarks: ((CameraManager.FaceDetection || {}).Landmarks || {}).none,
faceDetectionClassifications: ((CameraManager.FaceDetection || {}).Classifications || {}).none,
permissionDialogTitle: '',
permissionDialogMessage: '',
androidCameraPermissionOptions: {
title: '',
message: '',
}, },
androidRecordAudioPermissionOptions: { [_cameraRef, _cameraHandle],
title: '', );
message: '', const _onMountError = useCallback(
({ nativeEvent }: EventCallbackArgumentsType) => {
if (props.onMountError) {
props.onMountError(nativeEvent);
}
}, },
notAuthorizedView: ( [props.onMountError],
<View style={styles.authorizationContainer}> );
<Text style={styles.notAuthorizedText}>Camera not authorized</Text> const _onCameraReady = useCallback(() => {
</View> if (props.onCameraReady) {
), props.onCameraReady();
pendingAuthorizationView: ( }
<View style={styles.authorizationContainer}> }, [props.onCameraReady]);
<ActivityIndicator size="small" /> const _onAudioInterrupted = useCallback(() => {
</View> if (props.onAudioInterrupted) {
), props.onAudioInterrupted();
captureAudio: true, }
keepAudioSession: false, }, [props.onAudioInterrupted]);
useCamera2Api: false, const _onAudioConnected = useCallback(() => {
playSoundOnCapture: false, if (props.onAudioConnected) {
pictureSize: 'None', props.onAudioConnected();
videoStabilizationMode: 0, }
mirrorVideo: false, }, [props.onAudioConnected]);
const _onObjectDetected = useCallback(
(callback: ?Function) => ({ nativeEvent }: EventCallbackArgumentsType) => {
const { type } = nativeEvent;
if (
_lastEvents[type] &&
_lastEventsTimes[type] &&
JSON.stringify(nativeEvent) === _lastEvents[type] &&
new Date() - _lastEventsTimes[type] < EventThrottleMs
) {
return;
}
if (callback) {
callback(nativeEvent);
_lastEventsTimes[type] = new Date();
_lastEvents[type] = JSON.stringify(nativeEvent);
}
},
[],
);
const _onPictureSaved = useCallback(
({ nativeEvent }: EventCallbackArgumentsType) => {
if (props.onPictureSaved) {
props.onPictureSaved(nativeEvent);
}
},
[props.onPictureSaved],
);
const _onSubjectAreaChanged = useCallback(
e => () => {
if (props.onSubjectAreaChanged) {
props.onSubjectAreaChanged(e);
}
},
[props.onSubjectAreaChanged],
);
const getStatus = useMemo(() => {
if (isAuthorizationChecked === false) {
return CameraStatus.PENDING_AUTHORIZATION;
}
return isAuthorized ? CameraStatus.READY : CameraStatus.NOT_AUTHORIZED;
}, [isAuthorizationChecked, isAuthorized]);
const renderChildren = useMemo(() => {
if (hasFaCC) {
return props.children({
camera: this,
status: getStatus,
recordAudioPermissionStatus: recordAudioPermissionStatus,
});
}
return props.children;
}, []);
const { style, ...nativeProps } = convertNativeProps(props);
const arePermissionsGranted = async () => {
const {
permissionDialogTitle,
permissionDialogMessage,
androidCameraPermissionOptions,
androidRecordAudioPermissionOptions,
} = props;
let cameraPermissions = androidCameraPermissionOptions;
let audioPermissions = androidRecordAudioPermissionOptions;
if (permissionDialogTitle || permissionDialogMessage) {
// eslint-disable-next-line no-console
console.warn(
'permissionDialogTitle and permissionDialogMessage are deprecated. Please use androidCameraPermissionOptions instead.',
);
cameraPermissions = {
...cameraPermissions,
title: permissionDialogTitle,
message: permissionDialogMessage,
};
audioPermissions = {
...audioPermissions,
title: permissionDialogTitle,
message: permissionDialogMessage,
};
}
const { hasCameraPermissions, hasRecordAudioPermissions } = await requestPermissions(
props.captureAudio,
CameraManager,
cameraPermissions,
audioPermissions,
);
const recordAudioPermissionStatus = hasRecordAudioPermissions
? RecordAudioPermissionStatusEnum.AUTHORIZED
: RecordAudioPermissionStatusEnum.NOT_AUTHORIZED;
return { hasCameraPermissions, recordAudioPermissionStatus };
}; };
_cameraRef: ?Object; const refreshAuthorizationStatus = async () => {
_cameraHandle: ?number; const { hasCameraPermissions, recordAudioPermissionStatus } = await arePermissionsGranted();
_lastEvents: { [string]: string }; if (_isMounted === false) {
_lastEventsTimes: { [string]: Date }; return;
_isMounted: boolean; }
constructor(props: PropsType) { setIsAuthorized(hasCameraPermissions);
super(props); setIsAuthorizationChecked(true);
this._lastEvents = {}; setRecordAudioPermissionStatus(recordAudioPermissionStatus);
this._lastEventsTimes = {}; };
this._isMounted = true;
this.state = {
isAuthorized: false,
isAuthorizationChecked: false,
recordAudioPermissionStatus: RecordAudioPermissionStatusEnum.PENDING_AUTHORIZATION,
};
}
async takePictureAsync(options?: PictureOptions) { const _onStatusChange = useCallback(() => {
if (props.onStatusChange) {
props.onStatusChange({
cameraStatus: getStatus(),
recordAudioPermissionStatus,
});
}
}, [props.onStatusChange]);
const stopRecording = useCallback(() => {
CameraManager.stopRecording(_cameraHandle);
}, [_cameraHandle]);
const pausePreview = useCallback(() => {
CameraManager.pausePreview(_cameraHandle);
}, [_cameraHandle]);
const isRecording = useCallback(() => {
return CameraManager.isRecording(_cameraHandle);
}, [_cameraHandle]);
const resumePreview = useCallback(() => {
CameraManager.resumePreview(_cameraHandle);
}, [_cameraHandle]);
const takePicture = async (options?: PictureOptions) => {
if (!options) { if (!options) {
options = {}; options = {};
} }
@ -519,35 +618,35 @@ export default class Camera extends React.Component<PropsType, StateType> {
options.pauseAfterCapture = false; options.pauseAfterCapture = false;
} }
if (!this._cameraHandle) { if (!_cameraHandle) {
throw 'Camera handle cannot be null'; throw 'Camera handle cannot be null';
} }
return await CameraManager.takePicture(options, this._cameraHandle); return await CameraManager.takePicture(options, _cameraHandle);
} };
async getSupportedRatiosAsync() { const getSupportedRatiosAsync = async () => {
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
return await CameraManager.getSupportedRatios(this._cameraHandle); return await CameraManager.getSupportedRatios(_cameraHandle);
} else { } else {
throw new Error('Ratio is not supported on iOS'); throw new Error('Ratio is not supported on iOS');
} }
} };
async getCameraIdsAsync() { const getCameraIdsAsync = async () => {
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
return await CameraManager.getCameraIds(this._cameraHandle); return await CameraManager.getCameraIds(_cameraHandle);
} else { } else {
return await CameraManager.getCameraIds(); // iOS does not need a camera instance return await CameraManager.getCameraIds(); // iOS does not need a camera instance
} }
}
getAvailablePictureSizes = async (): string[] => {
//$FlowFixMe
return await CameraManager.getAvailablePictureSizes(this.props.ratio, this._cameraHandle);
}; };
async recordAsync(options?: RecordingOptions) { const getAvailablePictureSizes = async (): string[] => {
//$FlowFixMe
return await CameraManager.getAvailablePictureSizes(props.ratio, _cameraHandle);
};
const recordAsync = async (options?: RecordingOptions) => {
if (!options || typeof options !== 'object') { if (!options || typeof options !== 'object') {
options = {}; options = {};
} else if (typeof options.quality === 'string') { } else if (typeof options.quality === 'string') {
@ -573,8 +672,7 @@ export default class Camera extends React.Component<PropsType, StateType> {
} }
} }
const { recordAudioPermissionStatus } = this.state; const { captureAudio } = props;
const { captureAudio } = this.props;
if ( if (
!captureAudio || !captureAudio ||
@ -593,269 +691,153 @@ export default class Camera extends React.Component<PropsType, StateType> {
} }
} }
return await CameraManager.record(options, this._cameraHandle); return await CameraManager.record(options, _cameraHandle);
}
stopRecording() {
CameraManager.stopRecording(this._cameraHandle);
}
pausePreview() {
CameraManager.pausePreview(this._cameraHandle);
}
isRecording() {
return CameraManager.isRecording(this._cameraHandle);
}
resumePreview() {
CameraManager.resumePreview(this._cameraHandle);
}
_onMountError = ({ nativeEvent }: EventCallbackArgumentsType) => {
if (this.props.onMountError) {
this.props.onMountError(nativeEvent);
}
}; };
_onCameraReady = () => { useEffect(() => {
if (this.props.onCameraReady) { async function getPermissionsAndSetState() {
this.props.onCameraReady(); const { hasCameraPermissions, recordAudioPermissionStatus } = await arePermissionsGranted();
} if (_isMounted === false) {
}; return;
}
_onAudioInterrupted = () => { setIsAuthorized(hasCameraPermissions);
if (this.props.onAudioInterrupted) { setIsAuthorizationChecked(true);
this.props.onAudioInterrupted(); setRecordAudioPermissionStatus(recordAudioPermissionStatus);
} _onStatusChange();
};
_onAudioConnected = () => {
if (this.props.onAudioConnected) {
this.props.onAudioConnected();
}
};
_onStatusChange = () => {
if (this.props.onStatusChange) {
this.props.onStatusChange({
cameraStatus: this.getStatus(),
recordAudioPermissionStatus: this.state.recordAudioPermissionStatus,
});
}
};
_onPictureSaved = ({ nativeEvent }: EventCallbackArgumentsType) => {
if (this.props.onPictureSaved) {
this.props.onPictureSaved(nativeEvent);
}
};
_onObjectDetected = (callback: ?Function) => ({ nativeEvent }: EventCallbackArgumentsType) => {
const { type } = nativeEvent;
if (
this._lastEvents[type] &&
this._lastEventsTimes[type] &&
JSON.stringify(nativeEvent) === this._lastEvents[type] &&
new Date() - this._lastEventsTimes[type] < EventThrottleMs
) {
return;
} }
if (callback) { getPermissionsAndSetState();
callback(nativeEvent);
this._lastEventsTimes[type] = new Date();
this._lastEvents[type] = JSON.stringify(nativeEvent);
}
};
_onSubjectAreaChanged = e => { return () => {
if (this.props.onSubjectAreaChanged) { _isMounted = false;
this.props.onSubjectAreaChanged(e); };
} }, []);
};
_setReference = (ref: ?Object) => { if (isAuthorized || hasFaCC) {
if (ref) { return (
this._cameraRef = ref; <View style={style}>
this._cameraHandle = findNodeHandle(ref); <RNCamera
} else { {...nativeProps}
this._cameraRef = null; style={StyleSheet.absoluteFill}
this._cameraHandle = null; ref={cameraRef}
} onMountError={_onMountError}
}; onCameraReady={_onCameraReady}
onAudioInterrupted={_onAudioInterrupted}
componentWillUnmount() { onAudioConnected={_onAudioConnected}
this._isMounted = false; onGoogleVisionBarcodesDetected={_onObjectDetected(props.onGoogleVisionBarcodesDetected)}
} onBarCodeRead={_onObjectDetected(props.onBarCodeRead)}
onFacesDetected={_onObjectDetected(props.onFacesDetected)}
async arePermissionsGranted() { onTextRecognized={_onObjectDetected(props.onTextRecognized)}
const { onPictureSaved={_onPictureSaved}
permissionDialogTitle, onSubjectAreaChanged={_onSubjectAreaChanged}
permissionDialogMessage, />
androidCameraPermissionOptions, {renderChildren}
androidRecordAudioPermissionOptions, </View>
} = this.props;
let cameraPermissions = androidCameraPermissionOptions;
let audioPermissions = androidRecordAudioPermissionOptions;
if (permissionDialogTitle || permissionDialogMessage) {
// eslint-disable-next-line no-console
console.warn(
'permissionDialogTitle and permissionDialogMessage are deprecated. Please use androidCameraPermissionOptions instead.',
);
cameraPermissions = {
...cameraPermissions,
title: permissionDialogTitle,
message: permissionDialogMessage,
};
audioPermissions = {
...audioPermissions,
title: permissionDialogTitle,
message: permissionDialogMessage,
};
}
const { hasCameraPermissions, hasRecordAudioPermissions } = await requestPermissions(
this.props.captureAudio,
CameraManager,
cameraPermissions,
audioPermissions,
); );
} else if (!isAuthorizationChecked) {
const recordAudioPermissionStatus = hasRecordAudioPermissions return props.pendingAuthorizationView;
? RecordAudioPermissionStatusEnum.AUTHORIZED } else {
: RecordAudioPermissionStatusEnum.NOT_AUTHORIZED; return props.notAuthorizedView;
return { hasCameraPermissions, recordAudioPermissionStatus };
}
async refreshAuthorizationStatus() {
const {
hasCameraPermissions,
recordAudioPermissionStatus,
} = await this.arePermissionsGranted();
if (this._isMounted === false) {
return;
}
this.setState({
isAuthorized: hasCameraPermissions,
isAuthorizationChecked: true,
recordAudioPermissionStatus,
});
}
async componentDidMount() {
const {
hasCameraPermissions,
recordAudioPermissionStatus,
} = await this.arePermissionsGranted();
if (this._isMounted === false) {
return;
}
this.setState(
{
isAuthorized: hasCameraPermissions,
isAuthorizationChecked: true,
recordAudioPermissionStatus,
},
this._onStatusChange,
);
}
getStatus = (): Status => {
const { isAuthorized, isAuthorizationChecked } = this.state;
if (isAuthorizationChecked === false) {
return CameraStatus.PENDING_AUTHORIZATION;
}
return isAuthorized ? CameraStatus.READY : CameraStatus.NOT_AUTHORIZED;
};
// FaCC = Function as Child Component;
hasFaCC = (): * => typeof this.props.children === 'function';
renderChildren = (): * => {
if (this.hasFaCC()) {
return this.props.children({
camera: this,
status: this.getStatus(),
recordAudioPermissionStatus: this.state.recordAudioPermissionStatus,
});
}
return this.props.children;
};
render() {
const { style, ...nativeProps } = this._convertNativeProps(this.props);
if (this.state.isAuthorized || this.hasFaCC()) {
return (
<View style={style}>
<RNCamera
{...nativeProps}
style={StyleSheet.absoluteFill}
ref={this._setReference}
onMountError={this._onMountError}
onCameraReady={this._onCameraReady}
onAudioInterrupted={this._onAudioInterrupted}
onAudioConnected={this._onAudioConnected}
onGoogleVisionBarcodesDetected={this._onObjectDetected(
this.props.onGoogleVisionBarcodesDetected,
)}
onBarCodeRead={this._onObjectDetected(this.props.onBarCodeRead)}
onFacesDetected={this._onObjectDetected(this.props.onFacesDetected)}
onTextRecognized={this._onObjectDetected(this.props.onTextRecognized)}
onPictureSaved={this._onPictureSaved}
onSubjectAreaChanged={this._onSubjectAreaChanged}
/>
{this.renderChildren()}
</View>
);
} else if (!this.state.isAuthorizationChecked) {
return this.props.pendingAuthorizationView;
} else {
return this.props.notAuthorizedView;
}
}
_convertNativeProps({ children, ...props }: PropsType) {
const newProps = mapValues(props, this._convertProp);
if (props.onBarCodeRead) {
newProps.barCodeScannerEnabled = true;
}
if (props.onGoogleVisionBarcodesDetected) {
newProps.googleVisionBarcodeDetectorEnabled = true;
}
if (props.onFacesDetected) {
newProps.faceDetectorEnabled = true;
}
if (props.onTextRecognized) {
newProps.textRecognizerEnabled = true;
}
if (Platform.OS === 'ios') {
delete newProps.googleVisionBarcodeMode;
delete newProps.ratio;
}
return newProps;
}
_convertProp(value: *, key: string): * {
if (typeof value === 'string' && Camera.ConversionTables[key]) {
return Camera.ConversionTables[key][value];
}
return value;
} }
} }
export const Constants = Camera.Constants; Camera.propTypes = {
...ViewPropTypes,
zoom: PropTypes.number,
maxZoom: PropTypes.number,
ratio: PropTypes.string,
focusDepth: PropTypes.number,
onMountError: PropTypes.func,
onCameraReady: PropTypes.func,
onAudioInterrupted: PropTypes.func,
onAudioConnected: PropTypes.func,
onStatusChange: PropTypes.func,
onBarCodeRead: PropTypes.func,
onPictureTaken: PropTypes.func,
onPictureSaved: PropTypes.func,
onGoogleVisionBarcodesDetected: PropTypes.func,
onFacesDetected: PropTypes.func,
onTextRecognized: PropTypes.func,
onSubjectAreaChanged: PropTypes.func,
trackingEnabled: PropTypes.bool,
faceDetectionMode: PropTypes.number,
faceDetectionLandmarks: PropTypes.number,
faceDetectionClassifications: PropTypes.number,
barCodeTypes: PropTypes.arrayOf(PropTypes.string),
googleVisionBarcodeType: PropTypes.number,
googleVisionBarcodeMode: PropTypes.number,
type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
cameraId: PropTypes.string,
flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
exposure: PropTypes.number,
whiteBalance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
autoFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
autoFocusPointOfInterest: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }),
permissionDialogTitle: PropTypes.string,
permissionDialogMessage: PropTypes.string,
androidCameraPermissionOptions: Rationale,
androidRecordAudioPermissionOptions: Rationale,
notAuthorizedView: PropTypes.element,
pendingAuthorizationView: PropTypes.element,
captureAudio: PropTypes.bool,
keepAudioSession: PropTypes.bool,
useCamera2Api: PropTypes.bool,
playSoundOnCapture: PropTypes.bool,
videoStabilizationMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
pictureSize: PropTypes.string,
mirrorVideo: PropTypes.bool,
rectOfInterest: PropTypes.any,
defaultVideoQuality: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
Camera.defaultProps = {
zoom: 0,
maxZoom: 0,
ratio: '4:3',
focusDepth: 0,
type: CameraManager.Type.back,
cameraId: null,
autoFocus: CameraManager.AutoFocus.on,
flashMode: CameraManager.FlashMode.off,
exposure: -1,
whiteBalance: CameraManager.WhiteBalance.auto,
faceDetectionMode: (CameraManager.FaceDetection || {}).fast,
barCodeTypes: Object.values(CameraManager.BarCodeType),
googleVisionBarcodeType: ((CameraManager.GoogleVisionBarcodeDetection || {}).BarcodeType || {})
.None,
googleVisionBarcodeMode: ((CameraManager.GoogleVisionBarcodeDetection || {}).BarcodeMode || {})
.NORMAL,
faceDetectionLandmarks: ((CameraManager.FaceDetection || {}).Landmarks || {}).none,
faceDetectionClassifications: ((CameraManager.FaceDetection || {}).Classifications || {}).none,
permissionDialogTitle: '',
permissionDialogMessage: '',
androidCameraPermissionOptions: {
title: '',
message: '',
},
androidRecordAudioPermissionOptions: {
title: '',
message: '',
},
notAuthorizedView: (
<View style={styles.authorizationContainer}>
<Text style={styles.notAuthorizedText}>Camera not authorized</Text>
</View>
),
pendingAuthorizationView: (
<View style={styles.authorizationContainer}>
<ActivityIndicator size="small" />
</View>
),
captureAudio: true,
keepAudioSession: false,
useCamera2Api: false,
playSoundOnCapture: false,
pictureSize: 'None',
videoStabilizationMode: 0,
mirrorVideo: false,
};
const RNCamera = requireNativeComponent('RNCamera', Camera, { const RNCamera = requireNativeComponent('RNCamera', Camera, {
nativeOnly: { nativeOnly: {

View File

@ -1,6 +1,10 @@
// @flow // @flow
import RNCamera, { type Status as _CameraStatus } from './RNCamera'; import RNCamera, {
type Status as _CameraStatus,
Constants as RNCConstants,
ConversionTables,
} from './RNCamera';
import FaceDetector from './FaceDetector'; import FaceDetector from './FaceDetector';
export type CameraStatus = _CameraStatus; export type CameraStatus = _CameraStatus;
export { RNCamera, FaceDetector }; export { RNCamera, FaceDetector, RNCConstants, ConversionTables };

70
types/index.d.ts vendored
View File

@ -94,13 +94,11 @@ type RecordAudioPermissionStatus = Readonly<
NOT_AUTHORIZED: 'NOT_AUTHORIZED'; NOT_AUTHORIZED: 'NOT_AUTHORIZED';
}> }>
>; >;
type FaCC = ( type FaCC = (params: {
params: {
camera: RNCamera; camera: RNCamera;
status: keyof CameraStatus; status: keyof CameraStatus;
recordAudioPermissionStatus: keyof RecordAudioPermissionStatus; recordAudioPermissionStatus: keyof RecordAudioPermissionStatus;
}, }) => JSX.Element;
) => JSX.Element;
export interface Constants { export interface Constants {
CameraStatus: CameraStatus; CameraStatus: CameraStatus;
@ -135,7 +133,7 @@ export interface RNCameraProps {
autoFocus?: keyof AutoFocus; autoFocus?: keyof AutoFocus;
autoFocusPointOfInterest?: Point; autoFocusPointOfInterest?: Point;
/* iOS only */ /* iOS only */
onSubjectAreaChanged?: (event: { nativeEvent: { prevPoint: { x: number; y: number; } } }) => void; onSubjectAreaChanged?: (event: { nativeEvent: { prevPoint: { x: number; y: number } } }) => void;
type?: keyof CameraType; type?: keyof CameraType;
flashMode?: keyof FlashMode; flashMode?: keyof FlashMode;
notAuthorizedView?: JSX.Element; notAuthorizedView?: JSX.Element;
@ -178,12 +176,12 @@ export interface RNCameraProps {
* @description For Android use `{ width: number, height: number, origin: Array<Point<string>> }` * @description For Android use `{ width: number, height: number, origin: Array<Point<string>> }`
* @description For iOS use `{ origin: Point<string>, size: Size<string> }` * @description For iOS use `{ origin: Point<string>, size: Size<string> }`
*/ */
bounds: { width: number, height: number, origin: Array<Point<string>> } | { origin: Point<string>; size: Size<string> }; bounds:
| { width: number; height: number; origin: Array<Point<string>> }
| { origin: Point<string>; size: Size<string> };
}): void; }): void;
onGoogleVisionBarcodesDetected?(event: { onGoogleVisionBarcodesDetected?(event: { barcodes: Barcode[] }): void;
barcodes: Barcode[];
}): void;
// -- FACE DETECTION PROPS // -- FACE DETECTION PROPS
@ -257,9 +255,9 @@ export interface Barcode {
firstName?: string; firstName?: string;
lastName?: string; lastName?: string;
middleName?: string; middleName?: string;
prefix?:string; prefix?: string;
pronounciation?:string; pronounciation?: string;
suffix?:string; suffix?: string;
formattedName?: string; formattedName?: string;
}; };
phone?: Phone; phone?: Phone;
@ -298,29 +296,29 @@ export interface Barcode {
} }
export type BarcodeType = export type BarcodeType =
|"EMAIL" |'EMAIL'
|"PHONE" |'PHONE'
|"CALENDAR_EVENT" |'CALENDAR_EVENT'
|"DRIVER_LICENSE" |'DRIVER_LICENSE'
|"GEO" |'GEO'
|"SMS" |'SMS'
|"CONTACT_INFO" |'CONTACT_INFO'
|"WIFI" |'WIFI'
|"TEXT" |'TEXT'
|"ISBN" |'ISBN'
|"PRODUCT" |'PRODUCT'
|"URL" |'URL'
export interface Email { export interface Email {
address?: string; address?: string;
body?: string; body?: string;
subject?: string; subject?: string;
emailType?: "UNKNOWN" | "Work" | "Home"; emailType?: 'UNKNOWN' | 'Work' | 'Home';
} }
export interface Phone { export interface Phone {
number?: string; number?: string;
phoneType?: "UNKNOWN" | "Work" | "Home" | "Fax" | "Mobile"; phoneType?: 'UNKNOWN' | 'Work' | 'Home' | 'Fax' | 'Mobile';
} }
export interface Face { export interface Face {
@ -409,26 +407,8 @@ export interface RecordResponse {
codec: VideoCodec[keyof VideoCodec]; codec: VideoCodec[keyof VideoCodec];
} }
export class RNCamera extends Component<RNCameraProps & ViewProperties> { export function RNCamera(props: RNCameraProps & ViewProperties): Component;
static Constants: Constants;
_cameraRef: null | NativeMethodsMixinStatic;
_cameraHandle: ReturnType<typeof findNodeHandle>;
takePictureAsync(options?: TakePictureOptions): Promise<TakePictureResponse>;
recordAsync(options?: RecordOptions): Promise<RecordResponse>;
refreshAuthorizationStatus(): Promise<void>;
stopRecording(): void;
pausePreview(): void;
resumePreview(): void;
getAvailablePictureSizes(): Promise<string[]>;
/** Android only */
getSupportedRatiosAsync(): Promise<string[]>;
/** iOS only */
isRecording(): Promise<boolean>;
}
interface DetectionOptions { interface DetectionOptions {
mode?: keyof FaceDetectionMode; mode?: keyof FaceDetectionMode;