import { UnavailabilityError } from '@unimodules/core'; import mapValues from 'lodash/mapValues'; import * as React from 'react'; import { Platform, ViewProps } from 'react-native'; import { PermissionResponse, PermissionStatus } from 'unimodules-permissions-interface'; import ExpoBarCodeScannerModule from './ExpoBarCodeScannerModule'; import ExpoBarCodeScannerView from './ExpoBarCodeScannerView'; const { BarCodeType, Type } = ExpoBarCodeScannerModule; const EVENT_THROTTLE_MS = 500; export type BarCodePoint = { x: number; y: number; }; export type BarCodeSize = { height: number; width: number; }; export type BarCodeBounds = { origin: BarCodePoint; size: BarCodeSize; }; export type BarCodeScannerResult = { type: string; data: string; bounds?: BarCodeBounds; cornerPoints?: BarCodePoint[]; }; export type BarCodeEvent = BarCodeScannerResult & { target?: number; }; export type BarCodeEventCallbackArguments = { nativeEvent: BarCodeEvent; }; export type BarCodeScannedCallback = (params: BarCodeEvent) => void; export { PermissionResponse, PermissionStatus }; export interface BarCodeScannerProps extends ViewProps { type?: 'front' | 'back' | number; barCodeTypes?: string[]; onBarCodeScanned: BarCodeScannedCallback; } export class BarCodeScanner extends React.Component { lastEvents: { [key: string]: any } = {}; lastEventsTimes: { [key: string]: any } = {}; static Constants = { BarCodeType, Type, }; static ConversionTables = { type: Type, }; static defaultProps = { type: Type.back, barCodeTypes: Object.values(BarCodeType), }; static async getPermissionsAsync(): Promise { return ExpoBarCodeScannerModule.getPermissionsAsync(); } static async requestPermissionsAsync(): Promise { return ExpoBarCodeScannerModule.requestPermissionsAsync(); } static async scanFromURLAsync( url: string, barCodeTypes: string[] = Object.values(BarCodeType) ): Promise { if (!ExpoBarCodeScannerModule.scanFromURLAsync) { throw new UnavailabilityError('expo-barcode-scanner', 'scanFromURLAsync'); } if (Array.isArray(barCodeTypes) && !barCodeTypes.length) { throw new Error('No barCodeTypes specified; provide at least one barCodeType for scanner'); } if (Platform.OS === 'ios') { if (Array.isArray(barCodeTypes) && !barCodeTypes.includes(BarCodeType.qr)) { // Only QR type is supported on iOS, fail if one tries to use other types throw new Error('Only QR type is supported by scanFromURLAsync() on iOS'); } // on iOS use only supported QR type return await ExpoBarCodeScannerModule.scanFromURLAsync(url, [BarCodeType.qr]); } // On other platforms, if barCodeTypes is not provided, use all available types return await ExpoBarCodeScannerModule.scanFromURLAsync(url, barCodeTypes); } render() { const nativeProps = this.convertNativeProps(this.props); const { onBarCodeScanned } = this.props; return ( ); } onObjectDetected = (callback?: BarCodeScannedCallback) => ({ nativeEvent, }: BarCodeEventCallbackArguments) => { const { type } = nativeEvent; if ( this.lastEvents[type] && this.lastEventsTimes[type] && JSON.stringify(nativeEvent) === this.lastEvents[type] && Date.now() - this.lastEventsTimes[type] < EVENT_THROTTLE_MS ) { return; } if (callback) { callback(nativeEvent); this.lastEventsTimes[type] = new Date(); this.lastEvents[type] = JSON.stringify(nativeEvent); } }; convertNativeProps(props: BarCodeScannerProps) { const newProps = mapValues(props, this.convertProp); return newProps; } convertProp(value: any, key: string): any { if (typeof value === 'string' && BarCodeScanner.ConversionTables[key]) { return BarCodeScanner.ConversionTables[key][value]; } return value; } } export const { Constants, getPermissionsAsync, requestPermissionsAsync } = BarCodeScanner;