react-native-qrcode-scanner
Version:
A QR code scanner for React Native.
305 lines (280 loc) • 7.47 kB
JavaScript
'use strict';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
StyleSheet,
Dimensions,
Vibration,
Animated,
Easing,
View,
Text,
Platform,
PermissionsAndroid,
} from 'react-native';
import Permissions from 'react-native-permissions';
import { RNCamera as Camera } from 'react-native-camera';
const PERMISSION_AUTHORIZED = 'authorized';
const CAMERA_PERMISSION = 'camera';
export default class QRCodeScanner extends Component {
static propTypes = {
onRead: PropTypes.func.isRequired,
vibrate: PropTypes.bool,
reactivate: PropTypes.bool,
reactivateTimeout: PropTypes.number,
fadeIn: PropTypes.bool,
showMarker: PropTypes.bool,
cameraType: PropTypes.oneOf(['front', 'back']),
customMarker: PropTypes.element,
containerStyle: PropTypes.any,
cameraStyle: PropTypes.any,
markerStyle: PropTypes.any,
topViewStyle: PropTypes.any,
bottomViewStyle: PropTypes.any,
topContent: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
bottomContent: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
notAuthorizedView: PropTypes.element,
permissionDialogTitle: PropTypes.string,
permissionDialogMessage: PropTypes.string,
checkAndroid6Permissions: PropTypes.bool,
cameraProps: PropTypes.object,
};
static defaultProps = {
onRead: () => console.log('QR code scanned!'),
reactivate: false,
vibrate: true,
reactivateTimeout: 0,
fadeIn: true,
showMarker: false,
cameraType: 'back',
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',
}}
>
<Text
style={{
textAlign: 'center',
fontSize: 16,
}}
>
...
</Text>
</View>
),
permissionDialogTitle: 'Info',
permissionDialogMessage: 'Need camera permission',
checkAndroid6Permissions: false,
cameraProps: {},
};
constructor(props) {
super(props);
this.state = {
scanning: false,
fadeInOpacity: new Animated.Value(0),
isAuthorized: false,
isAuthorizationChecked: false,
disableVibrationByUser: false,
};
this._handleBarCodeRead = this._handleBarCodeRead.bind(this);
}
componentWillMount() {
if (Platform.OS === 'ios') {
Permissions.request(CAMERA_PERMISSION).then(response => {
this.setState({
isAuthorized: response === PERMISSION_AUTHORIZED,
isAuthorizationChecked: true,
});
});
} else if (
Platform.OS === 'android' &&
this.props.checkAndroid6Permissions
) {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
title: this.props.permissionDialogTitle,
message: this.props.permissionDialogMessage,
}).then(granted => {
const isAuthorized =
Platform.Version >= 23
? granted === PermissionsAndroid.RESULTS.GRANTED
: granted === true;
this.setState({ isAuthorized, isAuthorizationChecked: true });
});
} else {
this.setState({ isAuthorized: true, isAuthorizationChecked: true });
}
}
componentDidMount() {
if (this.props.fadeIn) {
Animated.sequence([
Animated.delay(1000),
Animated.timing(this.state.fadeInOpacity, {
toValue: 1,
easing: Easing.inOut(Easing.quad),
}),
]).start();
}
}
disable() {
this.setState({ disableVibrationByUser: true });
}
enable() {
this.setState({ disableVibrationByUser: false });
}
_setScanning(value) {
this.setState({ scanning: value });
}
_handleBarCodeRead(e) {
if (!this.state.scanning && !this.state.disableVibrationByUser) {
if (this.props.vibrate) {
Vibration.vibrate();
}
this._setScanning(true);
this.props.onRead(e);
if (this.props.reactivate) {
setTimeout(
() => this._setScanning(false),
this.props.reactivateTimeout
);
}
}
}
_renderTopContent() {
if (this.props.topContent) {
return this.props.topContent;
}
return null;
}
_renderBottomContent() {
if (this.props.bottomContent) {
return this.props.bottomContent;
}
return null;
}
_renderCameraMarker() {
if (this.props.showMarker) {
if (this.props.customMarker) {
return this.props.customMarker;
} else {
return (
<View style={styles.rectangleContainer}>
<View style={[styles.rectangle, this.props.markerStyle ? this.props.markerStyle : null]} />
</View>
);
}
}
return null;
}
_renderCamera() {
const {
notAuthorizedView,
pendingAuthorizationView,
cameraType,
} = this.props;
const { isAuthorized, isAuthorizationChecked } = this.state;
if (isAuthorized) {
if (this.props.fadeIn) {
return (
<Animated.View
style={{
opacity: this.state.fadeInOpacity,
backgroundColor: 'transparent',
}}
>
<Camera
style={[styles.camera, this.props.cameraStyle]}
onBarCodeRead={this._handleBarCodeRead.bind(this)}
type={this.props.cameraType}
{...this.props.cameraProps}
>
{this._renderCameraMarker()}
</Camera>
</Animated.View>
);
}
return (
<Camera
type={cameraType}
style={[styles.camera, this.props.cameraStyle]}
onBarCodeRead={this._handleBarCodeRead.bind(this)}
{...this.props.cameraProps}
>
{this._renderCameraMarker()}
</Camera>
);
} else if (!isAuthorizationChecked) {
return pendingAuthorizationView;
} else {
return notAuthorizedView;
}
}
reactivate() {
this._setScanning(false);
}
render() {
return (
<View style={[styles.mainContainer, this.props.containerStyle]}>
<View style={[styles.infoView, this.props.topViewStyle]}>
{this._renderTopContent()}
</View>
{this._renderCamera()}
<View style={[styles.infoView, this.props.bottomViewStyle]}>
{this._renderBottomContent()}
</View>
</View>
);
}
}
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
},
infoView: {
flex: 2,
justifyContent: 'center',
alignItems: 'center',
width: Dimensions.get('window').width,
},
camera: {
flex: 0,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'transparent',
height: Dimensions.get('window').width,
width: Dimensions.get('window').width,
},
rectangleContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'transparent',
},
rectangle: {
height: 250,
width: 250,
borderWidth: 2,
borderColor: '#00FF00',
backgroundColor: 'transparent',
},
});