1 | import { UnavailabilityError } from '@unimodules/core';
|
2 | import mapValues from 'lodash/mapValues';
|
3 | import * as React from 'react';
|
4 | import { Platform, ViewProps } from 'react-native';
|
5 | import { PermissionResponse, PermissionStatus } from 'unimodules-permissions-interface';
|
6 |
|
7 | import ExpoBarCodeScannerModule from './ExpoBarCodeScannerModule';
|
8 | import ExpoBarCodeScannerView from './ExpoBarCodeScannerView';
|
9 |
|
10 | const { BarCodeType, Type } = ExpoBarCodeScannerModule;
|
11 |
|
12 | const EVENT_THROTTLE_MS = 500;
|
13 |
|
14 | export type BarCodePoint = {
|
15 | x: number;
|
16 | y: number;
|
17 | };
|
18 |
|
19 | export type BarCodeSize = {
|
20 | height: number;
|
21 | width: number;
|
22 | };
|
23 |
|
24 | export type BarCodeBounds = {
|
25 | origin: BarCodePoint;
|
26 | size: BarCodeSize;
|
27 | };
|
28 |
|
29 | export type BarCodeScannerResult = {
|
30 | type: string;
|
31 | data: string;
|
32 | bounds?: BarCodeBounds;
|
33 | cornerPoints?: BarCodePoint[];
|
34 | };
|
35 |
|
36 | export type BarCodeEvent = BarCodeScannerResult & {
|
37 | target?: number;
|
38 | };
|
39 |
|
40 | export type BarCodeEventCallbackArguments = {
|
41 | nativeEvent: BarCodeEvent;
|
42 | };
|
43 |
|
44 | export type BarCodeScannedCallback = (params: BarCodeEvent) => void;
|
45 |
|
46 | export { PermissionResponse, PermissionStatus };
|
47 |
|
48 | export interface BarCodeScannerProps extends ViewProps {
|
49 | type?: 'front' | 'back' | number;
|
50 | barCodeTypes?: string[];
|
51 | onBarCodeScanned?: BarCodeScannedCallback;
|
52 | }
|
53 |
|
54 | export class BarCodeScanner extends React.Component<BarCodeScannerProps> {
|
55 | lastEvents: { [key: string]: any } = {};
|
56 | lastEventsTimes: { [key: string]: any } = {};
|
57 |
|
58 | static Constants = {
|
59 | BarCodeType,
|
60 | Type,
|
61 | };
|
62 |
|
63 | static ConversionTables = {
|
64 | type: Type,
|
65 | };
|
66 |
|
67 | static defaultProps = {
|
68 | type: Type.back,
|
69 | barCodeTypes: Object.values(BarCodeType),
|
70 | };
|
71 |
|
72 | static async getPermissionsAsync(): Promise<PermissionResponse> {
|
73 | return ExpoBarCodeScannerModule.getPermissionsAsync();
|
74 | }
|
75 |
|
76 | static async requestPermissionsAsync(): Promise<PermissionResponse> {
|
77 | return ExpoBarCodeScannerModule.requestPermissionsAsync();
|
78 | }
|
79 |
|
80 | static async scanFromURLAsync(
|
81 | url: string,
|
82 | barCodeTypes: string[] = Object.values(BarCodeType)
|
83 | ): Promise<BarCodeScannerResult[]> {
|
84 | if (!ExpoBarCodeScannerModule.scanFromURLAsync) {
|
85 | throw new UnavailabilityError('expo-barcode-scanner', 'scanFromURLAsync');
|
86 | }
|
87 | if (Array.isArray(barCodeTypes) && !barCodeTypes.length) {
|
88 | throw new Error('No barCodeTypes specified; provide at least one barCodeType for scanner');
|
89 | }
|
90 |
|
91 | if (Platform.OS === 'ios') {
|
92 | if (Array.isArray(barCodeTypes) && !barCodeTypes.includes(BarCodeType.qr)) {
|
93 |
|
94 | throw new Error('Only QR type is supported by scanFromURLAsync() on iOS');
|
95 | }
|
96 |
|
97 | return await ExpoBarCodeScannerModule.scanFromURLAsync(url, [BarCodeType.qr]);
|
98 | }
|
99 |
|
100 |
|
101 | return await ExpoBarCodeScannerModule.scanFromURLAsync(url, barCodeTypes);
|
102 | }
|
103 |
|
104 | render() {
|
105 | const nativeProps = this.convertNativeProps(this.props);
|
106 | const { onBarCodeScanned } = this.props;
|
107 | return (
|
108 | <ExpoBarCodeScannerView
|
109 | {...nativeProps}
|
110 | onBarCodeScanned={this.onObjectDetected(onBarCodeScanned)}
|
111 | />
|
112 | );
|
113 | }
|
114 |
|
115 | onObjectDetected = (callback?: BarCodeScannedCallback) => ({
|
116 | nativeEvent,
|
117 | }: BarCodeEventCallbackArguments) => {
|
118 | const { type } = nativeEvent;
|
119 | if (
|
120 | this.lastEvents[type] &&
|
121 | this.lastEventsTimes[type] &&
|
122 | JSON.stringify(nativeEvent) === this.lastEvents[type] &&
|
123 | Date.now() - this.lastEventsTimes[type] < EVENT_THROTTLE_MS
|
124 | ) {
|
125 | return;
|
126 | }
|
127 |
|
128 | if (callback) {
|
129 | callback(nativeEvent);
|
130 | this.lastEventsTimes[type] = new Date();
|
131 | this.lastEvents[type] = JSON.stringify(nativeEvent);
|
132 | }
|
133 | };
|
134 |
|
135 | convertNativeProps(props: BarCodeScannerProps) {
|
136 | const newProps = mapValues(props, this.convertProp);
|
137 | return newProps;
|
138 | }
|
139 |
|
140 | convertProp(value: any, key: string): any {
|
141 | if (typeof value === 'string' && BarCodeScanner.ConversionTables[key]) {
|
142 | return BarCodeScanner.ConversionTables[key][value];
|
143 | }
|
144 | return value;
|
145 | }
|
146 | }
|
147 |
|
148 | export const { Constants, getPermissionsAsync, requestPermissionsAsync } = BarCodeScanner;
|