1*dd9570b9SBartosz Kaszubowskiimport { BarCodeScanner, BarCodePoint, BarCodeBounds } from 'expo-barcode-scanner';
2e331da1dSEvan Baconimport * as ScreenOrientation from 'expo-screen-orientation';
3e331da1dSEvan Baconimport React from 'react';
4e331da1dSEvan Baconimport { Button, Platform, StyleSheet, Text, View } from 'react-native';
5e331da1dSEvan Baconimport * as Svg from 'react-native-svg';
669185572SBartłomiej Bukowski
769185572SBartłomiej Bukowskiconst BUTTON_COLOR = Platform.OS === 'ios' ? '#fff' : '#666';
869185572SBartłomiej Bukowski
991d99453SEvan Bacontype State = {
1069185572SBartłomiej Bukowski  type: any;
11bd4c8242SŁukasz Kosmaty  cornerPoints?: BarCodePoint[];
1269185572SBartłomiej Bukowski  alerting: boolean;
1369185572SBartłomiej Bukowski  haveDimensions: boolean;
1469185572SBartłomiej Bukowski  canvasHeight?: number;
1569185572SBartłomiej Bukowski  canvasWidth?: number;
16bd4c8242SŁukasz Kosmaty  boundingBox?: BarCodeBounds;
17bd4c8242SŁukasz Kosmaty  cornerPointsString?: string;
18bd4c8242SŁukasz Kosmaty  showBoundingBox: boolean;
19bd4c8242SŁukasz Kosmaty  showText: boolean;
20bd4c8242SŁukasz Kosmaty  data: string;
2169185572SBartłomiej Bukowski};
2269185572SBartłomiej Bukowski
2391d99453SEvan Baconconst initialState: State = {
2469185572SBartłomiej Bukowski  type: BarCodeScanner.Constants.Type.back,
2569185572SBartłomiej Bukowski  alerting: false,
2669185572SBartłomiej Bukowski  haveDimensions: false,
27bd4c8242SŁukasz Kosmaty  showBoundingBox: false,
28bd4c8242SŁukasz Kosmaty  data: '',
29bd4c8242SŁukasz Kosmaty  showText: false,
3069185572SBartłomiej Bukowski};
3169185572SBartłomiej Bukowski
3291d99453SEvan Baconfunction reducer(state: State, action: Partial<State>): State {
3391d99453SEvan Bacon  return {
3491d99453SEvan Bacon    ...state,
3591d99453SEvan Bacon    ...action,
36e331da1dSEvan Bacon  };
3769185572SBartłomiej Bukowski}
3869185572SBartłomiej Bukowski
3991d99453SEvan Baconexport default function BarcodeScannerScreen() {
40*dd9570b9SBartosz Kaszubowski  const [permission, requestPermission] = BarCodeScanner.usePermissions();
4169185572SBartłomiej Bukowski
42972c2d8bSCedric van Putten  if (!permission) {
43972c2d8bSCedric van Putten    return null;
4469185572SBartłomiej Bukowski  }
4569185572SBartłomiej Bukowski
46972c2d8bSCedric van Putten  if (permission.granted) {
4791d99453SEvan Bacon    return <BarcodeScannerExample />;
4891d99453SEvan Bacon  }
4991d99453SEvan Bacon
50972c2d8bSCedric van Putten  return (
51972c2d8bSCedric van Putten    <View style={[styles.container, { justifyContent: 'center', alignItems: 'center' }]}>
52972c2d8bSCedric van Putten      <Text style={{ margin: 16 }}>
53972c2d8bSCedric van Putten        You have not granted permission to use the camera on this device!
54972c2d8bSCedric van Putten      </Text>
55972c2d8bSCedric van Putten      <Button onPress={requestPermission} title="Grant permission" />
56972c2d8bSCedric van Putten    </View>
57972c2d8bSCedric van Putten  );
58972c2d8bSCedric van Putten}
59972c2d8bSCedric van Putten
6091d99453SEvan Baconfunction BarcodeScannerExample() {
6191d99453SEvan Bacon  const [state, dispatch] = React.useReducer(reducer, initialState);
6291d99453SEvan Bacon
6391d99453SEvan Bacon  let canChangeOrientation = false;
6491d99453SEvan Bacon
6591d99453SEvan Bacon  const toggleAlertingAboutResult = () => {
6691d99453SEvan Bacon    dispatch({ alerting: !state.alerting });
6791d99453SEvan Bacon  };
6891d99453SEvan Bacon
6991d99453SEvan Bacon  const toggleScreenOrientationState = () => {
7091d99453SEvan Bacon    if (canChangeOrientation) {
7191d99453SEvan Bacon      ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT_UP);
7291d99453SEvan Bacon    } else {
7391d99453SEvan Bacon      ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.ALL);
7491d99453SEvan Bacon    }
7591d99453SEvan Bacon    canChangeOrientation = !canChangeOrientation;
7691d99453SEvan Bacon  };
7791d99453SEvan Bacon
7891d99453SEvan Bacon  const setCanvasDimensions = ({ nativeEvent: { layout } }: any) => {
7991d99453SEvan Bacon    dispatch({ canvasWidth: layout.width, canvasHeight: layout.height, haveDimensions: true });
8091d99453SEvan Bacon  };
8191d99453SEvan Bacon
8291d99453SEvan Bacon  const toggleType = () => {
8391d99453SEvan Bacon    dispatch({
8491d99453SEvan Bacon      type:
8591d99453SEvan Bacon        state.type === BarCodeScanner.Constants.Type.back
8691d99453SEvan Bacon          ? BarCodeScanner.Constants.Type.front
8791d99453SEvan Bacon          : BarCodeScanner.Constants.Type.back,
8891d99453SEvan Bacon    });
8991d99453SEvan Bacon  };
9091d99453SEvan Bacon
9191d99453SEvan Bacon  const handleBarCodeScanned = (barCodeEvent: any) => {
9291d99453SEvan Bacon    if (state.alerting) {
9391d99453SEvan Bacon      requestAnimationFrame(() => {
9491d99453SEvan Bacon        alert(JSON.stringify(barCodeEvent));
9591d99453SEvan Bacon      });
9691d99453SEvan Bacon    }
9791d99453SEvan Bacon    dispatch({
9891d99453SEvan Bacon      data: barCodeEvent.data,
9991d99453SEvan Bacon      cornerPoints: barCodeEvent.cornerPoints,
10091d99453SEvan Bacon      boundingBox: barCodeEvent.bounds,
10191d99453SEvan Bacon      cornerPointsString: getPointsString(barCodeEvent.cornerPoints),
10291d99453SEvan Bacon    });
10391d99453SEvan Bacon  };
10491d99453SEvan Bacon
10591d99453SEvan Bacon  const toggleText = () => dispatch({ showText: !state.showText });
10691d99453SEvan Bacon
10791d99453SEvan Bacon  const toggleBoundingBox = () => dispatch({ showBoundingBox: !state.showBoundingBox });
10891d99453SEvan Bacon
10991d99453SEvan Bacon  const getPointsString = (barCodePoints?: BarCodePoint[]): string | undefined => {
11091d99453SEvan Bacon    if (!barCodePoints) {
11191d99453SEvan Bacon      return;
11291d99453SEvan Bacon    }
11391d99453SEvan Bacon    return barCodePoints.map(({ x, y }) => `${Math.round(x)},${Math.round(y)}`).join(' ');
11491d99453SEvan Bacon  };
11591d99453SEvan Bacon
116cf13b9bdSŁukasz Kosmaty  const circles = (state.cornerPoints || []).map((point, index) => (
117cf13b9bdSŁukasz Kosmaty    <Svg.Circle
118cf13b9bdSŁukasz Kosmaty      cx={point.x}
119cf13b9bdSŁukasz Kosmaty      cy={point.y}
120cf13b9bdSŁukasz Kosmaty      r={3}
121cf13b9bdSŁukasz Kosmaty      strokeWidth={0.5}
122cf13b9bdSŁukasz Kosmaty      stroke="#CF4048"
123cf13b9bdSŁukasz Kosmaty      fill="#CF4048"
124cf13b9bdSŁukasz Kosmaty      key={index}
125cf13b9bdSŁukasz Kosmaty    />
126cf13b9bdSŁukasz Kosmaty  ));
12769185572SBartłomiej Bukowski
12869185572SBartłomiej Bukowski  return (
12969185572SBartłomiej Bukowski    <View style={styles.container}>
13069185572SBartłomiej Bukowski      <BarCodeScanner
13191d99453SEvan Bacon        onLayout={setCanvasDimensions}
13291d99453SEvan Bacon        onBarCodeScanned={handleBarCodeScanned}
13369185572SBartłomiej Bukowski        barCodeTypes={[
13469185572SBartłomiej Bukowski          BarCodeScanner.Constants.BarCodeType.qr,
13569185572SBartłomiej Bukowski          BarCodeScanner.Constants.BarCodeType.pdf417,
13669185572SBartłomiej Bukowski          BarCodeScanner.Constants.BarCodeType.code128,
1371f9c336aSBartłomiej Bukowski          BarCodeScanner.Constants.BarCodeType.code39,
13869185572SBartłomiej Bukowski        ]}
13991d99453SEvan Bacon        type={state.type}
14069185572SBartłomiej Bukowski        style={styles.preview}
14169185572SBartłomiej Bukowski      />
14269185572SBartłomiej Bukowski
14391d99453SEvan Bacon      {state.haveDimensions && (
14491d99453SEvan Bacon        <Svg.Svg height={state.canvasHeight} width={state.canvasWidth} style={styles.svg}>
14569185572SBartłomiej Bukowski          <Svg.Circle
14691d99453SEvan Bacon            cx={state.canvasWidth! / 2}
14791d99453SEvan Bacon            cy={state.canvasHeight! / 2}
14869185572SBartłomiej Bukowski            r={2}
14969185572SBartłomiej Bukowski            strokeWidth={2.5}
15069185572SBartłomiej Bukowski            stroke="#e74c3c"
15169185572SBartłomiej Bukowski            fill="#f1c40f"
15269185572SBartłomiej Bukowski          />
15391d99453SEvan Bacon          {state.showBoundingBox && state.cornerPointsString && (
154bd4c8242SŁukasz Kosmaty            <Svg.Polygon
15591d99453SEvan Bacon              points={state.cornerPointsString}
15669185572SBartłomiej Bukowski              strokeWidth={2}
157bd4c8242SŁukasz Kosmaty              stroke="#582E6E"
15869185572SBartłomiej Bukowski              fill="none"
15969185572SBartłomiej Bukowski            />
16069185572SBartłomiej Bukowski          )}
16191d99453SEvan Bacon          {state.showText && state.boundingBox && (
162bd4c8242SŁukasz Kosmaty            <Svg.Text
163bd4c8242SŁukasz Kosmaty              fill="#CF4048"
164bd4c8242SŁukasz Kosmaty              stroke="#CF4048"
165bd4c8242SŁukasz Kosmaty              fontSize="14"
16691d99453SEvan Bacon              x={state.boundingBox.origin.x}
16791d99453SEvan Bacon              y={state.boundingBox.origin.y - 8}>
16891d99453SEvan Bacon              {state.data}
169bd4c8242SŁukasz Kosmaty            </Svg.Text>
170bd4c8242SŁukasz Kosmaty          )}
171bd4c8242SŁukasz Kosmaty
17269185572SBartłomiej Bukowski          {circles}
1736e2bfc6bSTomasz Sapeta        </Svg.Svg>
17469185572SBartłomiej Bukowski      )}
17569185572SBartłomiej Bukowski
17669185572SBartłomiej Bukowski      <View style={styles.toolbar}>
17791d99453SEvan Bacon        <Button color={BUTTON_COLOR} title="Direction" onPress={toggleType} />
17891d99453SEvan Bacon        <Button color={BUTTON_COLOR} title="Orientation" onPress={toggleScreenOrientationState} />
179972c2d8bSCedric van Putten        <Button
180972c2d8bSCedric van Putten          title="Bounding box"
181972c2d8bSCedric van Putten          onPress={toggleBoundingBox}
182972c2d8bSCedric van Putten          color={state.showBoundingBox ? undefined : BUTTON_COLOR}
183972c2d8bSCedric van Putten        />
184972c2d8bSCedric van Putten        <Button
185972c2d8bSCedric van Putten          title="Text"
186972c2d8bSCedric van Putten          onPress={toggleText}
187972c2d8bSCedric van Putten          color={state.showText ? undefined : BUTTON_COLOR}
188972c2d8bSCedric van Putten        />
189972c2d8bSCedric van Putten        <Button
190972c2d8bSCedric van Putten          title="Alerting"
191972c2d8bSCedric van Putten          onPress={toggleAlertingAboutResult}
192972c2d8bSCedric van Putten          color={state.alerting ? undefined : BUTTON_COLOR}
193972c2d8bSCedric van Putten        />
19469185572SBartłomiej Bukowski      </View>
19569185572SBartłomiej Bukowski    </View>
19669185572SBartłomiej Bukowski  );
19769185572SBartłomiej Bukowski}
19869185572SBartłomiej Bukowski
19991d99453SEvan BaconBarcodeScannerExample.navigationOptions = {
20091d99453SEvan Bacon  title: '<BarCodeScanner />',
201bd4c8242SŁukasz Kosmaty};
202bd4c8242SŁukasz Kosmaty
20369185572SBartłomiej Bukowskiconst styles = StyleSheet.create({
20469185572SBartłomiej Bukowski  container: {
20569185572SBartłomiej Bukowski    flex: 1,
20669185572SBartłomiej Bukowski  },
20769185572SBartłomiej Bukowski  preview: {
20869185572SBartłomiej Bukowski    ...StyleSheet.absoluteFillObject,
20969185572SBartłomiej Bukowski    backgroundColor: 'black',
21069185572SBartłomiej Bukowski  },
21169185572SBartłomiej Bukowski  toolbar: {
21269185572SBartłomiej Bukowski    position: 'absolute',
21369185572SBartłomiej Bukowski    bottom: 0,
21469185572SBartłomiej Bukowski    left: 0,
21569185572SBartłomiej Bukowski    right: 0,
21669185572SBartłomiej Bukowski    paddingVertical: 10,
21769185572SBartłomiej Bukowski    paddingHorizontal: 10,
21869185572SBartłomiej Bukowski    flexDirection: 'row',
21969185572SBartłomiej Bukowski    justifyContent: 'space-between',
22069185572SBartłomiej Bukowski    backgroundColor: 'rgba(255,255,255,0.2)',
22169185572SBartłomiej Bukowski  },
22269185572SBartłomiej Bukowski  svg: {
22369185572SBartłomiej Bukowski    position: 'absolute',
22469185572SBartłomiej Bukowski    borderWidth: 2,
22569185572SBartłomiej Bukowski    borderColor: 'red',
22669185572SBartłomiej Bukowski  },
22769185572SBartłomiej Bukowski});
228