diff --git a/.changeset/nine-ads-drum.md b/.changeset/nine-ads-drum.md new file mode 100644 index 00000000..d5e38753 --- /dev/null +++ b/.changeset/nine-ads-drum.md @@ -0,0 +1,6 @@ +--- +"@infinitered/react-native-mlkit-text-recognition": major +"example-app": major +--- + +Added first version of Text Recognition module diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..9226c6c9 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:developers.google.com)" + ], + "deny": [], + "ask": [] + } +} \ No newline at end of file diff --git a/apps/ExampleApp/app.json b/apps/ExampleApp/app.json index c2bffb28..529704d3 100644 --- a/apps/ExampleApp/app.json +++ b/apps/ExampleApp/app.json @@ -18,9 +18,7 @@ "fallbackToCacheTimeout": 0 }, "jsEngine": "hermes", - "assetBundlePatterns": [ - "**/*" - ], + "assetBundlePatterns": ["**/*"], "android": { "icon": "./assets/images/app-icon-android-legacy.png", "package": "red.infinite.reactnativemlkit.example", @@ -64,6 +62,12 @@ "backgroundColor": "#F4F2F1", "imageWidth": 250 } + ], + [ + "expo-image-picker", + { + "photosPermission": "This app uses the photo library to select images for Machine Learning purposes. i.e. Object and Image detection." + } ] ], "experiments": { diff --git a/apps/ExampleApp/app/navigators/AppNavigator.tsx b/apps/ExampleApp/app/navigators/AppNavigator.tsx index e0a625d6..555125b7 100644 --- a/apps/ExampleApp/app/navigators/AppNavigator.tsx +++ b/apps/ExampleApp/app/navigators/AppNavigator.tsx @@ -35,6 +35,7 @@ export type AppStackParamList = { ImageLabeling: Record ObjectDetection: Record DocumentScanner: Record + TextRecognition: Record // IGNITE_GENERATOR_ANCHOR_APP_STACK_PARAM_LIST } @@ -68,6 +69,7 @@ const AppStack = observer(function AppStack() { + {/* IGNITE_GENERATOR_ANCHOR_APP_STACK_SCREENS */} ) diff --git a/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts b/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts index 5a455057..331dc0f2 100644 --- a/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts +++ b/apps/ExampleApp/app/screens/HomeScreen/demoInfo.ts @@ -11,6 +11,7 @@ export interface DemoInfo { const FACE_DETECTION = require("../../../assets/images/face-detection.jpg") const FACE_HOLDER = require("../../../assets/images/welcome-face.png") const DOCUMENT_SCANNER = require("../../../assets/images/doc-scanner.png") +const TEXT_RECOGNITION = require("../../../assets/images/text-recognition.png") const ANDROID_ONLY_DEMOS: DemoInfo[] = [ { @@ -46,5 +47,11 @@ export const DEMO_LIST: DemoInfo[] = [ screen: "ImageLabeling", image: FACE_HOLDER, }, + { + title: "Text recognition", + description: "Recognize text in an image", + screen: "TextRecognition", + image: TEXT_RECOGNITION, + }, ...PLATFORM_SPECIFIC_DEMOS, ] diff --git a/apps/ExampleApp/app/screens/TextRecognitionScreen.tsx b/apps/ExampleApp/app/screens/TextRecognitionScreen.tsx new file mode 100644 index 00000000..9d68b396 --- /dev/null +++ b/apps/ExampleApp/app/screens/TextRecognitionScreen.tsx @@ -0,0 +1,130 @@ +import React, { FC, useState, useEffect, useCallback } from "react" +import { observer } from "mobx-react-lite" +import { ViewStyle, View, ImageStyle, TextStyle } 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 { recognizeText } from "@infinitered/react-native-mlkit-text-recognition" +import { UseExampleImageStatus, SelectedImage } from "../utils/useExampleImage" + +type TextRecognitionScreenProps = NativeStackScreenProps> + +export const TextRecognitionScreen: FC = observer( + function TextRecognitionScreen() { + const navigation = useTypedNavigation<"TextRecognition">() + + 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) + }, + [], + ) + + useEffect(() => { + const recognizeImage = async () => { + if (!image?.uri) return + setStatus("recognizing") + try { + const recognitionResult = await recognizeText(image.uri) + setResult(recognitionResult.text) + setStatus("done") + } catch (error) { + console.error("Error recognizing image:", error) + setStatus("error") + } + } + + recognizeImage().then(() => null) + }, [image]) + + const statusMessage = React.useMemo(() => { + if (!image && status !== "init") { + setStatus("init") + } + 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 "Done!" + case "error": + return "Error during recognition!" + case "recognizing": + return "Recognizing Image..." + case "loading": + return "Loading Example Images..." + default: + throw new Error("Invalid status") + } + }, [result, image, status]) + + const clearResults = useCallback(() => { + setResult(null) + }, []) + + return ( + + + navigation.navigate("Home")} style={$backIcon} /> + + Take a photo, and extract text from it. + + + + {result && ( + + {result} + + )} + + ) + }, +) + +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, + marginVertical: 24, +} diff --git a/apps/ExampleApp/app/screens/index.ts b/apps/ExampleApp/app/screens/index.ts index f9588eb8..52f2fb39 100644 --- a/apps/ExampleApp/app/screens/index.ts +++ b/apps/ExampleApp/app/screens/index.ts @@ -7,3 +7,4 @@ export * from "./ImageLabelingScreen" export * from "./DocumentScannerScreen" export { BOX_COLORS } from "./FaceDetectionScreen" export * from "./ObjectDetectionScreen" +export * from "./TextRecognitionScreen" \ No newline at end of file diff --git a/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts b/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts index fb813eed..76570f08 100644 --- a/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts +++ b/apps/ExampleApp/app/utils/useExampleImage/useExampleImage.ts @@ -1,9 +1,7 @@ import { ImagePickerResult, - launchCameraAsync, launchImageLibraryAsync, ImagePickerOptions, - MediaTypeOptions, ImagePickerAsset, useCameraPermissions, } from "expo-image-picker" @@ -17,6 +15,7 @@ import { imageFilters, imageGroupers, } from "./examples" +import { launchImageLibrary } from "react-native-image-picker" export type UseExampleImageStatus = | "init" @@ -24,6 +23,7 @@ export type UseExampleImageStatus = | "takingPhoto" | "selectingPhoto" | "classifying" + | "recognizing" | "done" | "error" | "loading" @@ -56,7 +56,7 @@ interface ZippedImage extends RandomImage { } const IMAGE_PICKER_OPTIONS: ImagePickerOptions = { - mediaTypes: MediaTypeOptions.Images, + mediaTypes: "images", allowsEditing: false, quality: 0.5, } @@ -127,7 +127,9 @@ export function useExampleImage(predicates?: { return } setStatus("takingPhoto") - const result = await launchCameraAsync(IMAGE_PICKER_OPTIONS) + const result = await launchImageLibrary({ + mediaType: "photo", + }) if (result.assets?.[0]) { setImage({ ...result.assets?.[0], localUri: result.assets?.[0].uri } as SelectedImage) } else { diff --git a/apps/ExampleApp/assets/images/text-recognition.png b/apps/ExampleApp/assets/images/text-recognition.png new file mode 100644 index 00000000..c58cd834 Binary files /dev/null and b/apps/ExampleApp/assets/images/text-recognition.png differ diff --git a/apps/ExampleApp/package.json b/apps/ExampleApp/package.json index 5f6843d6..d76c3628 100644 --- a/apps/ExampleApp/package.json +++ b/apps/ExampleApp/package.json @@ -36,21 +36,22 @@ "@infinitered/react-native-mlkit-face-detection": "workspace:^3.1.0", "@infinitered/react-native-mlkit-image-labeling": "workspace:^3.1.0", "@infinitered/react-native-mlkit-object-detection": "workspace:^3.1.0", - "@react-native-async-storage/async-storage": "^2.0.0", + "@infinitered/react-native-mlkit-text-recognition": "workspace:^1.0.0", + "@react-native-async-storage/async-storage": "1.23.1", "@react-navigation/native": "^6.0.8", "@react-navigation/native-stack": "^6.0.2", - "@shopify/flash-list": "1.7.1", + "@shopify/flash-list": "1.7.3", "apisauce": "3.0.1", "date-fns": "^2.30.0", - "expo": "^52.0.28", - "expo-build-properties": "~0.13.2", - "expo-dev-client": "~5.0.11", - "expo-font": "~13.0.3", - "expo-image": "~2.0.4", - "expo-image-picker": "~16.0.5", + "expo": "~52.0.47", + "expo-build-properties": "~0.13.3", + "expo-dev-client": "~5.0.20", + "expo-font": "~13.0.4", + "expo-image": "~2.0.7", + "expo-image-picker": "~16.0.6", "expo-linking": "~7.0.5", "expo-localization": "~16.0.1", - "expo-splash-screen": "~0.29.21", + "expo-splash-screen": "~0.29.24", "expo-status-bar": "~2.0.1", "i18n-js": "3.9.2", "mobx": "6.10.2", @@ -58,12 +59,13 @@ "mobx-state-tree": "5.3.0", "react": "18.3.1", "react-dom": "^18.3.1", - "react-native": "^0.76.0", + "react-native": "0.76.9", "react-native-device-info": "^14.0.4", - "react-native-gesture-handler": "^2.20.0", + "react-native-gesture-handler": "~2.20.2", + "react-native-image-picker": "^8.2.1", "react-native-reanimated": "^3.16.1", - "react-native-safe-area-context": "^4.12.0", - "react-native-screens": "^3.34.0", + "react-native-safe-area-context": "4.12.0", + "react-native-screens": "~4.4.0", "react-native-web": "~0.19.13" }, "devDependencies": { @@ -100,7 +102,7 @@ "eslint-plugin-reactotron": "^0.1.2", "expo-atlas": "^0.3.0", "jest": "^29.2.1", - "jest-expo": "~52.0.3", + "jest-expo": "~52.0.6", "patch-package": "6.4.7", "postinstall-prepare": "1.0.1", "prettier": "2.8.8", @@ -111,7 +113,7 @@ "reactotron-react-native": "^5.0.5", "ts-jest": "^29.1.1", "ts-node": "^10.9.2", - "typescript": "~5.1.6" + "typescript": "^5.3.3" }, "engines": { "node": ">=18" diff --git a/docs/text-recognition/_category_.json b/docs/text-recognition/_category_.json new file mode 100644 index 00000000..e622a7e7 --- /dev/null +++ b/docs/text-recognition/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "Text Recognition", + "position": 500, + "link": { + "type": "generated-index", + "description": "Recognize text" + } +} diff --git a/docs/text-recognition/index.md b/docs/text-recognition/index.md new file mode 100644 index 00000000..46ffa3fd --- /dev/null +++ b/docs/text-recognition/index.md @@ -0,0 +1,98 @@ +--- +sidebar_position: 1 +title: Getting Started +--- + +# Object Detection + +## Getting Started + +This is an expo module that lets you use +the [MLKit Text Recognition](https://developers.google.com/ml-kit/vision/text-recognition/v2) library in your Expo app. + +## Installation + +Install like any other npm package: + +```bash +#yarn +yarn add @infinitered/react-native-mlkit-text-recognition + +#npm +npm install @infinitered/react-native-mlkit-text-recognition +``` + +## Basic Usage + +The models are made available through the context system. You can access them in your components using the same hook + +```tsx +// MyComponent.tsx +import { recognizeText } from "@infinitered/react-native-mlkit-text-recognition"; +import React, { useEffect, useState } from "react"; +import { View } from "react-native"; +import type { MyModelsConfig } from "./App"; + +type Props = { + imagePath: string; +}; + +function MyComponent({ imagePath }: Props) { + const [recognizedText, setRecognizedText] = useState(null); + + useEffect(() => { + async function recognizeTextAsync(imagePath: string) { + try { + const { text } = await recognizeText(imagePath); + setRecognizedText(text); + } catch (error) { + console.error("Error recognizing text:", error); + } + } + + if (imagePath) { + recognizeTextAsync(imagePath); + } + }, [imagePath]); + + return ( + + {recognizedText} + + ); +} +``` + +### Recognition Results + +The `recognizeText` method returns an `Text` object: + +```ts +interface Rect { + left: number; + top: number; + right: number; + bottom: number; +} + +interface TextBase { + text: string; + frame: Rect; + recognizedLanguage: string; +} + +interface TextElement extends TextBase {} + +interface TextLine extends TextBase { + elements: TextElement[]; +} + +interface TextBlock extends TextBase { + lines: TextLine[]; +} + +interface Text { + text: string; + textBlocks: TextBlock[]; +} +``` diff --git a/modules/react-native-mlkit-text-recognition/.eslintrc.js b/modules/react-native-mlkit-text-recognition/.eslintrc.js new file mode 100644 index 00000000..0dc2ae2a --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/.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-text-recognition/.gitignore b/modules/react-native-mlkit-text-recognition/.gitignore new file mode 100644 index 00000000..e64b91c9 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/.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-text-recognition/.npmignore b/modules/react-native-mlkit-text-recognition/.npmignore new file mode 100644 index 00000000..fa6abe7c --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/.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-text-recognition/android/build.gradle b/modules/react-native-mlkit-text-recognition/android/build.gradle new file mode 100644 index 00000000..679acd5e --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/android/build.gradle @@ -0,0 +1,58 @@ +apply plugin: 'com.android.library' + +group = 'red.infinite.reactnativemlkit.textrecognition' +version = '1.0.0' + +def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle") +apply from: expoModulesCorePlugin +applyKotlinExpoModulesCorePlugin() +useCoreDependencies() +useExpoPublishing() + +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 + } + + // Ensures backward compatibility + ext.getKotlinVersion = { + if (ext.has("kotlinVersion")) { + ext.kotlinVersion() + } else { + ext.safeExtGet("kotlinVersion", "1.8.10") + } + } + + repositories { + mavenCentral() + } + + dependencies { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${getKotlinVersion()}") + } +} +project.android { + compileSdkVersion safeExtGet("compileSdkVersion", 34) + defaultConfig { + minSdkVersion safeExtGet("minSdkVersion", 21) + targetSdkVersion safeExtGet("targetSdkVersion", 34) + } +} + +android { + namespace "red.infinite.reactnativemlkit.textrecognition" + defaultConfig { + versionCode 1 + versionName "1.0.0" + } + lintOptions { + abortOnError false + } +} + +dependencies { + implementation project(':expo-modules-core') + implementation project(path: ':infinitered-react-native-mlkit-core') + implementation 'com.google.mlkit:text-recognition:16.0.1' +} diff --git a/modules/react-native-mlkit-text-recognition/android/src/main/AndroidManifest.xml b/modules/react-native-mlkit-text-recognition/android/src/main/AndroidManifest.xml new file mode 100644 index 00000000..bdae66c8 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/android/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/modules/react-native-mlkit-text-recognition/android/src/main/java/red/infinite/reactnativemlkit/textrecognition/RNMLKitTextRecognitionModule.kt b/modules/react-native-mlkit-text-recognition/android/src/main/java/red/infinite/reactnativemlkit/textrecognition/RNMLKitTextRecognitionModule.kt new file mode 100644 index 00000000..44abbfc8 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/android/src/main/java/red/infinite/reactnativemlkit/textrecognition/RNMLKitTextRecognitionModule.kt @@ -0,0 +1,54 @@ +package red.infinite.reactnativemlkit.textrecognition + +import expo.modules.kotlin.Promise +import expo.modules.kotlin.exception.CodedException +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition +import java.net.URL +import com.google.mlkit.vision.text.latin.TextRecognizerOptions +import com.google.mlkit.vision.text.TextRecognition +import com.google.mlkit.vision.common.InputImage +import android.graphics.BitmapFactory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext + +suspend fun getInputImage( + imagePath: String +): InputImage { + try { + val bitmap = BitmapFactory.decodeStream(withContext(Dispatchers.IO) { + URL(imagePath).openStream() + }) + + return InputImage.fromBitmap(bitmap, 0) + } catch (e: Exception) { + throw Exception("RNMLKitTextRecognition: Could not load image from $imagePath", e) + } +} + +class RNMLKitTextRecognitionModule : Module() { + override fun definition() = ModuleDefinition { + Name("RNMLKitTextRecognition") + + AsyncFunction("recognizeText") { imagePath: String, promise: Promise -> + runBlocking { + val recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS) + + val image: InputImage = getInputImage(imagePath) + + recognizer.process(image) + .addOnSuccessListener { visionText -> + promise.resolve(mapTextToRecord(visionText)) + } + .addOnFailureListener { e -> + promise.reject( + CodedException( + "RNMLKitTextRecognitionModule - Error: ${e.message}", e + ) + ) + } + } + } + } +} diff --git a/modules/react-native-mlkit-text-recognition/android/src/main/java/red/infinite/reactnativemlkit/textrecognition/RNMLKitTextRecord.kt b/modules/react-native-mlkit-text-recognition/android/src/main/java/red/infinite/reactnativemlkit/textrecognition/RNMLKitTextRecord.kt new file mode 100644 index 00000000..cc6c161e --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/android/src/main/java/red/infinite/reactnativemlkit/textrecognition/RNMLKitTextRecord.kt @@ -0,0 +1,81 @@ +package red.infinite.reactnativemlkit.textrecognition + +import expo.modules.kotlin.records.Field +import expo.modules.kotlin.records.Record +import com.google.mlkit.vision.text.Text + +class RectRecord( + @Field val left: Double = 0.0, + @Field val top: Double = 0.0, + @Field val right: Double = 0.0, + @Field val bottom: Double = 0.0 +) : Record + +class TextElementRecord( + @Field val text: String = "", + @Field val frame: RectRecord = RectRecord(), + @Field val recognizedLanguage: String = "" +) : Record + +class TextLineRecord( + @Field val text: String = "", + @Field val frame: RectRecord = RectRecord(), + @Field val recognizedLanguage: String = "", + @Field val elements: List = emptyList() +) : Record + +class TextBlockRecord( + @Field val text: String = "", + @Field val frame: RectRecord = RectRecord(), + @Field val recognizedLanguage: String = "", + @Field val lines: List = emptyList() +) : Record + +class TextRecord( + @Field val text: String = "", + @Field val textBlocks: List = emptyList() +) : Record + +fun mapRectToRecord(rect: android.graphics.Rect?): RectRecord { + if (rect == null) return RectRecord() + + return RectRecord( + left = rect.left.toDouble(), + top = rect.top.toDouble(), + right = rect.right.toDouble(), + bottom = rect.bottom.toDouble() + ) +} + +fun mapElementToRecord(element: Text.Element): TextElementRecord { + return TextElementRecord( + text = element.text, + frame = mapRectToRecord(element.boundingBox), + recognizedLanguage = element.recognizedLanguage ?: "" + ) +} + +fun mapLineToRecord(line: Text.Line): TextLineRecord { + return TextLineRecord( + text = line.text, + frame = mapRectToRecord(line.boundingBox), + recognizedLanguage = line.recognizedLanguage ?: "", + elements = line.elements.map { mapElementToRecord(it) } + ) +} + +fun mapTextBlockToRecord(textBlock: Text.TextBlock): TextBlockRecord { + return TextBlockRecord( + text = textBlock.text, + frame = mapRectToRecord(textBlock.boundingBox), + recognizedLanguage = textBlock.recognizedLanguage ?: "", + lines = textBlock.lines.map { mapLineToRecord(it) } + ) +} + +fun mapTextToRecord(text: Text): TextRecord { + return TextRecord( + text = text.text, + textBlocks = text.textBlocks.map { mapTextBlockToRecord(it) } + ) +} \ No newline at end of file diff --git a/modules/react-native-mlkit-text-recognition/expo-module.config.json b/modules/react-native-mlkit-text-recognition/expo-module.config.json new file mode 100644 index 00000000..b0badfb7 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/expo-module.config.json @@ -0,0 +1,17 @@ +{ + "platforms": [ + "apple", + "android", + "web" + ], + "apple": { + "modules": [ + "RNMLKitTextRecognitionModule" + ] + }, + "android": { + "modules": [ + "red.infinite.reactnativemlkit.textrecognition.RNMLKitTextRecognitionModule" + ] + } +} diff --git a/modules/react-native-mlkit-text-recognition/index.ts b/modules/react-native-mlkit-text-recognition/index.ts new file mode 100644 index 00000000..4fa27edf --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/index.ts @@ -0,0 +1,4 @@ +// Reexport the native module. On web, it will be resolved to RNMLKitTextRecognitionModule.web.ts +// and on native platforms to RNMLKitTextRecognitionModule.ts +export { recognizeText } from './src/RNMLKitTextRecognitionModule'; + diff --git a/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecognition.podspec b/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecognition.podspec new file mode 100644 index 00000000..cb805928 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecognition.podspec @@ -0,0 +1,29 @@ +require 'json' + +package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json'))) + +Pod::Spec.new do |s| + s.name = 'RNMLKitTextRecognition' + 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 'ExpoModulesCore' + s.dependency 'RNMLKitCore' + s.dependency 'GoogleMLKit/TextRecognition' + + # Swift/Objective-C compatibility + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + 'SWIFT_COMPILATION_MODE' => 'wholemodule' + } + + s.source_files = "**/*.{h,m,swift}" +end diff --git a/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecognitionModule.swift b/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecognitionModule.swift new file mode 100644 index 00000000..0357141d --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecognitionModule.swift @@ -0,0 +1,34 @@ +import ExpoModulesCore +import MLKitCommon +import MLKitTextRecognition +import RNMLKitCore + +public class RNMLKitTextRecognitionModule: Module { + let ERROR_DOMAIN: String = "red.infinite.RNMLKit.RNMLKitTextRecognitionModuleErrorDomain" + + public func definition() -> ModuleDefinition { + Name("RNMLKitTextRecognition") + + AsyncFunction("recognizeText") { (imagePath: String, promise: Promise) in + let logger = Logger(logHandlers: [createOSLogHandler(category: Logger.EXPO_LOG_CATEGORY)]) + logger.info("RNMLKit", "recognize text: Recognizing text from image: \(imagePath) ") + + let options = TextRecognizerOptions() + let textRecognizer = TextRecognizer.textRecognizer(options:options) + + let image = try RNMLKitImage(imagePath: imagePath) + + Task { + do { + let result = try await textRecognizer.process(image.visionImage) + + promise.resolve(mapTextToRecord(result)) + } catch { + promise.reject( + NSError(domain: ERROR_DOMAIN, code: 1, userInfo: [NSLocalizedDescriptionKey: "Error occurred: \(error)"]) + ) + } + } + } + } +} diff --git a/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecord.swift b/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecord.swift new file mode 100644 index 00000000..08e14ab9 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/ios/RNMLKitTextRecord.swift @@ -0,0 +1,78 @@ +import ExpoModulesCore +import MLKitCommon +import MLKitTextRecognition + +struct RectRecord: Record { + @Field var left: Double = 0.0 + @Field var top: Double = 0.0 + @Field var right: Double = 0.0 + @Field var bottom: Double = 0.0 +} + +struct TextElementRecord: Record { + @Field var text: String = "" + @Field var frame: RectRecord = RectRecord() + @Field var recognizedLanguage: String = "" +} + +struct TextLineRecord: Record { + @Field var text: String = "" + @Field var frame: RectRecord = RectRecord() + @Field var recognizedLanguage: String = "" + @Field var elements: [TextElementRecord] = [] +} + +struct TextBlockRecord: Record { + @Field var text: String = "" + @Field var frame: RectRecord = RectRecord() + @Field var recognizedLanguage: String = "" + @Field var lines: [TextLineRecord] = [] +} + +struct TextRecord: Record { + @Field var text: String = "" + @Field var textBlocks: [TextBlockRecord] = [] +} + +func mapRectToRecord(_ rect: CGRect?) -> RectRecord { + guard let rect = rect else { return RectRecord() } + return RectRecord( + left: Double(rect.minX), + top: Double(rect.minY), + right: Double(rect.maxX), + bottom: Double(rect.maxY) + ) +} + +func mapElementToRecord(_ element: TextElement) -> TextElementRecord { + return TextElementRecord( + text: element.text, + frame: mapRectToRecord(element.frame), + recognizedLanguage: element.recognizedLanguages.first?.languageCode ?? "" + ) +} + +func mapLineToRecord(_ line: TextLine) -> TextLineRecord { + return TextLineRecord( + text: line.text, + frame: mapRectToRecord(line.frame), + recognizedLanguage: line.recognizedLanguages.first?.languageCode ?? "", + elements: line.elements.map(mapElementToRecord) + ) +} + +func mapTextBlockToRecord(_ textBlock: TextBlock) -> TextBlockRecord { + return TextBlockRecord( + text: textBlock.text, + frame: mapRectToRecord(textBlock.frame), + recognizedLanguage: textBlock.recognizedLanguages.first?.languageCode ?? "", + lines: textBlock.lines.map(mapLineToRecord) + ) +} + +func mapTextToRecord(_ text: Text) -> TextRecord { + return TextRecord( + text: text.text, + textBlocks: text.blocks.map(mapTextBlockToRecord) + ) +} diff --git a/modules/react-native-mlkit-text-recognition/package.json b/modules/react-native-mlkit-text-recognition/package.json new file mode 100644 index 00000000..3921c921 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/package.json @@ -0,0 +1,44 @@ +{ + "name": "@infinitered/react-native-mlkit-text-recognition", + "version": "1.0.0", + "description": "Expo module for MLKit Text Recognition", + "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-text-recognition", + "RNMLKitObjectDetection" + ], + "repository": "https://github.com/infinitered/react-native-mlkit", + "bugs": { + "url": "https://github.com/infinitered/react-native-mlkit/issues" + }, + "author": "Diogo Carmo (https://github.com/dccarmo)", + "license": "MIT", + "homepage": "https://docs.infinite.red/react-native-mlkit/text-recognition", + "dependencies": { + "@infinitered/react-native-mlkit-core": "3.1.0" + }, + "devDependencies": { + "@infinitered/react-native-mlkit-core": "3.1.0", + "@types/react": "~18.3.12", + "expo-module-scripts": "^3.4.1", + "expo-modules-core": "~2.2.0", + "typescript": "~5.1.6" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } +} diff --git a/modules/react-native-mlkit-text-recognition/src/RNMLKitTextRecognitionModule.ts b/modules/react-native-mlkit-text-recognition/src/RNMLKitTextRecognitionModule.ts new file mode 100644 index 00000000..ac69fbce --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/src/RNMLKitTextRecognitionModule.ts @@ -0,0 +1,43 @@ +import { requireNativeModule } from "expo"; + +interface Rect { + left: number; + top: number; + right: number; + bottom: number; +} + +interface TextBase { + text: string; + frame: Rect; + recognizedLanguage: string; +} + +interface TextElement extends TextBase {} + +interface TextLine extends TextBase { + elements: TextElement[]; +} + +interface TextBlock extends TextBase { + lines: TextLine[]; +} + +interface Text { + text: string; + textBlocks: TextBlock[]; +} + +interface RNMLKitTextRecognitionModule { + recognizeText: (imagePath: string) => Promise; +} + +const textRecognitionModule = requireNativeModule( + "RNMLKitTextRecognition" +); + +async function recognizeText(imagePath: string): Promise { + return await textRecognitionModule.recognizeText(imagePath); +} + +export { recognizeText }; diff --git a/modules/react-native-mlkit-text-recognition/src/index.ts b/modules/react-native-mlkit-text-recognition/src/index.ts new file mode 100644 index 00000000..60ed681b --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/src/index.ts @@ -0,0 +1 @@ +export * from "./RNMLKitTextRecognitionModule"; diff --git a/modules/react-native-mlkit-text-recognition/tsconfig.json b/modules/react-native-mlkit-text-recognition/tsconfig.json new file mode 100644 index 00000000..af4318d3 --- /dev/null +++ b/modules/react-native-mlkit-text-recognition/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 342f22cd..73af8644 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3739,6 +3739,88 @@ __metadata: languageName: node linkType: hard +"@expo/cli@npm:0.22.26": + version: 0.22.26 + resolution: "@expo/cli@npm:0.22.26" + dependencies: + "@0no-co/graphql.web": ^1.0.8 + "@babel/runtime": ^7.20.0 + "@expo/code-signing-certificates": ^0.0.5 + "@expo/config": ~10.0.11 + "@expo/config-plugins": ~9.0.17 + "@expo/devcert": ^1.1.2 + "@expo/env": ~0.4.2 + "@expo/image-utils": ^0.6.5 + "@expo/json-file": ^9.0.2 + "@expo/metro-config": ~0.19.12 + "@expo/osascript": ^2.1.6 + "@expo/package-manager": ^1.7.2 + "@expo/plist": ^0.2.2 + "@expo/prebuild-config": ~8.2.0 + "@expo/rudder-sdk-node": ^1.1.1 + "@expo/spawn-async": ^1.7.2 + "@expo/ws-tunnel": ^1.0.1 + "@expo/xcpretty": ^4.3.0 + "@react-native/dev-middleware": 0.76.9 + "@urql/core": ^5.0.6 + "@urql/exchange-retry": ^1.3.0 + accepts: ^1.3.8 + arg: ^5.0.2 + better-opn: ~3.0.2 + bplist-creator: 0.0.7 + bplist-parser: ^0.3.1 + cacache: ^18.0.2 + chalk: ^4.0.0 + ci-info: ^3.3.0 + compression: ^1.7.4 + connect: ^3.7.0 + debug: ^4.3.4 + env-editor: ^0.4.1 + fast-glob: ^3.3.2 + form-data: ^3.0.1 + freeport-async: ^2.0.0 + fs-extra: ~8.1.0 + getenv: ^1.0.0 + glob: ^10.4.2 + internal-ip: ^4.3.0 + is-docker: ^2.0.0 + is-wsl: ^2.1.1 + lodash.debounce: ^4.0.8 + minimatch: ^3.0.4 + node-forge: ^1.3.1 + npm-package-arg: ^11.0.0 + ora: ^3.4.0 + picomatch: ^3.0.1 + pretty-bytes: ^5.6.0 + pretty-format: ^29.7.0 + progress: ^2.0.3 + prompts: ^2.3.2 + qrcode-terminal: 0.11.0 + require-from-string: ^2.0.2 + requireg: ^0.2.2 + resolve: ^1.22.2 + resolve-from: ^5.0.0 + resolve.exports: ^2.0.3 + semver: ^7.6.0 + send: ^0.19.0 + slugify: ^1.3.4 + source-map-support: ~0.5.21 + stacktrace-parser: ^0.1.10 + structured-headers: ^0.4.1 + tar: ^6.2.1 + temp-dir: ^2.0.0 + tempy: ^0.7.1 + terminal-link: ^2.1.1 + undici: ^6.18.2 + unique-string: ~2.0.0 + wrap-ansi: ^7.0.0 + ws: ^8.12.1 + bin: + expo-internal: build/bin/cli + checksum: 32b79ab6a5ee88487e457e5f74249b2e081889521a89d53b452fbd454652428a08164e933681bf7707f4834f1cf529c3b6eaa9df7a077bc1a7bc026442990bf4 + languageName: node + linkType: hard + "@expo/code-signing-certificates@npm:^0.0.5": version: 0.0.5 resolution: "@expo/code-signing-certificates@npm:0.0.5" @@ -3794,6 +3876,28 @@ __metadata: languageName: node linkType: hard +"@expo/config-plugins@npm:~9.0.17": + version: 9.0.17 + resolution: "@expo/config-plugins@npm:9.0.17" + dependencies: + "@expo/config-types": ^52.0.5 + "@expo/json-file": ~9.0.2 + "@expo/plist": ^0.2.2 + "@expo/sdk-runtime-versions": ^1.0.0 + chalk: ^4.1.2 + debug: ^4.3.5 + getenv: ^1.0.0 + glob: ^10.4.2 + resolve-from: ^5.0.0 + semver: ^7.5.4 + slash: ^3.0.0 + slugify: ^1.6.6 + xcode: ^3.0.1 + xml2js: 0.6.0 + checksum: 5f415a3f4b399024d904d5c6e7b807d52f0efb6eddd217e458fa7d26d04b882f45462aa525ee8e49d404aecfc508e2a829ebd168f9a3b949a215a33699b0b92f + languageName: node + linkType: hard + "@expo/config-types@npm:^51.0.0-unreleased": version: 51.0.1 resolution: "@expo/config-types@npm:51.0.1" @@ -3808,6 +3912,34 @@ __metadata: languageName: node linkType: hard +"@expo/config-types@npm:^52.0.5": + version: 52.0.5 + resolution: "@expo/config-types@npm:52.0.5" + checksum: 2e8aa1a0d88e788868df494709f7a2544ef4ff555b038bfe5f6a8e4ee0d20c1e1239e58504026bf0e41afc9422532a8aee6cb0fe121bb8b71ea5521fd9bb27d0 + languageName: node + linkType: hard + +"@expo/config@npm:~10.0.11": + version: 10.0.11 + resolution: "@expo/config@npm:10.0.11" + dependencies: + "@babel/code-frame": ~7.10.4 + "@expo/config-plugins": ~9.0.17 + "@expo/config-types": ^52.0.5 + "@expo/json-file": ^9.0.2 + deepmerge: ^4.3.1 + getenv: ^1.0.0 + glob: ^10.4.2 + require-from-string: ^2.0.2 + resolve-from: ^5.0.0 + resolve-workspace-root: ^2.0.0 + semver: ^7.6.0 + slugify: ^1.3.4 + sucrase: 3.35.0 + checksum: 28f147b84e49d35306769e620f8e19da12f245e8fd08cf8279512f84eaccfdc3ab69f6ce9ea8e603ae3d0e9d994045336eff450f43b89f0b92f63e4914c47f3a + languageName: node + linkType: hard + "@expo/config@npm:~10.0.8": version: 10.0.8 resolution: "@expo/config@npm:10.0.8" @@ -3881,6 +4013,39 @@ __metadata: languageName: node linkType: hard +"@expo/env@npm:~0.4.2": + version: 0.4.2 + resolution: "@expo/env@npm:0.4.2" + dependencies: + chalk: ^4.0.0 + debug: ^4.3.4 + dotenv: ~16.4.5 + dotenv-expand: ~11.0.6 + getenv: ^1.0.0 + checksum: cc9264e50faf5f38e6253b5c97e775bc8cb29bf8ca37bcd427cbb67dd773a4e62a2bdb030904565bac4644eac89e10fc61206d5aa42e5b1f26acf5ca1f6b9ce9 + languageName: node + linkType: hard + +"@expo/fingerprint@npm:0.11.11": + version: 0.11.11 + resolution: "@expo/fingerprint@npm:0.11.11" + dependencies: + "@expo/spawn-async": ^1.7.2 + arg: ^5.0.2 + chalk: ^4.1.2 + debug: ^4.3.4 + find-up: ^5.0.0 + getenv: ^1.0.0 + minimatch: ^3.0.4 + p-limit: ^3.1.0 + resolve-from: ^5.0.0 + semver: ^7.6.0 + bin: + fingerprint: bin/cli.js + checksum: ef98fc8a4d7026ad409063f5a5776bf89375e4869bbcb5e4b2f3315bb1af75300d1f07107da458ff010dd71b295513e15838a0de91daed877a68dc52790b3adc + languageName: node + linkType: hard + "@expo/fingerprint@npm:0.11.7": version: 0.11.7 resolution: "@expo/fingerprint@npm:0.11.7" @@ -3919,6 +4084,34 @@ __metadata: languageName: node linkType: hard +"@expo/image-utils@npm:^0.6.5": + version: 0.6.5 + resolution: "@expo/image-utils@npm:0.6.5" + dependencies: + "@expo/spawn-async": ^1.7.2 + chalk: ^4.0.0 + fs-extra: 9.0.0 + getenv: ^1.0.0 + jimp-compact: 0.16.1 + parse-png: ^2.1.0 + resolve-from: ^5.0.0 + semver: ^7.6.0 + temp-dir: ~2.0.0 + unique-string: ~2.0.0 + checksum: f6fe5efd518d84463d767a4fb8a920d8b70779c8d93ba07ef407e0f016452324e3da6cff8292d0e2b436facdaef0073b8d527881e73ff5ba0288b4c942cdb539 + languageName: node + linkType: hard + +"@expo/json-file@npm:^10.0.1": + version: 10.0.1 + resolution: "@expo/json-file@npm:10.0.1" + dependencies: + "@babel/code-frame": ~7.10.4 + json5: ^2.2.3 + checksum: 84b7d02401f62cb3e9d12f4d3ba3dcef0bd5a4db143281689da0edbf449067f477d4e879fb38d7a8567a5a1df6331589f6a0e7cd9a7aea89e3d92f70610fcacc + languageName: node + linkType: hard + "@expo/json-file@npm:^8.3.0, @expo/json-file@npm:~8.3.0": version: 8.3.3 resolution: "@expo/json-file@npm:8.3.3" @@ -3941,6 +4134,53 @@ __metadata: languageName: node linkType: hard +"@expo/json-file@npm:^9.0.2": + version: 9.1.5 + resolution: "@expo/json-file@npm:9.1.5" + dependencies: + "@babel/code-frame": ~7.10.4 + json5: ^2.2.3 + checksum: beedf9077dcff476acd895219e391e18079d3c375e58bb4902a4147fffe9774e11d4d1607cfc3488f8e9daec2c30e4d7c17c46fb701035ad7aabacaaf6d465b4 + languageName: node + linkType: hard + +"@expo/json-file@npm:~9.0.2": + version: 9.0.2 + resolution: "@expo/json-file@npm:9.0.2" + dependencies: + "@babel/code-frame": ~7.10.4 + json5: ^2.2.3 + write-file-atomic: ^2.3.0 + checksum: 665fb72028e403adcb3ff9d7763ff6fab0ce16eaa1485a6b502daaab709608a9953599cce2f5c46e91b4791bd2380c87eb911deef4161b9d1f3a7631c2630366 + languageName: node + linkType: hard + +"@expo/metro-config@npm:0.19.12, @expo/metro-config@npm:~0.19.12": + version: 0.19.12 + resolution: "@expo/metro-config@npm:0.19.12" + dependencies: + "@babel/core": ^7.20.0 + "@babel/generator": ^7.20.5 + "@babel/parser": ^7.20.0 + "@babel/types": ^7.20.0 + "@expo/config": ~10.0.11 + "@expo/env": ~0.4.2 + "@expo/json-file": ~9.0.2 + "@expo/spawn-async": ^1.7.2 + chalk: ^4.1.0 + debug: ^4.3.2 + fs-extra: ^9.1.0 + getenv: ^1.0.0 + glob: ^10.4.2 + jsc-safe-url: ^0.2.4 + lightningcss: ~1.27.0 + minimatch: ^3.0.4 + postcss: ~8.4.32 + resolve-from: ^5.0.0 + checksum: 241934860fcf90575de47d67a6de5c701b51e16069a7007c15fac5addc04a66663e66800241aac63635761921829c2c6895217fd2bf6b8d95a00c2e1c664dfc3 + languageName: node + linkType: hard + "@expo/metro-config@npm:0.19.9, @expo/metro-config@npm:~0.19.9": version: 0.19.9 resolution: "@expo/metro-config@npm:0.19.9" @@ -3997,6 +4237,16 @@ __metadata: languageName: node linkType: hard +"@expo/osascript@npm:^2.1.6": + version: 2.3.1 + resolution: "@expo/osascript@npm:2.3.1" + dependencies: + "@expo/spawn-async": ^1.7.2 + exec-async: ^2.2.0 + checksum: 897599643535f385f4441aa6e339d76be7bfd96c5c36f0ee87ec8368af3fbdde810d8d3fde82711c89ccce938b914470bf002c5b0eb41ae9d9641517910dbf7b + languageName: node + linkType: hard + "@expo/package-manager@npm:^1.7.1": version: 1.7.1 resolution: "@expo/package-manager@npm:1.7.1" @@ -4017,6 +4267,20 @@ __metadata: languageName: node linkType: hard +"@expo/package-manager@npm:^1.7.2": + version: 1.9.1 + resolution: "@expo/package-manager@npm:1.9.1" + dependencies: + "@expo/json-file": ^10.0.1 + "@expo/spawn-async": ^1.7.2 + chalk: ^4.0.0 + npm-package-arg: ^11.0.0 + ora: ^3.4.0 + resolve-workspace-root: ^2.0.0 + checksum: 2605cffaf09c45469853423847cfeeb83d2f04538bf9cb00125e66218abc6e471c2a6b35b7ff2dce5c75892c7dbd982c903481a73392152b19d7fc992842a73a + languageName: node + linkType: hard + "@expo/plist@npm:^0.1.0": version: 0.1.3 resolution: "@expo/plist@npm:0.1.3" @@ -4039,6 +4303,17 @@ __metadata: languageName: node linkType: hard +"@expo/plist@npm:^0.2.2": + version: 0.2.2 + resolution: "@expo/plist@npm:0.2.2" + dependencies: + "@xmldom/xmldom": ~0.7.7 + base64-js: ^1.2.3 + xmlbuilder: ^14.0.0 + checksum: ccc8256f07352e327092132d885c3e2291f14b3ef6060065eb11080f130a575012cfff7ae92c579b5e04cc6b2587930caed70e277c2f1f5b63591e39366e659a + languageName: node + linkType: hard + "@expo/prebuild-config@npm:^8.0.25": version: 8.0.25 resolution: "@expo/prebuild-config@npm:8.0.25" @@ -4058,6 +4333,25 @@ __metadata: languageName: node linkType: hard +"@expo/prebuild-config@npm:~8.2.0": + version: 8.2.0 + resolution: "@expo/prebuild-config@npm:8.2.0" + dependencies: + "@expo/config": ~10.0.11 + "@expo/config-plugins": ~9.0.17 + "@expo/config-types": ^52.0.5 + "@expo/image-utils": ^0.6.5 + "@expo/json-file": ^9.0.2 + "@react-native/normalize-colors": 0.76.9 + debug: ^4.3.1 + fs-extra: ^9.0.0 + resolve-from: ^5.0.0 + semver: ^7.6.0 + xml2js: 0.6.0 + checksum: 5c9d194e63cc4ec9ba3076179832ce928208e09846981cccc6f07e70742b1d7a29bf7594788543578ced75a42fbc0d4a624c4bd7af73e755d220170090f0b2e5 + languageName: node + linkType: hard + "@expo/rudder-sdk-node@npm:^1.1.1": version: 1.1.1 resolution: "@expo/rudder-sdk-node@npm:1.1.1" @@ -4110,6 +4404,22 @@ __metadata: languageName: node linkType: hard +"@expo/vector-icons@npm:~14.0.4": + version: 14.0.4 + resolution: "@expo/vector-icons@npm:14.0.4" + dependencies: + prop-types: ^15.8.1 + checksum: 31bd5d4e4e2f0b0620b7e8b55b0c5691875cf57c5737bd0ccef0017d0e7abee66352f3d66a58997b719bd0720cccf8f5119503c69fe1a30398747306ebefeb6e + languageName: node + linkType: hard + +"@expo/ws-tunnel@npm:^1.0.1": + version: 1.0.6 + resolution: "@expo/ws-tunnel@npm:1.0.6" + checksum: 0db9d5b94cfedfad7784cfd876bafbf9575d0cb00bb537f57954fa8fe6d7151f95b2fa0aa6071b7cc7ab49e3a68bdf647acbc323d7d6b23f07df21f97485ee4f + languageName: node + linkType: hard + "@expo/xcpretty@npm:^4.3.0": version: 4.3.1 resolution: "@expo/xcpretty@npm:4.3.1" @@ -4302,6 +4612,22 @@ __metadata: languageName: unknown linkType: soft +"@infinitered/react-native-mlkit-text-recognition@workspace:^1.0.0, @infinitered/react-native-mlkit-text-recognition@workspace:modules/react-native-mlkit-text-recognition": + version: 0.0.0-use.local + resolution: "@infinitered/react-native-mlkit-text-recognition@workspace:modules/react-native-mlkit-text-recognition" + dependencies: + "@infinitered/react-native-mlkit-core": 3.1.0 + "@types/react": ~18.3.12 + expo-module-scripts: ^3.4.1 + expo-modules-core: ~2.2.0 + typescript: ~5.1.6 + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + languageName: unknown + linkType: soft + "@infinitered/tsconfig@0.5.0, @infinitered/tsconfig@workspace:packages/tsconfig": version: 0.0.0-use.local resolution: "@infinitered/tsconfig@workspace:packages/tsconfig" @@ -4828,14 +5154,14 @@ __metadata: languageName: node linkType: hard -"@react-native-async-storage/async-storage@npm:^2.0.0": - version: 2.1.1 - resolution: "@react-native-async-storage/async-storage@npm:2.1.1" +"@react-native-async-storage/async-storage@npm:1.23.1": + version: 1.23.1 + resolution: "@react-native-async-storage/async-storage@npm:1.23.1" dependencies: merge-options: ^3.0.4 peerDependencies: - react-native: ^0.0.0-0 || >=0.65 <1.0 - checksum: 51f3c89ddc32afee7969af61621a989c766504da6d8310b9ab2fe6c807f3c3c9d7f409ad85036b8f4c433fed4689f57380d603755491825c28b75be34b45d58c + react-native: ^0.0.0-0 || >=0.60 <1.0 + checksum: 7096546ed4a5faf1f6e0425e2e15713575f1a7493a04524da386ff35c3844b57b8fd20544fad4157b4a61e048b10235f2f06124f262da5b327edc74fbc31e02b languageName: node linkType: hard @@ -5028,10 +5354,10 @@ __metadata: languageName: node linkType: hard -"@react-native/assets-registry@npm:0.76.6": - version: 0.76.6 - resolution: "@react-native/assets-registry@npm:0.76.6" - checksum: 20a4d8e00c5e975a2db7f449f8b6a0a81c25ed14de8ec14099b7bda690a27ed8f34a54f5e558cc45649d8171ff52d2a5f4305cf82abab3584490f67cc36ea718 +"@react-native/assets-registry@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/assets-registry@npm:0.76.9" + checksum: 07e7da7a20745b6bdea99620e50d69c76219b7232b21cc43982696123a330cebd9d24e1a4be2a61588ab3af5155557e651267dfad9c91ad0bc8e098e6e7ad38f languageName: node linkType: hard @@ -5053,6 +5379,15 @@ __metadata: languageName: node linkType: hard +"@react-native/babel-plugin-codegen@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/babel-plugin-codegen@npm:0.76.9" + dependencies: + "@react-native/codegen": 0.76.9 + checksum: 13bba234a6c9e29fa4f7bf13a23ce8aecc5fc00da6cef6f6dd0462f82cdfeeeca62842c054ffe626662a92326774bf22723a90be5ac2158990386422ceee96c5 + languageName: node + linkType: hard + "@react-native/babel-preset@npm:0.74.84": version: 0.74.84 resolution: "@react-native/babel-preset@npm:0.74.84" @@ -5102,13 +5437,68 @@ __metadata: react-refresh: ^0.14.0 peerDependencies: "@babel/core": "*" - checksum: 5cdc7a56b165e1a03c8cc24bf5d8fd32bf987cd889aa958a82aa828e5fdb651d517a033b16be33f4fa26b9b685dfb805df644bdccc8067fb9fca2bfa82a417b6 + checksum: 5cdc7a56b165e1a03c8cc24bf5d8fd32bf987cd889aa958a82aa828e5fdb651d517a033b16be33f4fa26b9b685dfb805df644bdccc8067fb9fca2bfa82a417b6 + languageName: node + linkType: hard + +"@react-native/babel-preset@npm:0.76.6": + version: 0.76.6 + resolution: "@react-native/babel-preset@npm:0.76.6" + dependencies: + "@babel/core": ^7.25.2 + "@babel/plugin-proposal-export-default-from": ^7.24.7 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-syntax-export-default-from": ^7.24.7 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-transform-arrow-functions": ^7.24.7 + "@babel/plugin-transform-async-generator-functions": ^7.25.4 + "@babel/plugin-transform-async-to-generator": ^7.24.7 + "@babel/plugin-transform-block-scoping": ^7.25.0 + "@babel/plugin-transform-class-properties": ^7.25.4 + "@babel/plugin-transform-classes": ^7.25.4 + "@babel/plugin-transform-computed-properties": ^7.24.7 + "@babel/plugin-transform-destructuring": ^7.24.8 + "@babel/plugin-transform-flow-strip-types": ^7.25.2 + "@babel/plugin-transform-for-of": ^7.24.7 + "@babel/plugin-transform-function-name": ^7.25.1 + "@babel/plugin-transform-literals": ^7.25.2 + "@babel/plugin-transform-logical-assignment-operators": ^7.24.7 + "@babel/plugin-transform-modules-commonjs": ^7.24.8 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.24.7 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.24.7 + "@babel/plugin-transform-numeric-separator": ^7.24.7 + "@babel/plugin-transform-object-rest-spread": ^7.24.7 + "@babel/plugin-transform-optional-catch-binding": ^7.24.7 + "@babel/plugin-transform-optional-chaining": ^7.24.8 + "@babel/plugin-transform-parameters": ^7.24.7 + "@babel/plugin-transform-private-methods": ^7.24.7 + "@babel/plugin-transform-private-property-in-object": ^7.24.7 + "@babel/plugin-transform-react-display-name": ^7.24.7 + "@babel/plugin-transform-react-jsx": ^7.25.2 + "@babel/plugin-transform-react-jsx-self": ^7.24.7 + "@babel/plugin-transform-react-jsx-source": ^7.24.7 + "@babel/plugin-transform-regenerator": ^7.24.7 + "@babel/plugin-transform-runtime": ^7.24.7 + "@babel/plugin-transform-shorthand-properties": ^7.24.7 + "@babel/plugin-transform-spread": ^7.24.7 + "@babel/plugin-transform-sticky-regex": ^7.24.7 + "@babel/plugin-transform-typescript": ^7.25.2 + "@babel/plugin-transform-unicode-regex": ^7.24.7 + "@babel/template": ^7.25.0 + "@react-native/babel-plugin-codegen": 0.76.6 + babel-plugin-syntax-hermes-parser: ^0.25.1 + babel-plugin-transform-flow-enums: ^0.0.2 + react-refresh: ^0.14.0 + peerDependencies: + "@babel/core": "*" + checksum: 4c2e231fd07e14dd9d7090d0247c58928c3b75adfea0a4fff836722aa848c4d9cef7db474fe81a663454794f43df1902569994a03ec9b1c34c06573393b1d7a7 languageName: node linkType: hard -"@react-native/babel-preset@npm:0.76.6": - version: 0.76.6 - resolution: "@react-native/babel-preset@npm:0.76.6" +"@react-native/babel-preset@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/babel-preset@npm:0.76.9" dependencies: "@babel/core": ^7.25.2 "@babel/plugin-proposal-export-default-from": ^7.24.7 @@ -5151,13 +5541,13 @@ __metadata: "@babel/plugin-transform-typescript": ^7.25.2 "@babel/plugin-transform-unicode-regex": ^7.24.7 "@babel/template": ^7.25.0 - "@react-native/babel-plugin-codegen": 0.76.6 + "@react-native/babel-plugin-codegen": 0.76.9 babel-plugin-syntax-hermes-parser: ^0.25.1 babel-plugin-transform-flow-enums: ^0.0.2 react-refresh: ^0.14.0 peerDependencies: "@babel/core": "*" - checksum: 4c2e231fd07e14dd9d7090d0247c58928c3b75adfea0a4fff836722aa848c4d9cef7db474fe81a663454794f43df1902569994a03ec9b1c34c06573393b1d7a7 + checksum: b48ac1195d4b52a14134f3dbfa26771aa66db0b787ebced6153d7c60802f1b959a3cf07b873da1b085e7db9b527507d1111302bb177ad52d7c77d635b6f3805b languageName: node linkType: hard @@ -5196,12 +5586,30 @@ __metadata: languageName: node linkType: hard -"@react-native/community-cli-plugin@npm:0.76.6": - version: 0.76.6 - resolution: "@react-native/community-cli-plugin@npm:0.76.6" +"@react-native/codegen@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/codegen@npm:0.76.9" dependencies: - "@react-native/dev-middleware": 0.76.6 - "@react-native/metro-babel-transformer": 0.76.6 + "@babel/parser": ^7.25.3 + glob: ^7.1.1 + hermes-parser: 0.23.1 + invariant: ^2.2.4 + jscodeshift: ^0.14.0 + mkdirp: ^0.5.1 + nullthrows: ^1.1.1 + yargs: ^17.6.2 + peerDependencies: + "@babel/preset-env": ^7.1.6 + checksum: fcb26bd5be6f923eafd05e356ab01c9bbd30cab5e950bb050312a651771bcb2cb8484a3ba511e1460d44f508700565b0b69d43039c8cc61e63b9eacca6b9c756 + languageName: node + linkType: hard + +"@react-native/community-cli-plugin@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/community-cli-plugin@npm:0.76.9" + dependencies: + "@react-native/dev-middleware": 0.76.9 + "@react-native/metro-babel-transformer": 0.76.9 chalk: ^4.0.0 execa: ^5.1.1 invariant: ^2.2.4 @@ -5212,11 +5620,11 @@ __metadata: readline: ^1.3.0 semver: ^7.1.3 peerDependencies: - "@react-native-community/cli-server-api": "*" + "@react-native-community/cli": "*" peerDependenciesMeta: - "@react-native-community/cli-server-api": + "@react-native-community/cli": optional: true - checksum: 290008817d89e15074ef333561e8b8a5db0722743b3f760595c63e17de37d6663018040e4ffd8dd91bbdc19a50f7ac7a9db8e8eaf532434f776c14145414e3e6 + checksum: 1c0c054d20b3b4c978928e80aa5e56cadeb8dfc1c80a374f67a23e80e2acac0fff5aea0b3f6413483f1ba2bad6a65749e8105dd0ebf2dcd6b045f88e3d7c8d24 languageName: node linkType: hard @@ -5227,6 +5635,13 @@ __metadata: languageName: node linkType: hard +"@react-native/debugger-frontend@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/debugger-frontend@npm:0.76.9" + checksum: c537ae5be75bb9a0a549d88b6545762364d87a1166c8a7339ccd774257096a2c62f83efdd86c78553a3f1c4ef35cfa7708aba477bf6eeb76b7814ceab2b98069 + languageName: node + linkType: hard + "@react-native/dev-middleware@npm:0.76.6": version: 0.76.6 resolution: "@react-native/dev-middleware@npm:0.76.6" @@ -5246,10 +5661,30 @@ __metadata: languageName: node linkType: hard -"@react-native/gradle-plugin@npm:0.76.6": - version: 0.76.6 - resolution: "@react-native/gradle-plugin@npm:0.76.6" - checksum: e77112769a6a6d1b1920dae4890599ea5287ee28655c3e214c39099d6f6167e3b605c2239ee9bfebd1305dc4a04767dfd2c984f991bb04e13d63eaaa829312b4 +"@react-native/dev-middleware@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/dev-middleware@npm:0.76.9" + dependencies: + "@isaacs/ttlcache": ^1.4.1 + "@react-native/debugger-frontend": 0.76.9 + chrome-launcher: ^0.15.2 + chromium-edge-launcher: ^0.2.0 + connect: ^3.6.5 + debug: ^2.2.0 + invariant: ^2.2.4 + nullthrows: ^1.1.1 + open: ^7.0.3 + selfsigned: ^2.4.1 + serve-static: ^1.13.1 + ws: ^6.2.3 + checksum: 1f7750ae0c4d4d7970a73cd4f8443004a93b91b998a003ddb965274eb718d2a70ff06d182903dcaeccf15d8d245f488a397ea8ae53f6ed5f25e4d476d844b90f + languageName: node + linkType: hard + +"@react-native/gradle-plugin@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/gradle-plugin@npm:0.76.9" + checksum: afc6010cf278ed7dba58fb67cb789965edb6cfb3608e54b518232ef46b651f541915b7f6eae0b298457ccd8626213c687962ec250143e714de5e3bd2dc6dc210 languageName: node linkType: hard @@ -5260,6 +5695,13 @@ __metadata: languageName: node linkType: hard +"@react-native/js-polyfills@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/js-polyfills@npm:0.76.9" + checksum: c49aac99f6973b102a9013632c204f02a57d96da500901bc6730ab96f56950d6924417e39c87be640a3a59b67e1af2583432361f55bf42c959aff02a285bcafc + languageName: node + linkType: hard + "@react-native/metro-babel-transformer@npm:0.76.6": version: 0.76.6 resolution: "@react-native/metro-babel-transformer@npm:0.76.6" @@ -5274,6 +5716,20 @@ __metadata: languageName: node linkType: hard +"@react-native/metro-babel-transformer@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/metro-babel-transformer@npm:0.76.9" + dependencies: + "@babel/core": ^7.25.2 + "@react-native/babel-preset": 0.76.9 + hermes-parser: 0.23.1 + nullthrows: ^1.1.1 + peerDependencies: + "@babel/core": "*" + checksum: cb38d150e30b3e07e2cb8e637e26b4dcb8b58d6accc95f51e507baea94bb970a0077573c319849a3e7d9bf976dadc39cf363bb505f53de1a209e1bb9ea0428f8 + languageName: node + linkType: hard + "@react-native/metro-config@npm:^0.76.0": version: 0.76.6 resolution: "@react-native/metro-config@npm:0.76.6" @@ -5293,6 +5749,13 @@ __metadata: languageName: node linkType: hard +"@react-native/normalize-colors@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/normalize-colors@npm:0.76.9" + checksum: 4fddb977b8aad2e848cb698f13b9ffec539668e8ae891846327d5e23ce3de13dea59a2dfbea8a154ea034791c7abc3f7d1d4c8caae2114f7a683c78b221aed36 + languageName: node + linkType: hard + "@react-native/normalize-colors@npm:^0.74.1": version: 0.74.84 resolution: "@react-native/normalize-colors@npm:0.74.84" @@ -5300,9 +5763,9 @@ __metadata: languageName: node linkType: hard -"@react-native/virtualized-lists@npm:0.76.6": - version: 0.76.6 - resolution: "@react-native/virtualized-lists@npm:0.76.6" +"@react-native/virtualized-lists@npm:0.76.9": + version: 0.76.9 + resolution: "@react-native/virtualized-lists@npm:0.76.9" dependencies: invariant: ^2.2.4 nullthrows: ^1.1.1 @@ -5313,7 +5776,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 6c5aa84733b55bf5a927d0c666dc7d8808f7696fc12d4c22a86f5d68c2ad38d908132e59526934d36bc49f17546baae00f49c3f99f25317cabafa19387caa5de + checksum: 697a04bdf4b5f430164bf666bf60cd0207f4d3fb06b0a62d7c39b54c166973b29c73640e5c1a44f1c6891d93398bedd63eb8addcbe78641d7ebb13b9ab022052 languageName: node linkType: hard @@ -5511,17 +5974,17 @@ __metadata: languageName: node linkType: hard -"@shopify/flash-list@npm:1.7.1": - version: 1.7.1 - resolution: "@shopify/flash-list@npm:1.7.1" +"@shopify/flash-list@npm:1.7.3": + version: 1.7.3 + resolution: "@shopify/flash-list@npm:1.7.3" dependencies: recyclerlistview: 4.2.1 - tslib: 2.6.3 + tslib: 2.8.1 peerDependencies: "@babel/runtime": "*" react: "*" react-native: "*" - checksum: 82235ac12043dd9da0bc58ab4be76d01f0496f6c769167f5139854278c5a680154d745e5226b0176cd28d1d2351fd9d3f484ed35c44c3b6ee18dbcb075826451 + checksum: cbf3289779141777eab4ec6f1a59b90c6f2f91fb4a880dad09ace5e37559a1448ddbf7a282c8787bb7b4f1b45d3f612f8a940760accfd88313494d47a1d63cce languageName: node linkType: hard @@ -7945,6 +8408,31 @@ __metadata: languageName: node linkType: hard +"babel-preset-expo@npm:~12.0.11": + version: 12.0.11 + resolution: "babel-preset-expo@npm:12.0.11" + dependencies: + "@babel/plugin-proposal-decorators": ^7.12.9 + "@babel/plugin-transform-export-namespace-from": ^7.22.11 + "@babel/plugin-transform-object-rest-spread": ^7.12.13 + "@babel/plugin-transform-parameters": ^7.22.15 + "@babel/preset-react": ^7.22.15 + "@babel/preset-typescript": ^7.23.0 + "@react-native/babel-preset": 0.76.9 + babel-plugin-react-native-web: ~0.19.13 + react-refresh: ^0.14.2 + peerDependencies: + babel-plugin-react-compiler: ^19.0.0-beta-9ee70a1-20241017 + react-compiler-runtime: ^19.0.0-beta-8a03594-20241020 + peerDependenciesMeta: + babel-plugin-react-compiler: + optional: true + react-compiler-runtime: + optional: true + checksum: 8ff4437a5e3ea229c22ad2de645abc452f05fe55bc72b2586e4cfe675fcc6b3c83779c1a18343364d200b988cac5e60eed6e616a29eb1446e2294236f9f60d3f + languageName: node + linkType: hard + "babel-preset-expo@npm:~12.0.6": version: 12.0.6 resolution: "babel-preset-expo@npm:12.0.6" @@ -11416,8 +11904,9 @@ __metadata: "@infinitered/react-native-mlkit-face-detection": "workspace:^3.1.0" "@infinitered/react-native-mlkit-image-labeling": "workspace:^3.1.0" "@infinitered/react-native-mlkit-object-detection": "workspace:^3.1.0" + "@infinitered/react-native-mlkit-text-recognition": "workspace:^1.0.0" "@infinitered/tsconfig": 0.5.0 - "@react-native-async-storage/async-storage": ^2.0.0 + "@react-native-async-storage/async-storage": 1.23.1 "@react-native-community/cli": ^15.0.0 "@react-native-community/cli-platform-android": ^15.0.0 "@react-native-community/cli-platform-ios": ^15.0.0 @@ -11425,7 +11914,7 @@ __metadata: "@react-navigation/native": ^6.0.8 "@react-navigation/native-stack": ^6.0.2 "@rnx-kit/align-deps": ^3.0.3 - "@shopify/flash-list": 1.7.1 + "@shopify/flash-list": 1.7.3 "@types/i18n-js": 3.8.2 "@types/jest": ^29.2.1 "@types/react": ~18.3.12 @@ -11444,20 +11933,20 @@ __metadata: eslint-plugin-react: 7.30.0 eslint-plugin-react-native: 4.0.0 eslint-plugin-reactotron: ^0.1.2 - expo: ^52.0.28 + expo: ~52.0.47 expo-atlas: ^0.3.0 - expo-build-properties: ~0.13.2 - expo-dev-client: ~5.0.11 - expo-font: ~13.0.3 - expo-image: ~2.0.4 - expo-image-picker: ~16.0.5 + expo-build-properties: ~0.13.3 + expo-dev-client: ~5.0.20 + expo-font: ~13.0.4 + expo-image: ~2.0.7 + expo-image-picker: ~16.0.6 expo-linking: ~7.0.5 expo-localization: ~16.0.1 - expo-splash-screen: ~0.29.21 + expo-splash-screen: ~0.29.24 expo-status-bar: ~2.0.1 i18n-js: 3.9.2 jest: ^29.2.1 - jest-expo: ~52.0.3 + jest-expo: ~52.0.6 mobx: 6.10.2 mobx-react-lite: 4.0.5 mobx-state-tree: 5.3.0 @@ -11466,12 +11955,13 @@ __metadata: prettier: 2.8.8 react: 18.3.1 react-dom: ^18.3.1 - react-native: ^0.76.0 + react-native: 0.76.9 react-native-device-info: ^14.0.4 - react-native-gesture-handler: ^2.20.0 + react-native-gesture-handler: ~2.20.2 + react-native-image-picker: ^8.2.1 react-native-reanimated: ^3.16.1 - react-native-safe-area-context: ^4.12.0 - react-native-screens: ^3.34.0 + react-native-safe-area-context: 4.12.0 + react-native-screens: ~4.4.0 react-native-web: ~0.19.13 react-test-renderer: 18.3.1 reactotron-core-client: ^2.8.13 @@ -11480,7 +11970,7 @@ __metadata: reactotron-react-native: ^5.0.5 ts-jest: ^29.1.1 ts-node: ^10.9.2 - typescript: ~5.1.6 + typescript: ^5.3.3 languageName: unknown linkType: soft @@ -11576,6 +12066,22 @@ __metadata: languageName: node linkType: hard +"expo-asset@npm:~11.0.5": + version: 11.0.5 + resolution: "expo-asset@npm:11.0.5" + dependencies: + "@expo/image-utils": ^0.6.5 + expo-constants: ~17.0.8 + invariant: ^2.2.4 + md5-file: ^3.2.3 + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + checksum: 7650dc032f76b0924eedaf24dee135b293e5c3258e0a9e43a6db7c93ef40ea6b6d6a47432bf80f3051f3b62e40a6ccb25e8acca820baa791d52a2e95432868bc + languageName: node + linkType: hard + "expo-atlas@npm:^0.3.0": version: 0.3.8 resolution: "expo-atlas@npm:0.3.8" @@ -11600,15 +12106,15 @@ __metadata: languageName: node linkType: hard -"expo-build-properties@npm:~0.13.2": - version: 0.13.2 - resolution: "expo-build-properties@npm:0.13.2" +"expo-build-properties@npm:~0.13.3": + version: 0.13.3 + resolution: "expo-build-properties@npm:0.13.3" dependencies: ajv: ^8.11.0 semver: ^7.6.0 peerDependencies: expo: "*" - checksum: 47ddcd6b2bf981e02f7bec67f0988c2171e01dc9ac44bb7e1addb23136c5674abfe3be77f76702a3ee6aa417239bc4926b4c88db8eddedb6cb3d06bcb5e72f98 + checksum: 65b97a82dc46b5d92f7ed7e1d4e85bb441ac719a6dacea54ba0ae0c9080ae5c465b5ccab6e41cc8bdca63a26128a72d73ed6901e5c38793fd95fac0fa6dc2588 languageName: node linkType: hard @@ -11625,32 +12131,45 @@ __metadata: languageName: node linkType: hard -"expo-dev-client@npm:~5.0.11": - version: 5.0.11 - resolution: "expo-dev-client@npm:5.0.11" +"expo-constants@npm:~17.0.8": + version: 17.0.8 + resolution: "expo-constants@npm:17.0.8" + dependencies: + "@expo/config": ~10.0.11 + "@expo/env": ~0.4.2 + peerDependencies: + expo: "*" + react-native: "*" + checksum: 493e18f8ea2c49efd69aae37b756ede1c37ecc29ac9bd5c23cb2ca88dbc57109c7f915196bcfaab71ceca2141e9a9806a685f8ac787fa206af7f1391be2e09f2 + languageName: node + linkType: hard + +"expo-dev-client@npm:~5.0.20": + version: 5.0.20 + resolution: "expo-dev-client@npm:5.0.20" dependencies: - expo-dev-launcher: 5.0.27 - expo-dev-menu: 6.0.18 + expo-dev-launcher: 5.0.35 + expo-dev-menu: 6.0.25 expo-dev-menu-interface: 1.9.3 - expo-manifests: ~0.15.5 + expo-manifests: ~0.15.8 expo-updates-interface: ~1.0.0 peerDependencies: expo: "*" - checksum: 76ae8545da8d42e633b7f5ad6b5820b00d16717900cf2bdf2214f4f163715aacc961b16b8588b6e208d8389d931645bfced08cf20cb8f93d3239472d6512b04c + checksum: bc853c70217c2e9e4903d2f23bc383e1b4f8a9037d95c5af66d8c1c4835edce045e1eda98b1479e72ad88e379899e3af16f625f7f75974650e72a258e60c34c2 languageName: node linkType: hard -"expo-dev-launcher@npm:5.0.27": - version: 5.0.27 - resolution: "expo-dev-launcher@npm:5.0.27" +"expo-dev-launcher@npm:5.0.35": + version: 5.0.35 + resolution: "expo-dev-launcher@npm:5.0.35" dependencies: ajv: 8.11.0 - expo-dev-menu: 6.0.18 - expo-manifests: ~0.15.5 + expo-dev-menu: 6.0.25 + expo-manifests: ~0.15.8 resolve-from: ^5.0.0 peerDependencies: expo: "*" - checksum: 5f4e4a70b3d4b9baf9f122aebef7d024a04d72c6d11c07866e4c3d00b8f578036bc02f904525e0e07649b176a506556c91c00af68906e11c88c977c66fe1f8f5 + checksum: 621f4a3ca047f5663a7a7dcbd790a19b41d8c01ef629ae075db7fd7af3dc5b829e463defc3bb247fea0d618f0598b7a7e3461d96cf6711b5076749c63ed305e9 languageName: node linkType: hard @@ -11663,14 +12182,26 @@ __metadata: languageName: node linkType: hard -"expo-dev-menu@npm:6.0.18": - version: 6.0.18 - resolution: "expo-dev-menu@npm:6.0.18" +"expo-dev-menu@npm:6.0.25": + version: 6.0.25 + resolution: "expo-dev-menu@npm:6.0.25" dependencies: expo-dev-menu-interface: 1.9.3 peerDependencies: expo: "*" - checksum: b4b810e6600025446b21fbe0e4647cbbfc1420466ddf62126edd4746231899d547d22a6dd3496440f08b1a74a035affcf6844c554367dac1024bb0e86946d08a + checksum: 6ec93000526929f26b55ffb7e78341afd51fbffb881d25bdf2b65cfa41a2b7052bde567f08f5fa9909e2b324c23fb7878d5aca0da2279aeef2229cd676ac12a0 + languageName: node + linkType: hard + +"expo-file-system@npm:~18.0.12": + version: 18.0.12 + resolution: "expo-file-system@npm:18.0.12" + dependencies: + web-streams-polyfill: ^3.3.2 + peerDependencies: + expo: "*" + react-native: "*" + checksum: 9724e2a9da1cf596d82920cf3cec3d4d6e6544d3b057c7e5895d2aac6f2fc30d9f963774198254fcde707030974407b13a4da7558160fc2278fc388cb183d253 languageName: node linkType: hard @@ -11698,6 +12229,18 @@ __metadata: languageName: node linkType: hard +"expo-font@npm:~13.0.4": + version: 13.0.4 + resolution: "expo-font@npm:13.0.4" + dependencies: + fontfaceobserver: ^2.1.0 + peerDependencies: + expo: "*" + react: "*" + checksum: 36fa98d333c97a9a309f0ffa45827616167162caaaca6873f04d6e3d658c669da9e894fadd582b9bcc569f3b5b2043553ca204e4333d7496ad2e5843f0373b09 + languageName: node + linkType: hard + "expo-image-loader@npm:~5.0.0": version: 5.0.0 resolution: "expo-image-loader@npm:5.0.0" @@ -11707,18 +12250,18 @@ __metadata: languageName: node linkType: hard -"expo-image-picker@npm:~16.0.5": - version: 16.0.5 - resolution: "expo-image-picker@npm:16.0.5" +"expo-image-picker@npm:~16.0.6": + version: 16.0.6 + resolution: "expo-image-picker@npm:16.0.6" dependencies: expo-image-loader: ~5.0.0 peerDependencies: expo: "*" - checksum: 8391455480d07a2fa785a0246b8eb892d393e64173f4663d77ee26bc497a0f52d9e1690b0fa04094d03ada8cc78aa5477505d870bdcbdb05d5c48c791ddac168 + checksum: 448097075ad08c99a9c2857547e36f07e5e491fe5264fe03e77418271f077478a89f1ad462febedb9070013bf90f826b75ad4b2855d98a93593f76ae20c121de languageName: node linkType: hard -"expo-image@npm:^2.0.4, expo-image@npm:~2.0.4": +"expo-image@npm:^2.0.4": version: 2.0.4 resolution: "expo-image@npm:2.0.4" peerDependencies: @@ -11733,6 +12276,21 @@ __metadata: languageName: node linkType: hard +"expo-image@npm:~2.0.7": + version: 2.0.7 + resolution: "expo-image@npm:2.0.7" + peerDependencies: + expo: "*" + react: "*" + react-native: "*" + react-native-web: "*" + peerDependenciesMeta: + react-native-web: + optional: true + checksum: 07a6b41295e1acea62c4ed6c1ef00736a357a436aecce07579858430e99c236a5b3e77044502b205aa63411a8b95e3f6b11d4eb65c34d3f5313ce7fb73438688 + languageName: node + linkType: hard + "expo-json-utils@npm:~0.14.0": version: 0.14.0 resolution: "expo-json-utils@npm:0.14.0" @@ -11750,6 +12308,16 @@ __metadata: languageName: node linkType: hard +"expo-keep-awake@npm:~14.0.3": + version: 14.0.3 + resolution: "expo-keep-awake@npm:14.0.3" + peerDependencies: + expo: "*" + react: "*" + checksum: 1f8c4c4fbc6030b4ea55fd51b6bb74ba926c71ab3c5350445b065d1433188553b67c64114230240055788df918c96d2d925d9987dcd9fc4045e45362adcbb110 + languageName: node + linkType: hard + "expo-linking@npm:~7.0.5": version: 7.0.5 resolution: "expo-linking@npm:7.0.5" @@ -11775,15 +12343,15 @@ __metadata: languageName: node linkType: hard -"expo-manifests@npm:~0.15.5": - version: 0.15.5 - resolution: "expo-manifests@npm:0.15.5" +"expo-manifests@npm:~0.15.8": + version: 0.15.8 + resolution: "expo-manifests@npm:0.15.8" dependencies: - "@expo/config": ~10.0.8 + "@expo/config": ~10.0.11 expo-json-utils: ~0.14.0 peerDependencies: expo: "*" - checksum: 58e7da19f79947210067428f6549b54ab9cb7a683ed9b1d739a17c3c240bf1beb745064d15eefcd7a54cc348652732730d08b14e2c65d71d3c2cbe29f396f584 + checksum: 608e3ca95757b6adc2374442691cb918402810c69ed9fca6acd3f64bdfbd7e6be33470e777cb4d8656c322cd2e2a1524066bf8dcf9d11c1a21e5ce11145f31f2 languageName: node linkType: hard @@ -11834,6 +12402,24 @@ __metadata: languageName: node linkType: hard +"expo-modules-autolinking@npm:2.0.8": + version: 2.0.8 + resolution: "expo-modules-autolinking@npm:2.0.8" + dependencies: + "@expo/spawn-async": ^1.7.2 + chalk: ^4.1.0 + commander: ^7.2.0 + fast-glob: ^3.2.5 + find-up: ^5.0.0 + fs-extra: ^9.1.0 + require-from-string: ^2.0.2 + resolve-from: ^5.0.0 + bin: + expo-modules-autolinking: bin/expo-modules-autolinking.js + checksum: 1e706d40163e0d3c239641c6d4a846c8006c0367007006cff1eb26a571e605d5fa5ce49c995b9118516d82c819be0e2e2849c2ae63df9b2921bf23bc9a4c2939 + languageName: node + linkType: hard + "expo-modules-core@npm:2.2.0, expo-modules-core@npm:^2.2.0, expo-modules-core@npm:~2.2.0": version: 2.2.0 resolution: "expo-modules-core@npm:2.2.0" @@ -11843,14 +12429,23 @@ __metadata: languageName: node linkType: hard -"expo-splash-screen@npm:~0.29.21": - version: 0.29.21 - resolution: "expo-splash-screen@npm:0.29.21" +"expo-modules-core@npm:2.2.3": + version: 2.2.3 + resolution: "expo-modules-core@npm:2.2.3" + dependencies: + invariant: ^2.2.4 + checksum: 7b2952f1220b55eb03f395d1549525edeb5bff7bf805257d9652ea4ef85ea71e34ad13b5971f1b559e7aa080f41130846b24cbe3d754660c08196c3ce899143b + languageName: node + linkType: hard + +"expo-splash-screen@npm:~0.29.24": + version: 0.29.24 + resolution: "expo-splash-screen@npm:0.29.24" dependencies: - "@expo/prebuild-config": ^8.0.25 + "@expo/prebuild-config": ~8.2.0 peerDependencies: expo: "*" - checksum: 7c26c80f1840cbe6a68db8d71884c424cea2b93d2516fd000957aeae62dbae50d7bbed557f5eb5a1dd52a41b6db1b78fb469e6d25b5c57d482e8cc1826f17b75 + checksum: 6a2b1c0c58490e67821f9c5ef6d6d8fdf55d95a8b856d42ebe28d66e5221ab9f03dbf08329e4ec9196ba7942730db96fccaceb87e7d6f2963cca204727aad577 languageName: node linkType: hard @@ -11873,7 +12468,7 @@ __metadata: languageName: node linkType: hard -"expo@npm:^52.0.0, expo@npm:^52.0.28": +"expo@npm:^52.0.0": version: 52.0.28 resolution: "expo@npm:52.0.28" dependencies: @@ -11914,6 +12509,49 @@ __metadata: languageName: node linkType: hard +"expo@npm:~52.0.47": + version: 52.0.47 + resolution: "expo@npm:52.0.47" + dependencies: + "@babel/runtime": ^7.20.0 + "@expo/cli": 0.22.26 + "@expo/config": ~10.0.11 + "@expo/config-plugins": ~9.0.17 + "@expo/fingerprint": 0.11.11 + "@expo/metro-config": 0.19.12 + "@expo/vector-icons": ~14.0.4 + babel-preset-expo: ~12.0.11 + expo-asset: ~11.0.5 + expo-constants: ~17.0.8 + expo-file-system: ~18.0.12 + expo-font: ~13.0.4 + expo-keep-awake: ~14.0.3 + expo-modules-autolinking: 2.0.8 + expo-modules-core: 2.2.3 + fbemitter: ^3.0.0 + web-streams-polyfill: ^3.3.2 + whatwg-url-without-unicode: 8.0.0-3 + peerDependencies: + "@expo/dom-webview": "*" + "@expo/metro-runtime": "*" + react: "*" + react-native: "*" + react-native-webview: "*" + peerDependenciesMeta: + "@expo/dom-webview": + optional: true + "@expo/metro-runtime": + optional: true + react-native-webview: + optional: true + bin: + expo: bin/cli + expo-modules-autolinking: bin/autolinking + fingerprint: bin/fingerprint + checksum: a49a132e921a4e075765ee1fa200351bbe31ce6e1aff5580032b579d96236b0cbec83fdd096ce8ae942d275f608c6e0f0914251f9a7e2fbec3d37f15321030a0 + languageName: node + linkType: hard + "exponential-backoff@npm:^3.1.1": version: 3.1.1 resolution: "exponential-backoff@npm:3.1.1" @@ -14744,7 +15382,7 @@ __metadata: languageName: node linkType: hard -"jest-expo@npm:^52.0.3, jest-expo@npm:~52.0.3": +"jest-expo@npm:^52.0.3": version: 52.0.3 resolution: "jest-expo@npm:52.0.3" dependencies: @@ -14796,6 +15434,36 @@ __metadata: languageName: node linkType: hard +"jest-expo@npm:~52.0.6": + version: 52.0.6 + resolution: "jest-expo@npm:52.0.6" + dependencies: + "@expo/config": ~10.0.11 + "@expo/json-file": ^9.0.2 + "@jest/create-cache-key-function": ^29.2.1 + "@jest/globals": ^29.2.1 + babel-jest: ^29.2.1 + fbemitter: ^3.0.0 + find-up: ^5.0.0 + jest-environment-jsdom: ^29.2.1 + jest-snapshot: ^29.2.1 + jest-watch-select-projects: ^2.0.0 + jest-watch-typeahead: 2.2.1 + json5: ^2.2.3 + lodash: ^4.17.19 + react-server-dom-webpack: 19.0.0-rc-6230622a1a-20240610 + react-test-renderer: 18.3.1 + server-only: ^0.0.1 + stacktrace-js: ^2.0.2 + peerDependencies: + expo: "*" + react-native: "*" + bin: + jest: bin/jest.js + checksum: 6ce4c73696e98a67e6479c716fc05ff52b97ce74d16b13132912b5492da08f537932437acea0b34bfb89df1433c882871906990334593b3eb9820de9ca8c6c70 + languageName: node + linkType: hard + "jest-get-type@npm:^29.6.3": version: 29.6.3 resolution: "jest-get-type@npm:29.6.3" @@ -19056,17 +19724,28 @@ __metadata: languageName: node linkType: hard -"react-native-gesture-handler@npm:^2.20.0": - version: 2.22.1 - resolution: "react-native-gesture-handler@npm:2.22.1" +"react-native-gesture-handler@npm:~2.20.2": + version: 2.20.2 + resolution: "react-native-gesture-handler@npm:2.20.2" dependencies: "@egjs/hammerjs": ^2.0.17 hoist-non-react-statics: ^3.3.0 invariant: ^2.2.4 + prop-types: ^15.7.2 + peerDependencies: + react: "*" + react-native: "*" + checksum: 8d9e7496615dad4e6bb6dd1c750c2d3b2e57c6173a1d466b4503b28b159b1dbbb1e7527c3d4bda12324422200c07835f34d81c9bd3cd1b7f594b22949bef274a + languageName: node + linkType: hard + +"react-native-image-picker@npm:^8.2.1": + version: 8.2.1 + resolution: "react-native-image-picker@npm:8.2.1" peerDependencies: react: "*" react-native: "*" - checksum: 31be1a30d35b20dc72426147b3c5b8a2bf23a4666a4208208c423baec098850564e8cb555d360b87435ffe65a4f51f84e5471bf2140979c84589bd787cf5cfe0 + checksum: fc85bc278c0ba5ccef8cbacfce3001e994b34b0895be34e0c884021d2215802c2e553c5e97ff7f21a30e502be60000f90cf9555e9c2a19c71fdc76120d30e158 languageName: node linkType: hard @@ -19112,26 +19791,26 @@ __metadata: languageName: node linkType: hard -"react-native-safe-area-context@npm:^4.12.0": - version: 4.14.1 - resolution: "react-native-safe-area-context@npm:4.14.1" +"react-native-safe-area-context@npm:4.12.0": + version: 4.12.0 + resolution: "react-native-safe-area-context@npm:4.12.0" peerDependencies: react: "*" react-native: "*" - checksum: acf94ea2a30a3ec5594b467f8e0942ac48c10cbb5d34d16beba33cc0052f7c82dfd6ace754fa55f41d55143f134d3d3fa908eaf4cc9dec5743d6c4483b23520a + checksum: 04a751afed448b31dc401f0e8ecf9cf3edc4fe77b5c16cb7bc2a70381c3a2ffa54f42a313a46ad7deec0aff74a3f5650cf49db0264ba4a6c4f6a1d69ecf489fd languageName: node linkType: hard -"react-native-screens@npm:^3.34.0": - version: 3.35.0 - resolution: "react-native-screens@npm:3.35.0" +"react-native-screens@npm:~4.4.0": + version: 4.4.0 + resolution: "react-native-screens@npm:4.4.0" dependencies: react-freeze: ^1.0.0 warn-once: ^0.1.0 peerDependencies: react: "*" react-native: "*" - checksum: cb8a0c8d8a41a8a1065cc2253e4272a970366a7d80bc54e889b2f48de7ccccd3e828e2701de39c0453a67956ec0cad140fb506324cce04419b5e2eb495c038c2 + checksum: 6e90539e8eb79ba4b3fd23f6c27b943e3595c9c275b3002e6b376eb0a1c17521bde9b05d0b2c4c7ab67042f20bdbec87c3d1e3d182a531b7e3115a2dace0e912 languageName: node linkType: hard @@ -19154,18 +19833,18 @@ __metadata: languageName: node linkType: hard -"react-native@npm:^0.76.0": - version: 0.76.6 - resolution: "react-native@npm:0.76.6" +"react-native@npm:0.76.9": + version: 0.76.9 + resolution: "react-native@npm:0.76.9" dependencies: "@jest/create-cache-key-function": ^29.6.3 - "@react-native/assets-registry": 0.76.6 - "@react-native/codegen": 0.76.6 - "@react-native/community-cli-plugin": 0.76.6 - "@react-native/gradle-plugin": 0.76.6 - "@react-native/js-polyfills": 0.76.6 - "@react-native/normalize-colors": 0.76.6 - "@react-native/virtualized-lists": 0.76.6 + "@react-native/assets-registry": 0.76.9 + "@react-native/codegen": 0.76.9 + "@react-native/community-cli-plugin": 0.76.9 + "@react-native/gradle-plugin": 0.76.9 + "@react-native/js-polyfills": 0.76.9 + "@react-native/normalize-colors": 0.76.9 + "@react-native/virtualized-lists": 0.76.9 abort-controller: ^3.0.0 anser: ^1.4.9 ansi-regex: ^5.0.0 @@ -19204,7 +19883,7 @@ __metadata: optional: true bin: react-native: cli.js - checksum: c3a36bb3e5c702de63d94fe4ccb0858f34fa5d580516156b5eb0651c157b7815a04c35f76078e7c29236cba84247394ea40066012d22c54917db88bdc6c13211 + checksum: cf621cef0649920bac2b730998be6eaaf9762d516bc65d9073b46f634bb640dfb6b9b5d64ce6a6e09da64d52d114d96d96435a91c9db8ec61b76c818fe209827 languageName: node linkType: hard @@ -21968,10 +22647,10 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.6.3, tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:^2.6.2": - version: 2.6.3 - resolution: "tslib@npm:2.6.3" - checksum: 74fce0e100f1ebd95b8995fbbd0e6c91bdd8f4c35c00d4da62e285a3363aaa534de40a80db30ecfd388ed7c313c42d930ee0eaf108e8114214b180eec3dbe6f5 +"tslib@npm:2.8.1": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a languageName: node linkType: hard @@ -21982,6 +22661,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.0.1, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.4.1, tslib@npm:^2.6.2": + version: 2.6.3 + resolution: "tslib@npm:2.6.3" + checksum: 74fce0e100f1ebd95b8995fbbd0e6c91bdd8f4c35c00d4da62e285a3363aaa534de40a80db30ecfd388ed7c313c42d930ee0eaf108e8114214b180eec3dbe6f5 + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -22241,6 +22927,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.3.3": + version: 5.9.2 + resolution: "typescript@npm:5.9.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: f619cf6773cfe31409279711afd68cdf0859780006c50bc2a7a0c3227f85dea89a3b97248846326f3a17dad72ea90ec27cf61a8387772c680b2252fd02d8497b + languageName: node + linkType: hard + "typescript@npm:~5.1.6": version: 5.1.6 resolution: "typescript@npm:5.1.6" @@ -22261,6 +22957,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@^5.3.3#~builtin": + version: 5.9.2 + resolution: "typescript@patch:typescript@npm%3A5.9.2#~builtin::version=5.9.2&hash=14eedb" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: e42a701947325500008334622321a6ad073f842f5e7d5e7b588a6346b31fdf51d56082b9ce5cef24312ecd3e48d6c0d4d44da7555f65e2feec18cf62ec540385 + languageName: node + linkType: hard + "typescript@patch:typescript@~5.1.6#~builtin": version: 5.1.6 resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071"