import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { StyleSheet, Text, View, TouchableOpacity, Image, Dimensions, Platform, SafeAreaView, } from 'react-native'; import _ from 'lodash'; import Camera from './Camera'; const FLASH_MODE_AUTO = 'auto'; const FLASH_MODE_ON = 'on'; const FLASH_MODE_OFF = 'off'; const { width, height } = Dimensions.get('window'); export enum CameraType { Front = 'front', Back = 'back' } export type Props = { ratioOverlay?: string, ratioOverlayColor?: string, allowCaptureRetake: boolean, cameraRatioOverlay: any, showCapturedImageCount?: boolean, captureButtonImage: any, cameraFlipImage: any, hideControls: any, showFrame: any, scanBarcode: any, laserColor: any, frameColor: any, torchOnImage: any, torchOffImage: any, onReadCode: (any) => void; onBottomButtonPressed: (any) => void; } type State = { captureImages: any[], flashData: any, torchMode: boolean, ratios: any[], ratioArrayPosition: number, imageCaptured: any, captured: boolean, cameraType: CameraType, } export default class CameraScreen extends Component { static propTypes = { allowCaptureRetake: PropTypes.bool, }; static defaultProps = { allowCaptureRetake: false, }; currentFlashArrayPosition: number; flashArray: any[]; camera: any; constructor(props) { super(props); this.currentFlashArrayPosition = 0; this.flashArray = [ { mode: FLASH_MODE_AUTO, image: _.get(this.props, 'flashImages.auto'), }, { mode: FLASH_MODE_ON, image: _.get(this.props, 'flashImages.on'), }, { mode: FLASH_MODE_OFF, image: _.get(this.props, 'flashImages.off'), }, ]; this.state = { captureImages: [], flashData: this.flashArray[this.currentFlashArrayPosition], torchMode: false, ratios: [], ratioArrayPosition: -1, imageCaptured: false, captured: false, cameraType: CameraType.Back, }; } componentDidMount() { let ratios = []; if (this.props.cameraRatioOverlay) { ratios = this.props.cameraRatioOverlay.ratios || []; } this.setState({ ratios: ratios || [], ratioArrayPosition: ratios.length > 0 ? 0 : -1, }); } isCaptureRetakeMode() { return !!(this.props.allowCaptureRetake && !_.isUndefined(this.state.imageCaptured)); } renderFlashButton() { return ( !this.isCaptureRetakeMode() && ( this.onSetFlash()}> ) ); } renderTorchButton() { return ( !this.isCaptureRetakeMode() && ( this.onSetTorch()}> ) ); } renderSwitchCameraButton() { return ( this.props.cameraFlipImage && !this.isCaptureRetakeMode() && ( this.onSwitchCameraPressed()}> ) ); } renderTopButtons() { return ( !this.props.hideControls && ( {this.renderFlashButton()} {this.renderSwitchCameraButton()} {this.renderTorchButton()} ) ); } renderCamera() { return ( {this.isCaptureRetakeMode() ? ( ) : ( (this.camera = cam)} style={{ flex: 1, justifyContent: 'flex-end' }} cameraType={this.state.cameraType} flashMode={this.state.flashData.mode} torchMode={this.state.torchMode ? 'on' : 'off'} focusMode={this.props.focusMode} zoomMode={this.props.zoomMode} ratioOverlay={this.state.ratios[this.state.ratioArrayPosition]} saveToCameraRoll={!this.props.allowCaptureRetake} showFrame={this.props.showFrame} scanBarcode={this.props.scanBarcode} laserColor={this.props.laserColor} frameColor={this.props.frameColor} onReadCode={this.props.onReadCode} /> )} ); } numberOfImagesTaken() { const numberTook = this.state.captureImages.length; if (numberTook >= 2) { return numberTook; } else if (this.state.captured) { return '1'; } else { return ''; } } renderCaptureButton() { return ( this.props.captureButtonImage && !this.isCaptureRetakeMode() && ( this.onCaptureImagePressed()}> {this.props.showCapturedImageCount && ( {this.numberOfImagesTaken()} )} ) ); } renderRatioStrip() { if (this.state.ratios.length === 0 || this.props.hideControls) { return null; } return ( Your images look best at a {this.state.ratios[0] || ''} ratio this.onRatioButtonPressed()} > {this.state.ratioOverlay} ); } sendBottomButtonPressedAction(type, captureRetakeMode, image) { if (this.props.onBottomButtonPressed) { this.props.onBottomButtonPressed({ type, captureImages: this.state.captureImages, captureRetakeMode, image }); } } onButtonPressed(type) { const captureRetakeMode = this.isCaptureRetakeMode(); if (captureRetakeMode) { if (type === 'left') { this.setState({ imageCaptured: undefined }); } } else { this.sendBottomButtonPressedAction(type, captureRetakeMode, null); } } renderBottomButton(type) { const showButton = true; if (showButton) { const buttonNameSuffix = this.isCaptureRetakeMode() ? 'CaptureRetakeButtonText' : 'ButtonText'; const buttonText = _(this.props).get(`actions.${type}${buttonNameSuffix}`); return ( this.onButtonPressed(type)} > {buttonText} ); } else { return ; } } renderBottomButtons() { return ( !this.props.hideControls && ( {this.renderBottomButton('left')} {this.renderCaptureButton()} ) ); } onSwitchCameraPressed() { const direction = this.state.cameraType === CameraType.Back ? CameraType.Front : CameraType.Back; this.setState({ cameraType: direction }); } onSetFlash() { this.currentFlashArrayPosition = (this.currentFlashArrayPosition + 1) % 3; const newFlashData = this.flashArray[this.currentFlashArrayPosition]; this.setState({ flashData: newFlashData }); } onSetTorch() { this.setState({ torchMode: !this.state.torchMode }); } async onCaptureImagePressed() { const image = await this.camera.capture(); if (this.props.allowCaptureRetake) { this.setState({ imageCaptured: image }); } else { if (image) { this.setState({ captured: true, imageCaptured: image, captureImages: _.concat(this.state.captureImages, image), }); } this.sendBottomButtonPressedAction('capture', false, image); } } onRatioButtonPressed() { const newRatiosArrayPosition = (this.state.ratioArrayPosition + 1) % this.state.ratios.length; this.setState({ ratioArrayPosition: newRatiosArrayPosition }); } render() { return ( {Platform.OS === 'android' && this.renderCamera()} {this.renderTopButtons()} {Platform.OS !== 'android' && this.renderCamera()} {this.renderRatioStrip()} {Platform.OS === 'android' && } {this.renderBottomButtons()} ); } } const styles = StyleSheet.create( { bottomButtons: { flex: 2, flexDirection: 'row', justifyContent: 'space-between', padding: 14, }, textStyle: { color: 'white', fontSize: 20, }, ratioBestText: { color: 'white', fontSize: 18, }, ratioText: { color: '#ffc233', fontSize: 18, }, topButtons: { flex: 1, flexDirection: 'row', justifyContent: 'space-between', paddingTop: 8, paddingBottom: 0, }, cameraContainer: { ...Platform.select({ android: { position: 'absolute', top: 0, left: 0, width, height, }, default: { flex: 10, flexDirection: 'column', }, }), }, captureButtonContainer: { flex: 1, justifyContent: 'center', alignItems: 'center', }, textNumberContainer: { position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, justifyContent: 'center', alignItems: 'center', }, bottomButton: { flex: 1, flexDirection: 'row', alignItems: 'center', padding: 10, }, bottomContainerGap: { flex: 1, flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center', padding: 10, }, gap: { flex: 10, flexDirection: 'column', }, });