merge with master

This commit is contained in:
Sibelius Seraphini 2018-01-07 09:06:20 -08:00
commit 30af527ac3
5 changed files with 136 additions and 86 deletions

View File

@ -1,11 +1,5 @@
import React from 'react'; import React from 'react';
import { import { Image, StatusBar, StyleSheet, TouchableOpacity, View } from 'react-native';
Image,
StatusBar,
StyleSheet,
TouchableOpacity,
View,
} from 'react-native';
import Camera from 'react-native-camera'; import Camera from 'react-native-camera';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -68,37 +62,39 @@ export default class Example extends React.Component {
orientation: Camera.constants.Orientation.auto, orientation: Camera.constants.Orientation.auto,
flashMode: Camera.constants.FlashMode.auto, flashMode: Camera.constants.FlashMode.auto,
}, },
isRecording: false isRecording: false,
}; };
} }
takePicture = () => { takePicture = () => {
if (this.camera) { if (this.camera) {
this.camera.capture() this.camera
.then((data) => console.log(data)) .capture()
.then(data => console.log(data))
.catch(err => console.error(err)); .catch(err => console.error(err));
} }
} };
startRecording = () => { startRecording = () => {
if (this.camera) { if (this.camera) {
this.camera.capture({mode: Camera.constants.CaptureMode.video}) this.camera
.then((data) => console.log(data)) .capture({ mode: Camera.constants.CaptureMode.video })
.catch(err => console.error(err)); .then(data => console.log(data))
.catch(err => console.error(err));
this.setState({ this.setState({
isRecording: true isRecording: true,
}); });
} }
} };
stopRecording = () => { stopRecording = () => {
if (this.camera) { if (this.camera) {
this.camera.stopCapture(); this.camera.stopCapture();
this.setState({ this.setState({
isRecording: false isRecording: false,
}); });
} }
} };
switchType = () => { switchType = () => {
let newType; let newType;
@ -116,7 +112,7 @@ export default class Example extends React.Component {
type: newType, type: newType,
}, },
}); });
} };
get typeIcon() { get typeIcon() {
let icon; let icon;
@ -149,7 +145,7 @@ export default class Example extends React.Component {
flashMode: newFlashMode, flashMode: newFlashMode,
}, },
}); });
} };
get flashIcon() { get flashIcon() {
let icon; let icon;
@ -169,12 +165,9 @@ export default class Example extends React.Component {
render() { render() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StatusBar <StatusBar animated hidden />
animated
hidden
/>
<Camera <Camera
ref={(cam) => { ref={cam => {
this.camera = cam; this.camera = cam;
}} }}
style={styles.preview} style={styles.preview}
@ -186,62 +179,34 @@ export default class Example extends React.Component {
onZoomChanged={() => {}} onZoomChanged={() => {}}
defaultTouchToFocus defaultTouchToFocus
mirrorImage={false} mirrorImage={false}
permissionDialogTitle="Sample title"
permissionDialogMessage="Sample dialog message"
/> />
<View style={[styles.overlay, styles.topOverlay]}> <View style={[styles.overlay, styles.topOverlay]}>
<TouchableOpacity <TouchableOpacity style={styles.typeButton} onPress={this.switchType}>
style={styles.typeButton} <Image source={this.typeIcon} />
onPress={this.switchType}
>
<Image
source={this.typeIcon}
/>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity style={styles.flashButton} onPress={this.switchFlash}>
style={styles.flashButton} <Image source={this.flashIcon} />
onPress={this.switchFlash}
>
<Image
source={this.flashIcon}
/>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<View style={[styles.overlay, styles.bottomOverlay]}> <View style={[styles.overlay, styles.bottomOverlay]}>
{ {(!this.state.isRecording && (
!this.state.isRecording <TouchableOpacity style={styles.captureButton} onPress={this.takePicture}>
&& <Image source={require('./assets/ic_photo_camera_36pt.png')} />
<TouchableOpacity
style={styles.captureButton}
onPress={this.takePicture}
>
<Image
source={require('./assets/ic_photo_camera_36pt.png')}
/>
</TouchableOpacity> </TouchableOpacity>
|| )) ||
null null}
}
<View style={styles.buttonsSpace} /> <View style={styles.buttonsSpace} />
{ {(!this.state.isRecording && (
!this.state.isRecording <TouchableOpacity style={styles.captureButton} onPress={this.startRecording}>
&& <Image source={require('./assets/ic_videocam_36pt.png')} />
<TouchableOpacity </TouchableOpacity>
style={styles.captureButton} )) || (
onPress={this.startRecording} <TouchableOpacity style={styles.captureButton} onPress={this.stopRecording}>
> <Image source={require('./assets/ic_stop_36pt.png')} />
<Image </TouchableOpacity>
source={require('./assets/ic_videocam_36pt.png')} )}
/>
</TouchableOpacity>
||
<TouchableOpacity
style={styles.captureButton}
onPress={this.stopRecording}
>
<Image
source={require('./assets/ic_stop_36pt.png')}
/>
</TouchableOpacity>
}
</View> </View>
</View> </View>
); );

View File

@ -5,6 +5,11 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.RECORD_VIDEO"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-sdk <uses-sdk
android:minSdkVersion="16" android:minSdkVersion="16"

View File

@ -34,7 +34,7 @@ To enable `video recording` feature you have to add the following code to the `A
### Requirements ### Requirements
1. JDK >= 1.7 (if you run on 1.6 you will get an error on "_cameras = new HashMap<>();") 1. JDK >= 1.7 (if you run on 1.6 you will get an error on "_cameras = new HashMap<>();")
2. With iOS 10 and higher you need to add the "Privacy - Camera Usage Description" key to the info.plist of your project. This should be found in 'your_project/ios/your_project/Info.plist'. Add the following code: 2. With iOS 10 and higher you need to add the "Privacy - Camera Usage Description" key to the Info.plist of your project. This should be found in 'your_project/ios/your_project/Info.plist'. Add the following code:
``` ```
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Your message to user when the camera is accessed for the first time</string> <string>Your message to user when the camera is accessed for the first time</string>
@ -56,8 +56,6 @@ To enable `video recording` feature you have to add the following code to the `A
<string>Your message to user when the photo library is accessed for the first time</string> <string>Your message to user when the photo library is accessed for the first time</string>
``` ```
NSPhotoLibraryAddUsageDescription
### Mostly automatic install with react-native ### Mostly automatic install with react-native
1. `npm install react-native-camera --save` 1. `npm install react-native-camera --save`
3. `react-native link react-native-camera` 3. `react-native link react-native-camera`
@ -324,6 +322,26 @@ from javascript.
If set to `true`, the device will not sleep while the camera preview is visible. This mimics the behavior of the default camera app, which keeps the device awake while open. If set to `true`, the device will not sleep while the camera preview is visible. This mimics the behavior of the default camera app, which keeps the device awake while open.
#### `Android` `permissionDialogTitle`
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the title of the dialog prompt requesting permissions.
#### `Android` `permissionDialogMessage`
Starting on android M individual permissions must be granted for certain services, the camera is one of them, you can use this to change the content of the dialog prompt requesting permissions.
#### `notAuthorizedView`
By default a `Camera not authorized` message will be displayed when access to the camera has been denied, if set displays the passed react element instead of the default one.
#### `pendingAuthorizationView`
By default a <ActivityIndicator> will be displayed while the component is waiting for the user to grant/deny access to the camera, if set displays the passed react element instead of the default one.
#### `pendingAuthorizationView`
#### `mirrorImage` #### `mirrorImage`
If set to `true`, the image returned will be mirrored. If set to `true`, the image returned will be mirrored.

View File

@ -1,4 +1,3 @@
// @flow
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
@ -9,6 +8,10 @@ import {
StyleSheet, StyleSheet,
requireNativeComponent, requireNativeComponent,
ViewPropTypes, ViewPropTypes,
PermissionsAndroid,
ActivityIndicator,
View,
Text,
} from 'react-native'; } from 'react-native';
const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule; const CameraManager = NativeModules.CameraManager || NativeModules.CameraModule;
@ -92,6 +95,10 @@ export default class Camera extends Component {
playSoundOnCapture: PropTypes.bool, playSoundOnCapture: PropTypes.bool,
torchMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), torchMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), type: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
permissionDialogTitle: PropTypes.string,
permissionDialogMessage: PropTypes.string,
notAuthorizedView: PropTypes.element,
pendingAuthorizationView: PropTypes.element,
}; };
static defaultProps = { static defaultProps = {
@ -109,6 +116,37 @@ export default class Camera extends Component {
torchMode: CameraManager.TorchMode.off, torchMode: CameraManager.TorchMode.off,
mirrorImage: false, mirrorImage: false,
barCodeTypes: Object.values(CameraManager.BarCodeType), barCodeTypes: Object.values(CameraManager.BarCodeType),
permissionDialogTitle: '',
permissionDialogMessage: '',
notAuthorizedView: (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text
style={{
textAlign: 'center',
fontSize: 16,
}}
>
Camera not authorized
</Text>
</View>
),
pendingAuthorizationView: (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}
>
<ActivityIndicator size="small" />
</View>
),
}; };
static checkDeviceAuthorizationStatus = CameraManager.checkDeviceAuthorizationStatus; static checkDeviceAuthorizationStatus = CameraManager.checkDeviceAuthorizationStatus;
@ -124,6 +162,7 @@ export default class Camera extends Component {
super(); super();
this.state = { this.state = {
isAuthorized: false, isAuthorized: false,
isAuthorizationChecked: false,
isRecording: false, isRecording: false,
}; };
} }
@ -134,13 +173,28 @@ export default class Camera extends Component {
let { captureMode } = convertNativeProps({ captureMode: this.props.captureMode }); let { captureMode } = convertNativeProps({ captureMode: this.props.captureMode });
let hasVideoAndAudio = let hasVideoAndAudio =
this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video; this.props.captureAudio && captureMode === Camera.constants.CaptureMode.video;
let check = hasVideoAndAudio
? Camera.checkDeviceAuthorizationStatus
: Camera.checkVideoAuthorizationStatus;
if (check) { if (Platform.OS === 'ios') {
const isAuthorized = await check(); let check = hasVideoAndAudio
this.setState({ isAuthorized }); ? Camera.checkDeviceAuthorizationStatus
: Camera.checkVideoAuthorizationStatus;
if (check) {
const isAuthorized = await check();
this.setState({ isAuthorized, isAuthorizationChecked: true });
}
} else if (Platform.OS === 'android') {
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
title: this.props.permissionDialogTitle,
message: this.props.permissionDialogMessage,
});
this.setState({
isAuthorized: granted === PermissionsAndroid.RESULTS.GRANTED,
isAuthorizationChecked: true,
});
} else {
this.setState({ isAuthorized: true, isAuthorizationChecked: true });
} }
} }
@ -182,7 +236,13 @@ export default class Camera extends Component {
const style = [styles.base, this.props.style]; const style = [styles.base, this.props.style];
const nativeProps = convertNativeProps(this.props); const nativeProps = convertNativeProps(this.props);
return <RCTCamera ref={CAMERA_REF} {...nativeProps} />; if (this.state.isAuthorized) {
return <RCTCamera ref={CAMERA_REF} {...nativeProps} />;
} else if (!this.state.isAuthorizationChecked) {
return this.props.pendingAuthorizationView;
} else {
return this.props.notAuthorizedView;
}
} }
_onBarCodeRead = data => { _onBarCodeRead = data => {

View File

@ -1,5 +1,7 @@
import Camera from './Camera'; import Camera from './Camera';
export RNCamera from './RNCamera'; import RNCamera from './RNCamera';
export FaceDetector from './FaceDetector'; import FaceDetector from './FaceDetector';
export { RNCamera, FaceDetector };
export default Camera; export default Camera;