Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8122141
wip: copied module structure over, started working on types
coolsoftwaretyler Dec 4, 2025
e4e65a3
fix: scaffold with create expo module, add placeholder doc
coolsoftwaretyler Dec 5, 2025
3dcaf71
wip: start adding more types to barcode interface
coolsoftwaretyler Dec 5, 2025
b95acd9
feat: finish barcode types on TS side
coolsoftwaretyler Dec 5, 2025
0f12bdf
fix: add other root level files to module, use core for types
coolsoftwaretyler Dec 5, 2025
449103a
chore: remove unused Expo files
coolsoftwaretyler Dec 5, 2025
4df6399
docs: clean up readme
coolsoftwaretyler Dec 5, 2025
10cf3c4
fix: add gradle dependencies for expo and mlkit core
coolsoftwaretyler Dec 5, 2025
f0c5159
fix: add podspec dependencies for MLKit and MLKitCore
coolsoftwaretyler Dec 6, 2025
84f02d6
refactor: rename to RNMLKitBarcodeScanning
coolsoftwaretyler Dec 6, 2025
718fbd0
fix: some metadata in podspec and module config
coolsoftwaretyler Dec 6, 2025
c9629f1
fix: readme formatting
coolsoftwaretyler Dec 6, 2025
c4465ef
refactor: rename files to RNMLKit
coolsoftwaretyler Dec 6, 2025
8dc6687
chore: remove unused view files
coolsoftwaretyler Dec 6, 2025
9cd87bb
fix: use the correct google dep for ios
coolsoftwaretyler Dec 6, 2025
f028c22
fix: nclude correct barcode-scanning in gradle
coolsoftwaretyler Dec 6, 2025
e2ad8b8
feat: add barcode scanning module to ex app deps
coolsoftwaretyler Dec 12, 2025
af9a663
feat: add barcode scanning demo screen
coolsoftwaretyler Dec 12, 2025
46b17be
fix: index file not found
coolsoftwaretyler Dec 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/ExampleApp/app/navigators/AppNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export type AppStackParamList = {
ObjectDetection: Record<string, never>
DocumentScanner: Record<string, never>
TextRecognition: Record<string, never>
BarcodeScanning: Record<string, never>
// IGNITE_GENERATOR_ANCHOR_APP_STACK_PARAM_LIST
}

Expand Down Expand Up @@ -63,6 +64,7 @@ const AppStack = observer(function AppStack() {
<Stack.Screen name="ObjectDetection" component={Screens.ObjectDetectionScreen} />
<Stack.Screen name="DocumentScanner" component={Screens.DocumentScannerScreen} />
<Stack.Screen name="TextRecognition" component={Screens.TextRecognitionScreen} />
<Stack.Screen name="BarcodeScanning" component={Screens.BarcodeScanningScreen} />
{/* IGNITE_GENERATOR_ANCHOR_APP_STACK_SCREENS */}
</Stack.Navigator>
)
Expand Down
230 changes: 230 additions & 0 deletions apps/ExampleApp/app/screens/BarcodeScanningScreen.tsx
Original file line number Diff line number Diff line change
@@ -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<AppStackScreenProps<"BarcodeScanning">>

function DebugOutput({ data }: { data: unknown }) {
const [expanded, setExpanded] = useState(false)

return (
<View style={$debugContainer}>
<Pressable onPress={() => setExpanded(!expanded)} style={$debugHeader}>
<Text style={$debugTitle}>{expanded ? "▼" : "▶"} Debug Output</Text>
</Pressable>
{expanded && (
<ScrollView style={$debugContent} horizontal>
<ScrollView nestedScrollEnabled>
<Text style={$debugText}>{JSON.stringify(data, null, 2)}</Text>
</ScrollView>
</ScrollView>
)}
</View>
)
}

export const BarcodeScanningScreen: FC<BarcodeScanningScreenProps> = observer(
function BarcodeScanningScreen() {
const navigation = useTypedNavigation<"BarcodeScanning">()

const [image, setImage] = useState<SelectedImage | null>(null)

const handleImageChange = useCallback((nextImage: SelectedImage) => {
setImage(nextImage)
}, [])

const [result, setResult] = useState<BarcodeScannerResult | null>(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 (
<Screen style={$root} preset="scroll" safeAreaEdges={["top", "bottom"]}>
<View>
<Icon icon={"back"} onPress={() => navigation.navigate("Home")} style={$backIcon} />
<Text preset={"heading"} text="Barcode Scanning" />
<Text style={$description}>Take a photo of a barcode and scan it.</Text>
</View>
<ImageSelector
onImageChange={handleImageChange}
onImageClear={clearResults}
onStatusChange={onStatusChange}
statusMessage={statusMessage}
status={isScanning ? "loading" : status}
isLoading={false}
images={{
filter: "all",
groupBy: "label",
}}
/>

{result && result.barcodes.length > 0 && (
<>
<View style={$resultContainer}>
<Text preset="subheading">Scanned Barcodes</Text>
{result.barcodes.map((barcode, index) => (
<View key={index} style={$barcodeItem}>
<Text style={$barcodeLabel}>Format: {barcode.format}</Text>
<Text style={$barcodeLabel}>Type: {barcode.valueType}</Text>
{barcode.displayValue && (
<Text style={$barcodeValue}>Value: {barcode.displayValue}</Text>
)}
{barcode.rawValue && barcode.rawValue !== barcode.displayValue && (
<Text style={$barcodeRaw}>Raw: {barcode.rawValue}</Text>
)}
</View>
))}
</View>
<DebugOutput data={result} />
</>
)}
</Screen>
)
},
)

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,
}
6 changes: 6 additions & 0 deletions apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
]
3 changes: 2 additions & 1 deletion apps/ExampleApp/app/screens/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export * from "./ImageLabelingScreen"
export * from "./DocumentScannerScreen"
export { BOX_COLORS } from "./FaceDetectionScreen"
export * from "./ObjectDetectionScreen"
export * from "./TextRecognitionScreen"
export * from "./TextRecognitionScreen"
export * from "./BarcodeScanningScreen"
1 change: 1 addition & 0 deletions apps/ExampleApp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 4 additions & 0 deletions docs/barcode-scanning/category.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Barcode Scanner",
"position": 100
}
7 changes: 7 additions & 0 deletions docs/barcode-scanning/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
sidebar_position: 1
---

# Barcode Scanner

<<Content goes here>>
8 changes: 8 additions & 0 deletions modules/react-native-mlkit-barcode-scanning/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
root: true,
extends: ["universe/native", "universe/web"],
ignorePatterns: ["build"],
rules: {
"@typescript-eslint/array-type": "off",
},
};
57 changes: 57 additions & 0 deletions modules/react-native-mlkit-barcode-scanning/.gitignore
Original file line number Diff line number Diff line change
@@ -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/*
11 changes: 11 additions & 0 deletions modules/react-native-mlkit-barcode-scanning/.npmignore
Original file line number Diff line number Diff line change
@@ -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/
1 change: 1 addition & 0 deletions modules/react-native-mlkit-barcode-scanning/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
5 changes: 5 additions & 0 deletions modules/react-native-mlkit-barcode-scanning/README.md
Original file line number Diff line number Diff line change
@@ -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
Loading