diff --git a/apps/ExampleApp/app/navigators/AppNavigator.tsx b/apps/ExampleApp/app/navigators/AppNavigator.tsx index 1e355b3c..98405560 100644 --- a/apps/ExampleApp/app/navigators/AppNavigator.tsx +++ b/apps/ExampleApp/app/navigators/AppNavigator.tsx @@ -35,6 +35,7 @@ export type AppStackParamList = { ObjectDetection: Record DocumentScanner: Record TextRecognition: Record + BarcodeScanning: Record // IGNITE_GENERATOR_ANCHOR_APP_STACK_PARAM_LIST } @@ -63,6 +64,7 @@ const AppStack = observer(function AppStack() { + {/* IGNITE_GENERATOR_ANCHOR_APP_STACK_SCREENS */} ) diff --git a/apps/ExampleApp/app/screens/BarcodeScanningScreen.tsx b/apps/ExampleApp/app/screens/BarcodeScanningScreen.tsx new file mode 100644 index 00000000..caa18d4e --- /dev/null +++ b/apps/ExampleApp/app/screens/BarcodeScanningScreen.tsx @@ -0,0 +1,230 @@ +import React, { FC, useState, useEffect, useCallback } from "react" +import { observer } from "mobx-react-lite" +import { ViewStyle, View, ImageStyle, TextStyle, ScrollView, Pressable } from "react-native" +import { NativeStackScreenProps } from "@react-navigation/native-stack" +import { AppStackScreenProps } from "../navigators" +import { Text, Icon, ImageSelector, Screen } from "../components" +import { useTypedNavigation } from "../navigators/useTypedNavigation" + +import RNMLKitBarcodeScanningModule from "@infinitered/react-native-mlkit-barcode-scanning" +import type { BarcodeScannerResult } from "@infinitered/react-native-mlkit-barcode-scanning" +import { UseExampleImageStatus, SelectedImage } from "../utils/useExampleImage" + +type BarcodeScanningScreenProps = NativeStackScreenProps> + +function DebugOutput({ data }: { data: unknown }) { + const [expanded, setExpanded] = useState(false) + + return ( + + setExpanded(!expanded)} style={$debugHeader}> + {expanded ? "▼" : "▶"} Debug Output + + {expanded && ( + + + {JSON.stringify(data, null, 2)} + + + )} + + ) +} + +export const BarcodeScanningScreen: FC = observer( + function BarcodeScanningScreen() { + const navigation = useTypedNavigation<"BarcodeScanning">() + + const [image, setImage] = useState(null) + + const handleImageChange = useCallback((nextImage: SelectedImage) => { + setImage(nextImage) + }, []) + + const [result, setResult] = useState(null) + const [status, setStatus] = useState< + "init" | "noPermissions" | "done" | "error" | "loading" | UseExampleImageStatus + >("init") + + const onStatusChange = React.useCallback( + (status: "init" | "noPermissions" | "done" | "error" | "loading" | UseExampleImageStatus) => { + setStatus(status) + }, + [], + ) + + const [isScanning, setIsScanning] = useState(false) + + useEffect(() => { + const scanBarcode = async () => { + if (!image?.uri) return + setIsScanning(true) + try { + const scanResult = await RNMLKitBarcodeScanningModule.process(image.uri) + setResult(scanResult) + setStatus("done") + } catch (error) { + console.error("Error scanning barcode:", error) + setStatus("error") + } finally { + setIsScanning(false) + } + } + + scanBarcode().then(() => null) + }, [image]) + + const statusMessage = React.useMemo(() => { + if (!image && status !== "init") { + setStatus("init") + } + if (isScanning) { + return "Scanning for barcodes..." + } + switch (status) { + case "init": + return "Take a photo or select one from your camera roll" + case "noPermissions": + return "You need to grant camera permissions to take a photo" + case "takingPhoto": + return "Taking photo..." + case "selectingPhoto": + return "Selecting photo..." + case "done": + return result?.barcodes.length + ? `Found ${result.barcodes.length} barcode${result.barcodes.length > 1 ? "s" : ""}!` + : "No barcodes found" + case "error": + return "Error during scanning!" + case "loading": + return "Loading Example Images..." + default: + return "" + } + }, [result, image, status, isScanning]) + + const clearResults = useCallback(() => { + setResult(null) + }, []) + + return ( + + + navigation.navigate("Home")} style={$backIcon} /> + + Take a photo of a barcode and scan it. + + + + {result && result.barcodes.length > 0 && ( + <> + + Scanned Barcodes + {result.barcodes.map((barcode, index) => ( + + Format: {barcode.format} + Type: {barcode.valueType} + {barcode.displayValue && ( + Value: {barcode.displayValue} + )} + {barcode.rawValue && barcode.rawValue !== barcode.displayValue && ( + Raw: {barcode.rawValue} + )} + + ))} + + + + )} + + ) + }, +) + +const $root: ViewStyle = { + flex: 1, + padding: 16, + display: "flex", + flexDirection: "column", +} +const $backIcon: ImageStyle = { marginVertical: 8 } + +const $description: TextStyle = { + marginVertical: 8, + color: "rgba(0,0,0,0.6)", +} + +const $resultContainer: ViewStyle = { + width: "100%", + borderWidth: 1, + borderColor: "rgba(0,0,0,0.2)", + borderRadius: 8, + padding: 12, + marginVertical: 16, +} + +const $barcodeItem: ViewStyle = { + marginTop: 12, + paddingTop: 12, + borderTopWidth: 1, + borderTopColor: "rgba(0,0,0,0.1)", +} + +const $barcodeLabel: TextStyle = { + fontSize: 12, + color: "rgba(0,0,0,0.6)", + marginBottom: 4, +} + +const $barcodeValue: TextStyle = { + fontSize: 16, + fontWeight: "600", + marginTop: 4, +} + +const $barcodeRaw: TextStyle = { + fontSize: 12, + fontFamily: "monospace", + marginTop: 4, + color: "rgba(0,0,0,0.5)", +} + +const $debugContainer: ViewStyle = { + width: "100%", + borderWidth: 1, + borderColor: "rgba(0,0,0,0.2)", + borderRadius: 8, + marginBottom: 24, + overflow: "hidden", +} + +const $debugHeader: ViewStyle = { + padding: 12, + backgroundColor: "rgba(0,0,0,0.05)", +} + +const $debugTitle: TextStyle = { + fontWeight: "bold", +} + +const $debugContent: ViewStyle = { + maxHeight: 300, + padding: 12, + backgroundColor: "rgba(0,0,0,0.02)", +} + +const $debugText: TextStyle = { + fontFamily: "monospace", + fontSize: 12, +} diff --git a/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts b/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts index 331dc0f2..eb4ca8f5 100644 --- a/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts +++ b/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts @@ -53,5 +53,11 @@ export const DEMO_LIST: DemoInfo[] = [ screen: "TextRecognition", image: TEXT_RECOGNITION, }, + { + title: "Barcode Scanning", + description: "Scan barcodes and QR codes from images", + screen: "BarcodeScanning", + image: FACE_HOLDER, + }, ...PLATFORM_SPECIFIC_DEMOS, ] diff --git a/apps/ExampleApp/app/screens/index.ts b/apps/ExampleApp/app/screens/index.ts index 52f2fb39..2f8d0276 100644 --- a/apps/ExampleApp/app/screens/index.ts +++ b/apps/ExampleApp/app/screens/index.ts @@ -7,4 +7,5 @@ export * from "./ImageLabelingScreen" export * from "./DocumentScannerScreen" export { BOX_COLORS } from "./FaceDetectionScreen" export * from "./ObjectDetectionScreen" -export * from "./TextRecognitionScreen" \ No newline at end of file +export * from "./TextRecognitionScreen" +export * from "./BarcodeScanningScreen" \ No newline at end of file diff --git a/apps/ExampleApp/package.json b/apps/ExampleApp/package.json index 0783ef09..a8688736 100644 --- a/apps/ExampleApp/package.json +++ b/apps/ExampleApp/package.json @@ -32,6 +32,7 @@ "dependencies": { "@expo-google-fonts/space-grotesk": "^0.2.2", "@expo/metro-runtime": "~6.1.2", + "@infinitered/react-native-mlkit-barcode-scanning": "workspace:^5.0.0", "@infinitered/react-native-mlkit-document-scanner": "workspace:^5.0.0", "@infinitered/react-native-mlkit-face-detection": "workspace:^5.0.0", "@infinitered/react-native-mlkit-image-labeling": "workspace:^5.0.0", diff --git a/docs/barcode-scanning/category.json b/docs/barcode-scanning/category.json new file mode 100644 index 00000000..333c8e38 --- /dev/null +++ b/docs/barcode-scanning/category.json @@ -0,0 +1,4 @@ +{ + "label": "Barcode Scanner", + "position": 100 + } \ No newline at end of file diff --git a/docs/barcode-scanning/index.md b/docs/barcode-scanning/index.md new file mode 100644 index 00000000..436bc90d --- /dev/null +++ b/docs/barcode-scanning/index.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 1 +--- + +# Barcode Scanner + +<> \ No newline at end of file diff --git a/modules/react-native-mlkit-barcode-scanning/.eslintrc.js b/modules/react-native-mlkit-barcode-scanning/.eslintrc.js new file mode 100644 index 00000000..0dc2ae2a --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + root: true, + extends: ["universe/native", "universe/web"], + ignorePatterns: ["build"], + rules: { + "@typescript-eslint/array-type": "off", + }, +}; diff --git a/modules/react-native-mlkit-barcode-scanning/.gitignore b/modules/react-native-mlkit-barcode-scanning/.gitignore new file mode 100644 index 00000000..e64b91c9 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/.gitignore @@ -0,0 +1,57 @@ +# OSX +# +.DS_Store + +# VSCode +.vscode/ +jsconfig.json + +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate +project.xcworkspace + +# Android/IJ +# +.classpath +.cxx +.gradle +.idea +.project +.settings +local.properties +android.iml +android/app/libs +android/keystores/debug.keystore + +# Cocoapods +# +example/ios/Pods + +# Ruby +example/vendor/ + +# node.js +# +node_modules/ +npm-debug.log +yarn-debug.log +yarn-error.log + +# Expo +.expo/* diff --git a/modules/react-native-mlkit-barcode-scanning/.npmignore b/modules/react-native-mlkit-barcode-scanning/.npmignore new file mode 100644 index 00000000..fa6abe7c --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/.npmignore @@ -0,0 +1,11 @@ +# Exclude all top-level hidden directories by convention +/.*/ + +__mocks__ +__tests__ + +/babel.config.js +/android/src/androidTest/ +/android/src/test/ +/android/build/ +/example/ diff --git a/modules/react-native-mlkit-barcode-scanning/.yarnrc.yml b/modules/react-native-mlkit-barcode-scanning/.yarnrc.yml new file mode 100644 index 00000000..3186f3f0 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/modules/react-native-mlkit-barcode-scanning/README.md b/modules/react-native-mlkit-barcode-scanning/README.md new file mode 100644 index 00000000..8ec2c6e0 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/README.md @@ -0,0 +1,5 @@ +# @infinitered/react-native-mlkit-barcode-scanning + +Check the friendly docs here! 📖](https://docs.infinite.red/react-native-mlkit/barcode-scanning) + +## Getting Started with react-native-mlkit-barcode-scanning diff --git a/modules/react-native-mlkit-barcode-scanning/android/build.gradle b/modules/react-native-mlkit-barcode-scanning/android/build.gradle new file mode 100644 index 00000000..4198bf94 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/android/build.gradle @@ -0,0 +1,54 @@ +apply plugin: 'com.android.library' + +group = 'expo.modules.mlkitbarcodescanning' +version = '0.7.6' + +def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle") +apply from: expoModulesCorePlugin +applyKotlinExpoModulesCorePlugin() +useCoreDependencies() +useExpoPublishing() + +// If you want to use the managed Android SDK versions from expo-modules-core, set this to true. +// The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code. +// Most of the time, you may like to manage the Android SDK versions yourself. +def useManagedAndroidSdkVersions = false +if (useManagedAndroidSdkVersions) { + useDefaultAndroidSdkVersions() +} else { + buildscript { + // Simple helper that allows the root project to override versions declared by this library. + ext.safeExtGet = { prop, fallback -> + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback + } + } + project.android { + compileSdkVersion safeExtGet("compileSdkVersion", 36) + defaultConfig { + minSdkVersion safeExtGet("minSdkVersion", 24) + targetSdkVersion safeExtGet("targetSdkVersion", 36) + } + } +} + +android { + namespace "expo.modules.mlkitbarcodescanning" + defaultConfig { + versionCode 1 + versionName "0.7.6" + } + lintOptions { + abortOnError false + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation project(':expo-modules-core') + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}" + implementation 'com.google.mlkit:barcode-scanning:17.3.0' + implementation project(path: ':infinitered-react-native-mlkit-core') +} diff --git a/modules/react-native-mlkit-barcode-scanning/android/src/main/AndroidManifest.xml b/modules/react-native-mlkit-barcode-scanning/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..bdae66c8 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/modules/react-native-mlkit-barcode-scanning/android/src/main/java/expo/modules/mlkitbarcodescanning/RNMLKitBarcodeScanningModule.kt b/modules/react-native-mlkit-barcode-scanning/android/src/main/java/expo/modules/mlkitbarcodescanning/RNMLKitBarcodeScanningModule.kt new file mode 100644 index 00000000..844a7c4e --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/android/src/main/java/expo/modules/mlkitbarcodescanning/RNMLKitBarcodeScanningModule.kt @@ -0,0 +1,50 @@ +package red.infinite.reactnativemlkit + +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition +import java.net.URL + +class RNMLKitBarcodeScanningModule : Module() { + // Each module class must implement the definition function. The definition consists of components + // that describes the module's functionality and behavior. + // See https://docs.expo.dev/modules/module-api for more details about available components. + override fun definition() = ModuleDefinition { + // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument. + // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity. + // The module will be accessible from `requireNativeModule('RNMLKitBarcodeScanning')` in JavaScript. + Name("RNMLKitBarcodeScanning") + + // Defines constant property on the module. + Constant("PI") { + Math.PI + } + + // Defines event names that the module can send to JavaScript. + Events("onChange") + + // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread. + Function("hello") { + "Hello world! 👋" + } + + // Defines a JavaScript function that always returns a Promise and whose native code + // is by default dispatched on the different thread than the JavaScript runtime runs on. + AsyncFunction("setValueAsync") { value: String -> + // Send an event to JavaScript. + sendEvent("onChange", mapOf( + "value" to value + )) + } + + // Enables the module to be used as a native view. Definition components that are accepted as part of + // the view definition: Prop, Events. + View(RNMLKitBarcodeScanningView::class) { + // Defines a setter for the `url` prop. + Prop("url") { view: RNMLKitBarcodeScanningView, url: URL -> + view.webView.loadUrl(url.toString()) + } + // Defines an event that the view can send to JavaScript. + Events("onLoad") + } + } +} diff --git a/modules/react-native-mlkit-barcode-scanning/babel.config.js b/modules/react-native-mlkit-barcode-scanning/babel.config.js new file mode 100644 index 00000000..d089e047 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/babel.config.js @@ -0,0 +1,5 @@ +// babel.config.js +module.exports = { + presets: ["module:@react-native/babel-preset"], + plugins: [["@babel/plugin-transform-private-methods", { loose: true }]], +}; diff --git a/modules/react-native-mlkit-barcode-scanning/expo-module.config.json b/modules/react-native-mlkit-barcode-scanning/expo-module.config.json new file mode 100644 index 00000000..fae1de7c --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/expo-module.config.json @@ -0,0 +1,9 @@ +{ + "platforms": ["ios", "android", "web"], + "apple": { + "modules": ["RNMLKitBarcodeScanningModule"] + }, + "android": { + "modules": ["red.infinite.reactnativemlkit.RNMLKitBarcodeScanningModule"] + } +} diff --git a/modules/react-native-mlkit-barcode-scanning/index.ts b/modules/react-native-mlkit-barcode-scanning/index.ts new file mode 100644 index 00000000..a8269f6f --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/index.ts @@ -0,0 +1,4 @@ +// Reexport the native module. On web, it will be resolved to RNMLKitBarcodeScanningModule.web.ts +// and on native platforms to RNMLKitBarcodeScanningModule.ts +export { default } from "./src/RNMLKitBarcodeScanningModule"; +export * from "./src/RNMLKitBarcodeScanning.types"; diff --git a/modules/react-native-mlkit-barcode-scanning/ios/RNMLKitBarcodeScanning.podspec b/modules/react-native-mlkit-barcode-scanning/ios/RNMLKitBarcodeScanning.podspec new file mode 100644 index 00000000..7895dfe5 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/ios/RNMLKitBarcodeScanning.podspec @@ -0,0 +1,29 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'RNMLKitBarcodeScanning' + s.version = package['version'] + s.summary = package['description'] + s.description = package['description'] + s.license = package['license'] + s.author = package['author'] + s.homepage = package['homepage'] + s.platform = :ios, '15.1' + s.swift_version = '5.4' + s.source = { git: 'http://github.com/infinitered/react-native-mlkit' } + s.static_framework = true + + s.dependency 'GoogleMLKit/BarcodeScanning' + s.dependency 'ExpoModulesCore' + s.dependency 'RNMLKitCore' + + # Swift/Objective-C compatibility + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + 'SWIFT_COMPILATION_MODE' => 'wholemodule' + } + + s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}" +end diff --git a/modules/react-native-mlkit-barcode-scanning/ios/RNMLKitBarcodeScanningModule.swift b/modules/react-native-mlkit-barcode-scanning/ios/RNMLKitBarcodeScanningModule.swift new file mode 100644 index 00000000..2d756485 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/ios/RNMLKitBarcodeScanningModule.swift @@ -0,0 +1,48 @@ +import ExpoModulesCore + +public class RNMLKitBarcodeScanningModule: Module { + // Each module class must implement the definition function. The definition consists of components + // that describes the module's functionality and behavior. + // See https://docs.expo.dev/modules/module-api for more details about available components. + public func definition() -> ModuleDefinition { + // Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument. + // Can be inferred from module's class name, but it's recommended to set it explicitly for clarity. + // The module will be accessible from `requireNativeModule('RNMLKitBarcodeScanning')` in JavaScript. + Name("RNMLKitBarcodeScanning") + + // Defines constant property on the module. + Constant("PI") { + Double.pi + } + + // Defines event names that the module can send to JavaScript. + Events("onChange") + + // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread. + Function("hello") { + return "Hello world! 👋" + } + + // Defines a JavaScript function that always returns a Promise and whose native code + // is by default dispatched on the different thread than the JavaScript runtime runs on. + AsyncFunction("setValueAsync") { (value: String) in + // Send an event to JavaScript. + self.sendEvent("onChange", [ + "value": value + ]) + } + + // Enables the module to be used as a native view. Definition components that are accepted as part of the + // view definition: Prop, Events. + View(RNMLKitBarcodeScanningView.self) { + // Defines a setter for the `url` prop. + Prop("url") { (view: RNMLKitBarcodeScanningView, url: URL) in + if view.webView.url != url { + view.webView.load(URLRequest(url: url)) + } + } + + Events("onLoad") + } + } +} diff --git a/modules/react-native-mlkit-barcode-scanning/package.json b/modules/react-native-mlkit-barcode-scanning/package.json new file mode 100644 index 00000000..9a3c699c --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/package.json @@ -0,0 +1,47 @@ +{ + "name": "@infinitered/react-native-mlkit-barcode-scanning", + "version": "5.0.0", + "description": "MLKit Barcode Scanning for React Native with Expo", + "main": "build/index.js", + "types": "build/index.d.ts", + "scripts": { + "build": "expo-module build", + "ci:build": "tsc", + "clean": "expo-module clean", + "lint": "expo-module lint", + "test": "../../scripts/test-module.sh", + "prepublishOnly": "expo-module prepublishOnly", + "expo-module": "expo-module" + }, + "keywords": [ + "react-native", + "expo", + "react-native-mlkit-barcode-scanning", + "RNMLKitBarcodeScanning" + ], + "repository": "https://www.github.com/infinitered/react-native-mlkit", + "bugs": { + "url": "https://www.github.com/infinitered/react-native-mlkit/issues" + }, + "author": "Tyler Williams (https://www.github.com/coolsoftwaretyler)", + "license": "MIT", + "homepage": "https://docs.infinite.red/react-native-mlkit/barcode-scanning", + "dependencies": { + "@infinitered/react-native-mlkit-core": "5.0.0" + }, + "devDependencies": { + "@types/react": "~19.1.10", + "expo-module-scripts": "^3.4.1", + "expo-modules-core": "~3.0.25" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + }, + "expo": { + "autolinking": { + "nativeModulesDir": "../../modules" + } + } +} diff --git a/modules/react-native-mlkit-barcode-scanning/src/RNMLKitBarcodeScanning.types.ts b/modules/react-native-mlkit-barcode-scanning/src/RNMLKitBarcodeScanning.types.ts new file mode 100644 index 00000000..213569be --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/src/RNMLKitBarcodeScanning.types.ts @@ -0,0 +1,202 @@ +import { RNMLKitRect, RNMLKitPoint } from "@infinitered/react-native-mlkit-core" + +export enum BarcodeFormat { + ALL = "all", + code128 = "code128", + code39 = "code39", + code93 = "code93", + codaBar = "codaBar", + dataMatrix = "dataMatrix", + EAN13 = "EAN13", + EAN8 = "EAN8", + ITF = "ITF", + qrCode = "qrCode", + UPCA = "UPCA", + UPCE = "UPCE", + PDF417 = "PDF417", + aztec = "AZTEC", +} + +/** + * Possible value types. Taken from Android API reference: + * https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode.BarcodeValueType?hl=en + */ +export enum BarcodeValueType { + UNKNOWN = "UNKNOWN", + CONTACT_INFO = "CONTACT_INFO", + EMAIL = "EMAIL", + ISBN = "ISBN", + PHONE = "PHONE", + PRODUCT = "PRODUCT", + SMS = "SMS", + TEXT = "TEXT", + URL = "URL", + WIFI = "WIFI", + GEO = "GEO", + DRIVER_LICENSE = "DRIVER_LICENSE", + CALENDAR_EVENT = "CALENDAR_EVENT", +} + +export interface BarcodeScannerOptions { + formats: BarcodeFormat[] +} + +export interface BarcodeScannerResult { + barcodes: Barcode[] +} + +/** + * RawData is a byte[] in Android, and Data in iOS: + * https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode#getRawValue() + * https://developers.google.com/ml-kit/reference/swift/mlkitbarcodescanning/api/reference/Classes/Barcode + * https://developer.apple.com/documentation/foundation/data + */ +export type BarcodeRawData = Uint8Array[]; + +/** + * Possible email types. Taken from Android API reference: + * https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode.Email.FormatType + */ +export enum BarcodeEmailType { + HOME = "HOME", + WORK = "WORK", + UNKNOWN = "UNKNOWN", +} + +export interface BarcodeEmail { + address?: string + body?: string + subject?: string + type: BarcodeEmailType +} + +/** + * Possible phone types. Taken from Android API reference: + * https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode.Phone.FormatType + */ +export enum BarcodePhoneType { + UNKNOWN = "UNKNOWN", + WORK = "WORK", + HOME = "HOME", + FAX = "FAX", + MOBILE = "MOBILE" +} + +export interface BarcodePhone { + number?: string + type: BarcodePhoneType +} + +export interface BarcodeSMS { + message?: string + phoneNumber?: string +} + +export interface BarcodeURLBookmark { + title?: string + url?: string +} + +/** + * https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode.WiFi.EncryptionType + */ +export enum BarcodeWifiEncryptionType { + OPEN = "OPEN", + WPA = "WPA", + WEP = "WEP" +} + +export interface BarcodeWifi { + ssid?: string + password?: string + type: BarcodeWifiEncryptionType +} + +export interface BarcodeGeoPoint { + latitude: number + longitude: number +} + +/** + * https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode.Address.AddressType + */ +export enum BarcodeAddressType { + UNKNOWN = "UNKNOWN", + WORK = "WORK", + HOME = "HOME", +} + +export interface BarcodeAddress { + addressLines?: Array + type: BarcodeAddressType +} + +export interface BarcodePersonName { + formattedName?: string + first?: string + last?: string + middle?: string + prefix?: string + pronunciation?: string + suffix?: string +} + +export interface BarcodeContactInfo { + addresses?: Array + emails?: Array + name?: BarcodePersonName + phones?: Array + urls?: Array + jobTitle?: string + organization?: string +} + +export interface BarcodeCalendarEvent { + eventDescription?: string + location?: string + organizer?: string + status?: string + summary?: string + start?: number // We use an epoch millisecond time stamp to represent the Date field here + end?: number // We use an epoch millisecond time stamp to represent the Date field here +} + +/** + * DL for driver's license, ID for ID cards + */ +export type BarcodeDriverLicenseDocumentType = 'DL' | 'ID' + +export interface BarcodeDriverLicense { + firstName?: string + middleName?: string + lastName?: string + gender?: string + addressCity?: string + addressState?: string + addressStreet?: string + addressZip?: string + birthDate?: string + documentType?: BarcodeDriverLicenseDocumentType + expiryDate?: string + issuingDate?: string + issuingCountry?: string +} + +export interface Barcode { + frame: RNMLKitRect + rawValue?: string + rawData?: BarcodeRawData + displayValue?: string + format: BarcodeFormat + cornerPoints: RNMLKitPoint[] + valueType: BarcodeValueType + email?: BarcodeEmail + phone?: BarcodePhone + sms?: BarcodeSMS + url?: BarcodeURLBookmark + wifi?: BarcodeWifi + geoPoint?: BarcodeGeoPoint + contactInfo?: BarcodeContactInfo + calendarEvent?: BarcodeCalendarEvent + driverLicense?: BarcodeDriverLicense +} \ No newline at end of file diff --git a/modules/react-native-mlkit-barcode-scanning/src/RNMLKitBarcodeScanningModule.ts b/modules/react-native-mlkit-barcode-scanning/src/RNMLKitBarcodeScanningModule.ts new file mode 100644 index 00000000..281534be --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/src/RNMLKitBarcodeScanningModule.ts @@ -0,0 +1,10 @@ +import { NativeModule, requireNativeModule } from 'expo'; + +import { BarcodeScannerResult } from './RNMLKitBarcodeScanning.types'; + +declare class RNMLKitBarcodeScanningModule extends NativeModule { + process(imagePath: string): Promise; +} + +// This call loads the native module object from the JSI. +export default requireNativeModule('RNMLKitBarcodeScanning'); diff --git a/modules/react-native-mlkit-barcode-scanning/src/index.ts b/modules/react-native-mlkit-barcode-scanning/src/index.ts new file mode 100644 index 00000000..0feb259b --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/src/index.ts @@ -0,0 +1,2 @@ +export { default } from './RNMLKitBarcodeScanningModule'; +export * from './RNMLKitBarcodeScanning.types'; diff --git a/modules/react-native-mlkit-barcode-scanning/tsconfig.json b/modules/react-native-mlkit-barcode-scanning/tsconfig.json new file mode 100644 index 00000000..af4318d3 --- /dev/null +++ b/modules/react-native-mlkit-barcode-scanning/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@infinitered/tsconfig/expo-module", + "compilerOptions": { + "outDir": "./build" + }, + "include": [ + "./src" + ], + "exclude": [ + "**/__mocks__/*", + "**/__tests__/*" + ] +} diff --git a/yarn.lock b/yarn.lock index 5ad0cde0..ac24eb14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4637,6 +4637,21 @@ __metadata: languageName: unknown linkType: soft +"@infinitered/react-native-mlkit-barcode-scanning@workspace:^5.0.0, @infinitered/react-native-mlkit-barcode-scanning@workspace:modules/react-native-mlkit-barcode-scanning": + version: 0.0.0-use.local + resolution: "@infinitered/react-native-mlkit-barcode-scanning@workspace:modules/react-native-mlkit-barcode-scanning" + dependencies: + "@infinitered/react-native-mlkit-core": 5.0.0 + "@types/react": ~19.1.10 + expo-module-scripts: ^3.4.1 + expo-modules-core: ~3.0.25 + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@infinitered/react-native-mlkit-core@5.0.0, @infinitered/react-native-mlkit-core@workspace:modules/react-native-mlkit-core": version: 0.0.0-use.local resolution: "@infinitered/react-native-mlkit-core@workspace:modules/react-native-mlkit-core" @@ -12036,6 +12051,7 @@ __metadata: "@babel/runtime": ^7.20.0 "@expo-google-fonts/space-grotesk": ^0.2.2 "@expo/metro-runtime": ~6.1.2 + "@infinitered/react-native-mlkit-barcode-scanning": "workspace:^5.0.0" "@infinitered/react-native-mlkit-document-scanner": "workspace:^5.0.0" "@infinitered/react-native-mlkit-face-detection": "workspace:^5.0.0" "@infinitered/react-native-mlkit-image-labeling": "workspace:^5.0.0"