From d9a19300993714be512eeb08f6a424b0f6642f5b Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Wed, 3 Apr 2024 15:14:14 +0200 Subject: [PATCH 01/16] feat: add barcode format controls --- .../src/BarcodeScanner.editorConfig.ts | 5 ++- .../src/BarcodeScanner.tsx | 2 ++ .../src/BarcodeScanner.xml | 31 +++++++++++++++- .../src/components/BarcodeScanner.tsx | 9 ++++- .../src/hooks/useReader.ts | 35 ++++++++++++++----- .../typings/BarcodeScannerProps.d.ts | 14 ++++++++ 6 files changed, 84 insertions(+), 12 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts index ef2449649a..29189f4eb5 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts @@ -1,5 +1,5 @@ import { StructurePreviewProps } from "@mendix/widget-plugin-platform/preview/structure-preview-api"; -import { Properties, transformGroupsIntoTabs } from "@mendix/pluggable-widgets-tools"; +import { hidePropertyIn, Properties, transformGroupsIntoTabs } from "@mendix/pluggable-widgets-tools"; import { BarcodeScannerContainerProps } from "../typings/BarcodeScannerProps"; import BarcodeScannerSvg from "./assets/barcodescanner.svg"; @@ -13,6 +13,9 @@ export function getProperties( if (platform === "web") { transformGroupsIntoTabs(defaultProperties); } + if (_.useAllFormats) { + hidePropertyIn(defaultProperties, _, "barcodeFormats"); + } return defaultProperties; } diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.tsx index b03df4e182..6381f5cdc9 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.tsx @@ -22,6 +22,8 @@ export const BarcodeScanner: FunctionComponent = p onDetect={onDetect} showMask={props.showMask} class={props.class} + useAllFormats={props.useAllFormats} + barcodeFormats={props.barcodeFormats} heightUnit={props.heightUnit} height={props.height} widthUnit={props.widthUnit} diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.xml b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.xml index 6046c2020a..778dfe1ed9 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.xml +++ b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.xml @@ -19,8 +19,37 @@ Show barcode mask Apply a mask to camera view, as a specific target area for the barcode. + + Use all barcode formats + Scan for all available barcode formats + + + Enabled barcode formats + + + + + Barcode format + Barcode format which should be recognized by the scanner + + Aztec + Code 39 + Code 128 + Data Matrix + EAN-8 + EAN-13 + ITF + PDF 417 + QR Code + RSS-14 + UPC-A + UPC-E + + + + + - On detect action diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index c2e1c449b6..489a85f170 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -4,6 +4,7 @@ import { Alert } from "@mendix/widget-plugin-component-kit/Alert"; import { Dimensions, getDimensions } from "@mendix/widget-plugin-platform/utils/get-dimensions"; import { useCustomErrorMessage } from "../hooks/useCustomErrorMessage"; import { useReader } from "../hooks/useReader"; +import { BarcodeFormatsType } from "../../typings/BarcodeScannerProps"; import "../ui/BarcodeScanner.scss"; @@ -48,19 +49,25 @@ export interface BarcodeScannerProps extends Dimensions { onDetect?: (data: string) => void; showMask: boolean; class: string; + useAllFormats: boolean; + barcodeFormats: BarcodeFormatsType[]; } export function BarcodeScanner({ onDetect, showMask, class: className, + barcodeFormats, + useAllFormats, ...dimensions }: BarcodeScannerProps): ReactElement | null { const [errorMessage, setError] = useCustomErrorMessage(); const videoRef = useReader({ onSuccess: onDetect, onError: setError, - useCrop: showMask + useCrop: showMask, + barcodeFormats: barcodeFormats, + useAllFormats: useAllFormats }); const supportsCameraAccess = typeof navigator?.mediaDevices?.getUserMedia === "function"; const onCanPlay = useCallback((event: SyntheticEvent) => { diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index 56649e6202..c86c9d2e9c 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -10,15 +10,7 @@ import { Result } from "@zxing/library/cjs"; import { useEventCallback } from "@mendix/widget-plugin-hooks/useEventCallback"; - -const hints = new Map(); -// RSS_Expanded is not production ready yet. -const exclusions = new Set([BarcodeFormat.RSS_EXPANDED]); -// `BarcodeFormat` is a TypeScript enum. Calling `Object.values` on it returns an array of string and ints, we only want the latter. -const formats = Object.values(BarcodeFormat) - .filter((format): format is BarcodeFormat => typeof format !== "string") - .filter(format => !exclusions.has(format)); -hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); +import { BarcodeFormatsType } from "../../typings/BarcodeScannerProps"; const mediaStreamConstraints: MediaStreamConstraints = { audio: false, @@ -33,6 +25,8 @@ type UseReaderHook = (args: { onSuccess?: (data: string) => void; onError?: (e: Error) => void; useCrop: boolean; + barcodeFormats: BarcodeFormatsType[]; + useAllFormats: boolean; }) => RefObject; export const useReader: UseReaderHook = args => { @@ -83,6 +77,29 @@ export const useReader: UseReaderHook = args => { }; useEffect(() => { + const hints = new Map(); + let formats: BarcodeFormat[] = []; + if (args.useAllFormats) { + formats = [ + BarcodeFormat.UPC_A, + BarcodeFormat.UPC_E, + BarcodeFormat.EAN_8, + BarcodeFormat.EAN_13, + BarcodeFormat.CODE_39, + BarcodeFormat.CODE_128, + BarcodeFormat.ITF, + BarcodeFormat.RSS_14, + BarcodeFormat.QR_CODE, + BarcodeFormat.DATA_MATRIX, + BarcodeFormat.AZTEC, + BarcodeFormat.PDF_417 + ]; + } else { + args.barcodeFormats.forEach((val, index) => { + formats[index] = BarcodeFormat[val.barcodeFormat]; + }); + } + hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); const reader = new BrowserMultiFormatReader(hints, 500); const stop = (): void => { diff --git a/packages/pluggableWidgets/barcode-scanner-web/typings/BarcodeScannerProps.d.ts b/packages/pluggableWidgets/barcode-scanner-web/typings/BarcodeScannerProps.d.ts index 927ff9e366..e7da52e304 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/typings/BarcodeScannerProps.d.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/typings/BarcodeScannerProps.d.ts @@ -6,10 +6,20 @@ import { CSSProperties } from "react"; import { ActionValue, EditableValue } from "mendix"; +export type BarcodeFormatEnum = "AZTEC" | "CODE_39" | "CODE_128" | "DATA_MATRIX" | "EAN_8" | "EAN_13" | "ITF" | "PDF_417" | "QR_CODE" | "RSS_14" | "UPC_A" | "UPC_E"; + +export interface BarcodeFormatsType { + barcodeFormat: BarcodeFormatEnum; +} + export type WidthUnitEnum = "percentage" | "pixels"; export type HeightUnitEnum = "percentageOfWidth" | "pixels" | "percentageOfParent"; +export interface BarcodeFormatsPreviewType { + barcodeFormat: BarcodeFormatEnum; +} + export interface BarcodeScannerContainerProps { name: string; class: string; @@ -17,6 +27,8 @@ export interface BarcodeScannerContainerProps { tabIndex?: number; datasource: EditableValue; showMask: boolean; + useAllFormats: boolean; + barcodeFormats: BarcodeFormatsType[]; onDetect?: ActionValue; widthUnit: WidthUnitEnum; width: number; @@ -35,6 +47,8 @@ export interface BarcodeScannerPreviewProps { readOnly: boolean; datasource: string; showMask: boolean; + useAllFormats: boolean; + barcodeFormats: BarcodeFormatsPreviewType[]; onDetect: {} | null; widthUnit: WidthUnitEnum; width: number | null; From 5ad8c3da464ab4752732e3f0ca19c0cb426a2e50 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 10:05:20 +0200 Subject: [PATCH 02/16] chore: add changelog, bump minor version --- packages/pluggableWidgets/barcode-scanner-web/CHANGELOG.md | 4 ++++ packages/pluggableWidgets/barcode-scanner-web/package.json | 2 +- packages/pluggableWidgets/barcode-scanner-web/src/package.xml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/CHANGELOG.md b/packages/pluggableWidgets/barcode-scanner-web/CHANGELOG.md index c9848a596c..cc5b798548 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/CHANGELOG.md +++ b/packages/pluggableWidgets/barcode-scanner-web/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added + +- Added barcode format controls to prevent incorrect scanning + ## [2.3.1] - 2023-09-27 ### Fixed diff --git a/packages/pluggableWidgets/barcode-scanner-web/package.json b/packages/pluggableWidgets/barcode-scanner-web/package.json index 3c305ad716..989587c847 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/package.json +++ b/packages/pluggableWidgets/barcode-scanner-web/package.json @@ -1,7 +1,7 @@ { "name": "@mendix/barcode-scanner-web", "widgetName": "BarcodeScanner", - "version": "2.3.1", + "version": "2.4.0", "description": "Displays a barcode scanner", "copyright": "© Mendix Technology BV 2023. All rights reserved.", "license": "Apache-2.0", diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/package.xml b/packages/pluggableWidgets/barcode-scanner-web/src/package.xml index e2eb53e476..f27a674a0c 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/package.xml +++ b/packages/pluggableWidgets/barcode-scanner-web/src/package.xml @@ -1,6 +1,6 @@ - + From ba80176db9d324f279c0160a6dd1b9dd6f5dc590 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 14:22:17 +0200 Subject: [PATCH 03/16] fix: lint errors --- .../barcode-scanner-web/src/components/BarcodeScanner.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index 489a85f170..d58a6ec560 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -66,8 +66,8 @@ export function BarcodeScanner({ onSuccess: onDetect, onError: setError, useCrop: showMask, - barcodeFormats: barcodeFormats, - useAllFormats: useAllFormats + barcodeFormats, + useAllFormats }); const supportsCameraAccess = typeof navigator?.mediaDevices?.getUserMedia === "function"; const onCanPlay = useCallback((event: SyntheticEvent) => { From 14f12eecb080c08b71278663c21e25b569563c4d Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 14:40:04 +0200 Subject: [PATCH 04/16] fix: define property as optional --- .../barcode-scanner-web/src/components/BarcodeScanner.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index d58a6ec560..783d349c2b 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -50,7 +50,7 @@ export interface BarcodeScannerProps extends Dimensions { showMask: boolean; class: string; useAllFormats: boolean; - barcodeFormats: BarcodeFormatsType[]; + barcodeFormats?: BarcodeFormatsType[]; } export function BarcodeScanner({ @@ -66,7 +66,7 @@ export function BarcodeScanner({ onSuccess: onDetect, onError: setError, useCrop: showMask, - barcodeFormats, + barcodeFormats: barcodeFormats, useAllFormats }); const supportsCameraAccess = typeof navigator?.mediaDevices?.getUserMedia === "function"; From 5ec027bcc8969f4548dcb3c4e2017359fdc0f4b7 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 14:40:24 +0200 Subject: [PATCH 05/16] fix: fix unit tests --- .../__tests__/BarcodeScanner.spec.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx index d3494f0f71..242fd715ce 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx @@ -38,17 +38,23 @@ describe("Barcode scanner", () => { it("renders video and overlay correctly", () => { mockGetUserMedia(jest.fn()); - expect(render().container).toMatchSnapshot(); + expect( + render().container + ).toMatchSnapshot(); }); it("does not show the overlay when the user opts out of it", () => { mockGetUserMedia(jest.fn()); - expect(render().container).toMatchSnapshot(); + expect( + render().container + ).toMatchSnapshot(); }); it("shows an appropriate error when the mediaDevices API is not present (like over http)", async () => { expect(navigator.mediaDevices).toBe(undefined); - expect(render().container).toMatchSnapshot(); + expect( + render().container + ).toMatchSnapshot(); }); it("prop health check: pass onDetect prop as onSuccess callback", async () => { @@ -58,7 +64,7 @@ describe("Barcode scanner", () => { }); mockGetUserMedia(jest.fn()); - render(); + render(); await waitFor(() => expect(onDetectMock).toBeCalledWith("42")); }); @@ -71,7 +77,7 @@ describe("Barcode scanner", () => { mockGetUserMedia(jest.fn()); await act(async () => { - render(); + render(); }); await waitFor(() => expect(screen.getByText(/some error message/i)).toBeVisible()); }); @@ -86,7 +92,7 @@ describe("Barcode scanner", () => { mockGetUserMedia(jest.fn()); await act(async () => { - render(); + render(); }); await waitFor(() => expect(screen.getByText(/Unable to decode from stream/i)).toBeVisible()); }); From f82bbb1833a67381dfe3cbd5fdab46acbb8002b6 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 15:13:49 +0200 Subject: [PATCH 06/16] fix: apply review comment suggestions --- .../barcode-scanner-web/src/BarcodeScanner.editorConfig.ts | 6 +++--- .../barcode-scanner-web/src/hooks/useReader.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts index 29189f4eb5..ca52cc0e26 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts @@ -6,15 +6,15 @@ import BarcodeScannerSvg from "./assets/barcodescanner.svg"; import BarcodeScannerSvgDark from "./assets/barcodescanner-dark.svg"; export function getProperties( - _: BarcodeScannerContainerProps, + barcodeScannerContainerProps: BarcodeScannerContainerProps, defaultProperties: Properties, platform: "web" | "desktop" ): Properties { if (platform === "web") { transformGroupsIntoTabs(defaultProperties); } - if (_.useAllFormats) { - hidePropertyIn(defaultProperties, _, "barcodeFormats"); + if (barcodeScannerContainerProps.useAllFormats) { + hidePropertyIn(defaultProperties, barcodeScannerContainerProps, "barcodeFormats"); } return defaultProperties; } diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index c86c9d2e9c..8785693222 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -25,7 +25,7 @@ type UseReaderHook = (args: { onSuccess?: (data: string) => void; onError?: (e: Error) => void; useCrop: boolean; - barcodeFormats: BarcodeFormatsType[]; + barcodeFormats?: BarcodeFormatsType[]; useAllFormats: boolean; }) => RefObject; @@ -95,7 +95,7 @@ export const useReader: UseReaderHook = args => { BarcodeFormat.PDF_417 ]; } else { - args.barcodeFormats.forEach((val, index) => { + args.barcodeFormats!.map((val, index) => { formats[index] = BarcodeFormat[val.barcodeFormat]; }); } From ca9ba5cdc0160c0e7ce4d84925578e9b5e808b96 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 15:40:18 +0200 Subject: [PATCH 07/16] fix: lint and test errors --- .../src/components/BarcodeScanner.tsx | 2 +- .../components/__tests__/BarcodeScanner.spec.tsx | 16 ++++++---------- .../barcode-scanner-web/src/hooks/useReader.ts | 4 +--- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index 783d349c2b..0c764d1d76 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -66,7 +66,7 @@ export function BarcodeScanner({ onSuccess: onDetect, onError: setError, useCrop: showMask, - barcodeFormats: barcodeFormats, + barcodeFormats, useAllFormats }); const supportsCameraAccess = typeof navigator?.mediaDevices?.getUserMedia === "function"; diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx index 242fd715ce..36c8e9620f 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/BarcodeScanner.spec.tsx @@ -38,23 +38,19 @@ describe("Barcode scanner", () => { it("renders video and overlay correctly", () => { mockGetUserMedia(jest.fn()); - expect( - render().container - ).toMatchSnapshot(); + expect(render().container).toMatchSnapshot(); }); it("does not show the overlay when the user opts out of it", () => { mockGetUserMedia(jest.fn()); expect( - render().container + render().container ).toMatchSnapshot(); }); it("shows an appropriate error when the mediaDevices API is not present (like over http)", async () => { expect(navigator.mediaDevices).toBe(undefined); - expect( - render().container - ).toMatchSnapshot(); + expect(render().container).toMatchSnapshot(); }); it("prop health check: pass onDetect prop as onSuccess callback", async () => { @@ -64,7 +60,7 @@ describe("Barcode scanner", () => { }); mockGetUserMedia(jest.fn()); - render(); + render(); await waitFor(() => expect(onDetectMock).toBeCalledWith("42")); }); @@ -77,7 +73,7 @@ describe("Barcode scanner", () => { mockGetUserMedia(jest.fn()); await act(async () => { - render(); + render(); }); await waitFor(() => expect(screen.getByText(/some error message/i)).toBeVisible()); }); @@ -92,7 +88,7 @@ describe("Barcode scanner", () => { mockGetUserMedia(jest.fn()); await act(async () => { - render(); + render(); }); await waitFor(() => expect(screen.getByText(/Unable to decode from stream/i)).toBeVisible()); }); diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index 8785693222..c6f147678e 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -95,9 +95,7 @@ export const useReader: UseReaderHook = args => { BarcodeFormat.PDF_417 ]; } else { - args.barcodeFormats!.map((val, index) => { - formats[index] = BarcodeFormat[val.barcodeFormat]; - }); + args.barcodeFormats!.map((val, index) => (formats[index] = BarcodeFormat[val.barcodeFormat])); } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); const reader = new BrowserMultiFormatReader(hints, 500); From 2b76613b7aef452214c444e7ffab10aab29163ea Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Mon, 8 Apr 2024 16:31:31 +0200 Subject: [PATCH 08/16] fix: fix nits --- .../barcode-scanner-web/src/BarcodeScanner.editorConfig.ts | 6 +++--- .../barcode-scanner-web/src/hooks/useReader.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts index ca52cc0e26..0aceba0186 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/BarcodeScanner.editorConfig.ts @@ -6,15 +6,15 @@ import BarcodeScannerSvg from "./assets/barcodescanner.svg"; import BarcodeScannerSvgDark from "./assets/barcodescanner-dark.svg"; export function getProperties( - barcodeScannerContainerProps: BarcodeScannerContainerProps, + values: BarcodeScannerContainerProps, defaultProperties: Properties, platform: "web" | "desktop" ): Properties { if (platform === "web") { transformGroupsIntoTabs(defaultProperties); } - if (barcodeScannerContainerProps.useAllFormats) { - hidePropertyIn(defaultProperties, barcodeScannerContainerProps, "barcodeFormats"); + if (values.useAllFormats) { + hidePropertyIn(defaultProperties, values, "barcodeFormats"); } return defaultProperties; } diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index c6f147678e..a1202a7b99 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -95,7 +95,7 @@ export const useReader: UseReaderHook = args => { BarcodeFormat.PDF_417 ]; } else { - args.barcodeFormats!.map((val, index) => (formats[index] = BarcodeFormat[val.barcodeFormat])); + formats = args.barcodeFormats!.map(val => BarcodeFormat[val.barcodeFormat]); } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); const reader = new BrowserMultiFormatReader(hints, 500); From 1b9e0f6397964fbf9176facb506891a8135e413a Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Tue, 9 Apr 2024 10:27:58 +0200 Subject: [PATCH 09/16] fix: eslint warnings --- .../barcode-scanner-web/src/hooks/useReader.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index a1202a7b99..f90289df32 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -34,7 +34,7 @@ export const useReader: UseReaderHook = args => { const onSuccess = useEventCallback(args.onSuccess); const onError = useEventCallback(args.onError); const scale = 0.3; - const stopped = useRef(false); + const stopped = useRef(false); const checkNotFound = (error: any): boolean => { const ifNotFound = error instanceof NotFoundException; return ifNotFound && !stopped.current; @@ -45,7 +45,7 @@ export const useReader: UseReaderHook = args => { const captureCanvas = reader.createCaptureCanvas(videoRef.current!); captureCanvas.width = cropWidth; captureCanvas.height = cropWidth; - const loop = (resolve: (value: Result) => void, reject: (reason?: Error) => void) => { + const loop = (resolve: (value: Result) => void, reject: (reason?: Error) => void): void => { try { const canvasContext = captureCanvas.getContext("2d"); if (canvasContext !== null) { From 80685af58ffe170e1b6378d3f5e2d93807d6e0d6 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Fri, 3 May 2024 21:32:31 +0200 Subject: [PATCH 10/16] fix: fix issue with crop area --- .../src/components/BarcodeScanner.tsx | 2 +- .../src/hooks/useReader.ts | 40 +++++++++++++------ .../src/ui/BarcodeScanner.scss | 6 +-- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index 0c764d1d76..1cfedb5705 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -29,7 +29,7 @@ export function BarcodeScannerOverlay({
-
+
diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index f90289df32..153418060b 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -8,7 +8,7 @@ import { HybridBinarizer, NotFoundException, Result -} from "@zxing/library/cjs"; +} from "@zxing/library"; import { useEventCallback } from "@mendix/widget-plugin-hooks/useEventCallback"; import { BarcodeFormatsType } from "../../typings/BarcodeScannerProps"; @@ -33,7 +33,6 @@ export const useReader: UseReaderHook = args => { const videoRef = useRef(null); const onSuccess = useEventCallback(args.onSuccess); const onError = useEventCallback(args.onError); - const scale = 0.3; const stopped = useRef(false); const checkNotFound = (error: any): boolean => { const ifNotFound = error instanceof NotFoundException; @@ -41,24 +40,39 @@ export const useReader: UseReaderHook = args => { }; const scanWithCropOnce = (reader: BrowserMultiFormatReader): Promise => { - const cropWidth = videoRef.current!.videoWidth * scale; + const element = document.getElementById("canvas-middle-middle")!; + + const cropWidth = element.clientWidth; + const cropHeight = element.clientHeight; + const captureCanvas = reader.createCaptureCanvas(videoRef.current!); - captureCanvas.width = cropWidth; - captureCanvas.height = cropWidth; + + const aspectRatioWidth = videoRef.current!.clientWidth / videoRef.current!.clientHeight; + const widthHeigher = videoRef.current!.videoWidth > videoRef.current!.videoHeight; + + let videoCropWidth = (cropWidth / videoRef.current!.clientWidth) * videoRef.current!.videoWidth; + let videoCropHeight = (cropHeight / videoRef.current!.clientHeight) * videoRef.current!.videoHeight; + captureCanvas.width = videoCropWidth; + captureCanvas.height = videoCropWidth; + if (widthHeigher) { + videoCropWidth = videoCropWidth / aspectRatioWidth; + } else { + videoCropHeight = videoCropWidth; + } const loop = (resolve: (value: Result) => void, reject: (reason?: Error) => void): void => { try { - const canvasContext = captureCanvas.getContext("2d"); + const canvasContext = captureCanvas.getContext("2d", { willReadFrequently: true }); if (canvasContext !== null) { canvasContext.drawImage( videoRef.current!, - (videoRef.current!.videoWidth * (1 - scale)) / 2, - (videoRef.current!.videoHeight - cropWidth) / 2, - cropWidth, - cropWidth, + (videoRef.current!.videoWidth - videoCropWidth) / 2, + (videoRef.current!.videoHeight - videoCropHeight) / 2, + videoCropWidth, + videoCropHeight, 0, 0, - captureCanvas.width, - captureCanvas.width + videoCropWidth, + videoCropHeight ); const luminanceSource = new HTMLCanvasElementLuminanceSource(captureCanvas); const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource)); @@ -67,7 +81,7 @@ export const useReader: UseReaderHook = args => { } } catch (error) { if (checkNotFound(error)) { - setTimeout(() => loop(resolve, reject), reader.timeBetweenDecodingAttempts); + setTimeout(() => loop(resolve, reject), 50); } else { reject(error); } diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/ui/BarcodeScanner.scss b/packages/pluggableWidgets/barcode-scanner-web/src/ui/BarcodeScanner.scss index 9ef3cf3580..a7d017b7d7 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/ui/BarcodeScanner.scss +++ b/packages/pluggableWidgets/barcode-scanner-web/src/ui/BarcodeScanner.scss @@ -34,7 +34,7 @@ .canvas-left { flex: 0; - flex-basis: 30%; + flex-basis: 33.333%; } $screen-md: 768px; @@ -42,7 +42,7 @@ $screen-xl: 1200px; .canvas-middle { flex: 0; - flex-basis: 40%; + flex-basis: 33.333%; display: flex; flex-direction: column; @@ -93,7 +93,7 @@ .canvas-right { flex: 0; - flex-basis: 30%; + flex-basis: 33.333%; } } } From e7b239fa6108ca8a48c7e470a0de20c4b2b1504a Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Wed, 15 May 2024 11:23:17 +0200 Subject: [PATCH 11/16] fix: prefer higher camera quality, clean up --- .../src/hooks/useReader.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index 153418060b..2a3a85a96d 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -16,8 +16,8 @@ const mediaStreamConstraints: MediaStreamConstraints = { audio: false, video: { facingMode: "environment", - width: { min: 1280, ideal: 1920, max: 2560 }, - height: { min: 720, ideal: 1080, max: 1440 } + width: { min: 1280, ideal: 2560, max: 2560 }, + height: { min: 720, ideal: 1440, max: 1440 } } }; @@ -42,23 +42,22 @@ export const useReader: UseReaderHook = args => { const scanWithCropOnce = (reader: BrowserMultiFormatReader): Promise => { const element = document.getElementById("canvas-middle-middle")!; - const cropWidth = element.clientWidth; - const cropHeight = element.clientHeight; - - const captureCanvas = reader.createCaptureCanvas(videoRef.current!); - const aspectRatioWidth = videoRef.current!.clientWidth / videoRef.current!.clientHeight; const widthHeigher = videoRef.current!.videoWidth > videoRef.current!.videoHeight; - let videoCropWidth = (cropWidth / videoRef.current!.clientWidth) * videoRef.current!.videoWidth; - let videoCropHeight = (cropHeight / videoRef.current!.clientHeight) * videoRef.current!.videoHeight; + let videoCropWidth = (element.clientWidth / videoRef.current!.clientWidth) * videoRef.current!.videoWidth; + let videoCropHeight = (element.clientHeight / videoRef.current!.clientHeight) * videoRef.current!.videoHeight; + + const captureCanvas = reader.createCaptureCanvas(videoRef.current!); captureCanvas.width = videoCropWidth; captureCanvas.height = videoCropWidth; + if (widthHeigher) { videoCropWidth = videoCropWidth / aspectRatioWidth; } else { videoCropHeight = videoCropWidth; } + const loop = (resolve: (value: Result) => void, reject: (reason?: Error) => void): void => { try { const canvasContext = captureCanvas.getContext("2d", { willReadFrequently: true }); @@ -113,13 +112,11 @@ export const useReader: UseReaderHook = args => { } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); const reader = new BrowserMultiFormatReader(hints, 500); - const stop = (): void => { stopped.current = true; reader.stopAsyncDecode(); reader.reset(); }; - const start = async (): Promise => { let stream; try { From d25bb0cbbb922fbbf7910ff5a1bfc83ca84a40ab Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Wed, 15 May 2024 14:33:56 +0200 Subject: [PATCH 12/16] fix: update snapshot --- .../__tests__/__snapshots__/BarcodeScanner.spec.tsx.snap | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/__snapshots__/BarcodeScanner.spec.tsx.snap b/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/__snapshots__/BarcodeScanner.spec.tsx.snap index 43be01eeef..a89dbcdc4c 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/__snapshots__/BarcodeScanner.spec.tsx.snap +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/__tests__/__snapshots__/BarcodeScanner.spec.tsx.snap @@ -43,6 +43,7 @@ exports[`Barcode scanner renders video and overlay correctly 1`] = ` />
Date: Wed, 15 May 2024 14:44:31 +0200 Subject: [PATCH 13/16] fix: update barcode scan library --- .../pluggableWidgets/barcode-scanner-web/package.json | 2 +- .../barcode-scanner-web/src/hooks/useReader.ts | 1 + pnpm-lock.yaml | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/package.json b/packages/pluggableWidgets/barcode-scanner-web/package.json index 989587c847..60ebcb29a1 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/package.json +++ b/packages/pluggableWidgets/barcode-scanner-web/package.json @@ -52,7 +52,7 @@ "@rollup/plugin-replace": "^2.4.2" }, "dependencies": { - "@zxing/library": "~0.20.0", + "@zxing/library": "~0.21.0", "classnames": "^2.3.2" } } diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index 2a3a85a96d..5b479dc073 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -111,6 +111,7 @@ export const useReader: UseReaderHook = args => { formats = args.barcodeFormats!.map(val => BarcodeFormat[val.barcodeFormat]); } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); + hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true); const reader = new BrowserMultiFormatReader(hints, 500); const stop = (): void => { stopped.current = true; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 363863c14f..15ed15645f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -665,8 +665,8 @@ importers: packages/pluggableWidgets/barcode-scanner-web: dependencies: '@zxing/library': - specifier: ~0.20.0 - version: 0.20.0 + specifier: ~0.21.0 + version: 0.21.0 classnames: specifier: ^2.3.2 version: 2.3.2 @@ -6414,8 +6414,8 @@ packages: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} dev: true - /@zxing/library@0.20.0: - resolution: {integrity: sha512-6Ev6rcqVjMakZFIDvbUf0dtpPGeZMTfyxYg4HkVWioWeN7cRcnUWT3bU6sdohc82O1nPXcjq6WiGfXX2Pnit6A==} + /@zxing/library@0.21.0: + resolution: {integrity: sha512-2+DFYM6NLl+ZXXUbDOkmVn4TAAOgTniEx5MJD2kStujcxSl6j9CfAgIT8DcsBYIlT5DW7oeiShEzWZjpL0hNOw==} engines: {node: '>= 10.4.0'} dependencies: ts-custom-error: 3.3.1 From bf62803ba96bcfa9e6cbff715080f8a5fa906237 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Thu, 30 May 2024 13:38:52 +0200 Subject: [PATCH 14/16] fix: fix aspect ratio for landscape mode, take out loop const in const --- .../src/hooks/useReader.ts | 96 ++++++++++--------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index 5b479dc073..d48664cf55 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -34,59 +34,66 @@ export const useReader: UseReaderHook = args => { const onSuccess = useEventCallback(args.onSuccess); const onError = useEventCallback(args.onError); const stopped = useRef(false); + const reader = useRef(); const checkNotFound = (error: any): boolean => { const ifNotFound = error instanceof NotFoundException; return ifNotFound && !stopped.current; }; + const loop = ( + resolve: (value: Result) => void, + reject: (reason?: Error) => void, + captureCanvas: HTMLCanvasElement, + videoCropWidth: number, + videoCropHeight: number + ): void => { + try { + const canvasContext = captureCanvas.getContext("2d", { willReadFrequently: true }); + if (canvasContext !== null) { + canvasContext.drawImage( + videoRef.current!, + (videoRef.current!.videoWidth - videoCropWidth) / 2, + (videoRef.current!.videoHeight - videoCropHeight) / 2, + videoCropWidth, + videoCropHeight, + 0, + 0, + videoCropWidth, + videoCropHeight + ); + const luminanceSource = new HTMLCanvasElementLuminanceSource(captureCanvas); + const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource)); + const result = reader.current!.decodeBitmap(binaryBitmap); + resolve(result); + } + } catch (error) { + if (checkNotFound(error)) { + setTimeout(() => loop(resolve, reject, captureCanvas, videoCropWidth, videoCropHeight), 50); + } else { + reject(error); + } + } + }; + const scanWithCropOnce = (reader: BrowserMultiFormatReader): Promise => { const element = document.getElementById("canvas-middle-middle")!; - const aspectRatioWidth = videoRef.current!.clientWidth / videoRef.current!.clientHeight; - const widthHeigher = videoRef.current!.videoWidth > videoRef.current!.videoHeight; - + const aspectRatioClient = videoRef.current!.clientWidth / videoRef.current!.clientHeight; + const aspectRatioVideo = videoRef.current!.videoWidth / videoRef.current!.videoHeight; let videoCropWidth = (element.clientWidth / videoRef.current!.clientWidth) * videoRef.current!.videoWidth; let videoCropHeight = (element.clientHeight / videoRef.current!.clientHeight) * videoRef.current!.videoHeight; - const captureCanvas = reader.createCaptureCanvas(videoRef.current!); - captureCanvas.width = videoCropWidth; - captureCanvas.height = videoCropWidth; - - if (widthHeigher) { - videoCropWidth = videoCropWidth / aspectRatioWidth; - } else { + if (aspectRatioVideo < aspectRatioClient) { videoCropHeight = videoCropWidth; + } else { + videoCropWidth = videoCropHeight; } - const loop = (resolve: (value: Result) => void, reject: (reason?: Error) => void): void => { - try { - const canvasContext = captureCanvas.getContext("2d", { willReadFrequently: true }); - if (canvasContext !== null) { - canvasContext.drawImage( - videoRef.current!, - (videoRef.current!.videoWidth - videoCropWidth) / 2, - (videoRef.current!.videoHeight - videoCropHeight) / 2, - videoCropWidth, - videoCropHeight, - 0, - 0, - videoCropWidth, - videoCropHeight - ); - const luminanceSource = new HTMLCanvasElementLuminanceSource(captureCanvas); - const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource)); - const result = reader.decodeBitmap(binaryBitmap); - resolve(result); - } - } catch (error) { - if (checkNotFound(error)) { - setTimeout(() => loop(resolve, reject), 50); - } else { - reject(error); - } - } - }; - return new Promise(loop); + const captureCanvas = reader.createCaptureCanvas(videoRef.current!); + captureCanvas.width = videoCropWidth; + captureCanvas.height = videoCropHeight; + + return new Promise((resolve, reject) => loop(resolve, reject, captureCanvas, videoCropWidth, videoCropHeight)); }; useEffect(() => { @@ -112,11 +119,12 @@ export const useReader: UseReaderHook = args => { } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true); - const reader = new BrowserMultiFormatReader(hints, 500); + const newReader = new BrowserMultiFormatReader(hints, 500); + reader.current = newReader; const stop = (): void => { stopped.current = true; - reader.stopAsyncDecode(); - reader.reset(); + newReader.stopAsyncDecode(); + newReader.reset(); }; const start = async (): Promise => { let stream; @@ -129,9 +137,9 @@ export const useReader: UseReaderHook = args => { videoRef.current.autofocus = true; videoRef.current.playsInline = true; // Fix error in Safari await videoRef.current.play(); - result = await scanWithCropOnce(reader); + result = await scanWithCropOnce(newReader); } else { - result = await reader.decodeOnceFromStream(stream, videoRef.current); + result = await newReader.decodeOnceFromStream(stream, videoRef.current); } if (!stopped.current) { onSuccess(result.getText()); From d3f6a8cf98185ddcdf8d058fceccfd72d39b9f2b Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Fri, 31 May 2024 17:04:09 +0200 Subject: [PATCH 15/16] fix: use ref instead of getelementbyid, use less non-null enforcement --- .../src/components/BarcodeScanner.tsx | 25 ++++++++-- .../src/hooks/useReader.ts | 48 +++++++++++-------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index 1cfedb5705..d41ce924c6 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -1,4 +1,4 @@ -import { createElement, ReactElement, ReactNode, useCallback, SyntheticEvent } from "react"; +import { createElement, ReactElement, ReactNode, useCallback, SyntheticEvent, useState } from "react"; import classNames from "classnames"; import { Alert } from "@mendix/widget-plugin-component-kit/Alert"; import { Dimensions, getDimensions } from "@mendix/widget-plugin-platform/utils/get-dimensions"; @@ -12,12 +12,14 @@ interface BarcodeScannerOverlayProps extends Dimensions { showMask: boolean; class: string; children?: ReactNode; + canvasMiddleMiddleRef?: (ref: HTMLDivElement | null) => void; } export function BarcodeScannerOverlay({ children, class: className, showMask, + canvasMiddleMiddleRef, ...dimensions }: BarcodeScannerOverlayProps): ReactElement { return ( @@ -29,7 +31,13 @@ export function BarcodeScannerOverlay({
-
+
{ + if (canvasMiddleMiddleRef !== undefined) canvasMiddleMiddleRef(ref); + }} + id={"canvas-middle-middle"} + className={classNames("canvas-middle-middle")} + >
@@ -62,12 +70,14 @@ export function BarcodeScanner({ ...dimensions }: BarcodeScannerProps): ReactElement | null { const [errorMessage, setError] = useCustomErrorMessage(); + const [canvasMiddleRef, setCanvasMiddleRef] = useState(); const videoRef = useReader({ onSuccess: onDetect, onError: setError, useCrop: showMask, barcodeFormats, - useAllFormats + useAllFormats, + canvasMiddleRef }); const supportsCameraAccess = typeof navigator?.mediaDevices?.getUserMedia === "function"; const onCanPlay = useCallback((event: SyntheticEvent) => { @@ -95,7 +105,14 @@ export function BarcodeScanner({ } return ( - + { + if (ref !== null) setCanvasMiddleRef(ref); + }} + {...dimensions} + > ); diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index d48664cf55..086205a870 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -27,6 +27,7 @@ type UseReaderHook = (args: { useCrop: boolean; barcodeFormats?: BarcodeFormatsType[]; useAllFormats: boolean; + canvasMiddleRef?: HTMLDivElement; }) => RefObject; export const useReader: UseReaderHook = args => { @@ -49,11 +50,11 @@ export const useReader: UseReaderHook = args => { ): void => { try { const canvasContext = captureCanvas.getContext("2d", { willReadFrequently: true }); - if (canvasContext !== null) { + if (canvasContext !== null && videoRef.current !== null && reader.current !== undefined) { canvasContext.drawImage( - videoRef.current!, - (videoRef.current!.videoWidth - videoCropWidth) / 2, - (videoRef.current!.videoHeight - videoCropHeight) / 2, + videoRef.current, + (videoRef.current.videoWidth - videoCropWidth) / 2, + (videoRef.current.videoHeight - videoCropHeight) / 2, videoCropWidth, videoCropHeight, 0, @@ -63,7 +64,7 @@ export const useReader: UseReaderHook = args => { ); const luminanceSource = new HTMLCanvasElementLuminanceSource(captureCanvas); const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource)); - const result = reader.current!.decodeBitmap(binaryBitmap); + const result = reader.current.decodeBitmap(binaryBitmap); resolve(result); } } catch (error) { @@ -76,24 +77,31 @@ export const useReader: UseReaderHook = args => { }; const scanWithCropOnce = (reader: BrowserMultiFormatReader): Promise => { - const element = document.getElementById("canvas-middle-middle")!; + if (videoRef.current && args.canvasMiddleRef) { + const aspectRatioClient = videoRef.current.clientWidth / videoRef.current.clientHeight; + const aspectRatioVideo = videoRef.current.videoWidth / videoRef.current.videoHeight; - const aspectRatioClient = videoRef.current!.clientWidth / videoRef.current!.clientHeight; - const aspectRatioVideo = videoRef.current!.videoWidth / videoRef.current!.videoHeight; - let videoCropWidth = (element.clientWidth / videoRef.current!.clientWidth) * videoRef.current!.videoWidth; - let videoCropHeight = (element.clientHeight / videoRef.current!.clientHeight) * videoRef.current!.videoHeight; + let videoCropWidth = + (args.canvasMiddleRef.clientWidth / videoRef.current.clientWidth) * videoRef.current.videoWidth; + let videoCropHeight = + (args.canvasMiddleRef.clientHeight / videoRef.current.clientHeight) * videoRef.current.videoHeight; - if (aspectRatioVideo < aspectRatioClient) { - videoCropHeight = videoCropWidth; - } else { - videoCropWidth = videoCropHeight; - } + if (aspectRatioVideo < aspectRatioClient) { + videoCropHeight = videoCropWidth; + } else { + videoCropWidth = videoCropHeight; + } - const captureCanvas = reader.createCaptureCanvas(videoRef.current!); - captureCanvas.width = videoCropWidth; - captureCanvas.height = videoCropHeight; + const captureCanvas = reader.createCaptureCanvas(videoRef.current); + captureCanvas.width = videoCropWidth; + captureCanvas.height = videoCropHeight; - return new Promise((resolve, reject) => loop(resolve, reject, captureCanvas, videoCropWidth, videoCropHeight)); + return new Promise((resolve, reject) => + loop(resolve, reject, captureCanvas, videoCropWidth, videoCropHeight) + ); + } else { + return Promise.reject(); + } }; useEffect(() => { @@ -115,7 +123,7 @@ export const useReader: UseReaderHook = args => { BarcodeFormat.PDF_417 ]; } else { - formats = args.barcodeFormats!.map(val => BarcodeFormat[val.barcodeFormat]); + if (args.barcodeFormats) formats = args.barcodeFormats.map(val => BarcodeFormat[val.barcodeFormat]); } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true); From 8cd46d99d4b78e962ef0c7140d2bfbaa7b6ddb21 Mon Sep 17 00:00:00 2001 From: "hedwig.doets" Date: Fri, 7 Jun 2024 15:42:30 +0200 Subject: [PATCH 16/16] fix: lint --- .../barcode-scanner-web/src/components/BarcodeScanner.tsx | 8 ++++++-- .../barcode-scanner-web/src/hooks/useReader.ts | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx index d41ce924c6..4d665c8933 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx +++ b/packages/pluggableWidgets/barcode-scanner-web/src/components/BarcodeScanner.tsx @@ -33,7 +33,9 @@ export function BarcodeScannerOverlay({
{ - if (canvasMiddleMiddleRef !== undefined) canvasMiddleMiddleRef(ref); + if (canvasMiddleMiddleRef !== undefined) { + canvasMiddleMiddleRef(ref); + } }} id={"canvas-middle-middle"} className={classNames("canvas-middle-middle")} @@ -109,7 +111,9 @@ export function BarcodeScanner({ class={className} showMask={showMask} canvasMiddleMiddleRef={ref => { - if (ref !== null) setCanvasMiddleRef(ref); + if (ref !== null) { + setCanvasMiddleRef(ref); + } }} {...dimensions} > diff --git a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts index 086205a870..771096028e 100644 --- a/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts +++ b/packages/pluggableWidgets/barcode-scanner-web/src/hooks/useReader.ts @@ -100,7 +100,7 @@ export const useReader: UseReaderHook = args => { loop(resolve, reject, captureCanvas, videoCropWidth, videoCropHeight) ); } else { - return Promise.reject(); + return Promise.reject(new Error("No video ref or no canvas ref found")); } }; @@ -123,7 +123,9 @@ export const useReader: UseReaderHook = args => { BarcodeFormat.PDF_417 ]; } else { - if (args.barcodeFormats) formats = args.barcodeFormats.map(val => BarcodeFormat[val.barcodeFormat]); + if (args.barcodeFormats) { + formats = args.barcodeFormats.map(val => BarcodeFormat[val.barcodeFormat]); + } } hints.set(DecodeHintType.POSSIBLE_FORMATS, formats); hints.set(DecodeHintType.ENABLE_CODE_39_EXTENDED_MODE, true);