Refactored with a new Camera Library:(react-native-vision-camera). Need fix scanQRCodeFromImage

This commit is contained in:
2024-08-12 01:14:54 +08:00
parent bfd79fbf73
commit e4cc584924
23 changed files with 265 additions and 257 deletions

View File

@@ -1,4 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.safeqr.safeqr">
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
@@ -14,9 +14,11 @@
</intent> </intent>
</queries> </queries>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="true" android:theme="@style/AppTheme"> <application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="true" android:theme="@style/AppTheme">
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/> <meta-data android:name="expo.modules.updates.ENABLED" android:value="true"/>
<meta-data android:name="expo.modules.updates.EXPO_SDK_VERSION" android:value="51.0.0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/> <meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
<meta-data android:name="expo.modules.updates.EXPO_UPDATE_URL" android:value="https://exp.host/@piggyinu/safeqr"/>
<activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait"> <activity android:name=".MainActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.SplashScreen" android:exported="true" android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -5,6 +5,7 @@
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item> <item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="android:statusBarColor">#ffffff</item> <item name="android:statusBarColor">#ffffff</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
</style> </style>
<style name="ResetEditText" parent="@android:style/Widget.EditText"> <style name="ResetEditText" parent="@android:style/Widget.EditText">
<item name="android:padding">0dp</item> <item name="android:padding">0dp</item>

View File

@@ -57,3 +57,6 @@ EX_DEV_CLIENT_NETWORK_INSPECTOR=true
# Use legacy packaging to compress native libraries in the resulting APK. # Use legacy packaging to compress native libraries in the resulting APK.
expo.useLegacyPackaging=false expo.useLegacyPackaging=false
expo.jsEngine=jsc
VisionCamera_enableCodeScanner=true

View File

@@ -9,7 +9,10 @@ export default ({ config }) => {
...config, ...config,
extra: { extra: {
API_BASE_URL: process.env.BASE_URL, API_BASE_URL: process.env.BASE_URL,
ENVIRONMENT: process.env.NODE_ENV ENVIRONMENT: process.env.NODE_ENV,
eas: {
projectId: "88ad983d-5ca3-44e6-bc1b-8a9a941af992"
}
}, },
}; };
}; };

View File

@@ -26,6 +26,17 @@
"projectId": "88ad983d-5ca3-44e6-bc1b-8a9a941af992" "projectId": "88ad983d-5ca3-44e6-bc1b-8a9a941af992"
} }
}, },
"plugins": [
[
"react-native-vision-camera",
{
"cameraPermissionText": "$(PRODUCT_NAME) needs access to your Camera.",
"enableMicrophonePermission": true,
"microphonePermissionText": "$(PRODUCT_NAME) needs access to your Microphone.",
"enableCodeScanner": true
}
]
],
"owner": "piggyinu" "owner": "piggyinu"
} }
} }

301
package-lock.json generated
View File

@@ -20,6 +20,7 @@
"@react-navigation/native": "^6.1.17", "@react-navigation/native": "^6.1.17",
"@react-navigation/stack": "^6.4.1", "@react-navigation/stack": "^6.4.1",
"@reduxjs/toolkit": "^2.2.6", "@reduxjs/toolkit": "^2.2.6",
"@zxing/library": "^0.21.2",
"aws-amplify": "^6.4.2", "aws-amplify": "^6.4.2",
"axios": "^1.7.2", "axios": "^1.7.2",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
@@ -31,7 +32,7 @@
"expo-sharing": "~12.0.1", "expo-sharing": "~12.0.1",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~1.12.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.74.3", "react-native": "0.74.5",
"react-native-dotenv": "^3.4.11", "react-native-dotenv": "^3.4.11",
"react-native-gesture-handler": "~2.16.1", "react-native-gesture-handler": "~2.16.1",
"react-native-get-random-values": "^1.11.0", "react-native-get-random-values": "^1.11.0",
@@ -40,9 +41,11 @@
"react-native-safe-area-context": "^4.10.5", "react-native-safe-area-context": "^4.10.5",
"react-native-screens": "3.31.1", "react-native-screens": "3.31.1",
"react-native-svg": "15.2.0", "react-native-svg": "15.2.0",
"react-native-vision-camera": "^4.5.1",
"react-native-webview": "^13.8.6", "react-native-webview": "^13.8.6",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"redux": "^5.0.1" "redux": "^5.0.1",
"safeqr": "file:"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
@@ -6841,9 +6844,9 @@
} }
}, },
"node_modules/@react-native/assets-registry": { "node_modules/@react-native/assets-registry": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.74.87.tgz",
"integrity": "sha512-59YmIQxfGDw4aP9S/nAM+sjSFdW8fUP6fsqczCcXgL2YVEjyER9XCaUT0J1K+PdHep8pi05KUgIKUds8P3jbmA==", "integrity": "sha512-1XmRhqQchN+pXPKEKYdpJlwESxVomJOxtEnIkbo7GAlaN2sym84fHEGDXAjLilih5GVPpcpSmFzTy8jx3LtaFg==",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
@@ -6936,14 +6939,14 @@
} }
}, },
"node_modules/@react-native/community-cli-plugin": { "node_modules/@react-native/community-cli-plugin": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.74.87.tgz",
"integrity": "sha512-ODzND33eA2owAY3g9jgCdqB+BjAh8qJ7dvmSotXgrgDYr3MJMpd8gvHTIPe2fg4Kab+wk8uipRhrE0i0RYMwtQ==", "integrity": "sha512-EgJG9lSr8x3X67dHQKQvU6EkO+3ksVlJHYIVv6U/AmW9dN80BEFxgYbSJ7icXS4wri7m4kHdgeq2PQ7/3vvrTQ==",
"dependencies": { "dependencies": {
"@react-native-community/cli-server-api": "13.6.9", "@react-native-community/cli-server-api": "13.6.9",
"@react-native-community/cli-tools": "13.6.9", "@react-native-community/cli-tools": "13.6.9",
"@react-native/dev-middleware": "0.74.85", "@react-native/dev-middleware": "0.74.87",
"@react-native/metro-babel-transformer": "0.74.85", "@react-native/metro-babel-transformer": "0.74.87",
"chalk": "^4.0.0", "chalk": "^4.0.0",
"execa": "^5.1.1", "execa": "^5.1.1",
"metro": "^0.80.3", "metro": "^0.80.3",
@@ -6957,6 +6960,37 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@react-native/community-cli-plugin/node_modules/@react-native/debugger-frontend": {
"version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.74.87.tgz",
"integrity": "sha512-MN95DJLYTv4EqJc+9JajA3AJZSBYJz2QEJ3uWlHrOky2vKrbbRVaW1ityTmaZa2OXIvNc6CZwSRSE7xCoHbXhQ==",
"engines": {
"node": ">=18"
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/@react-native/dev-middleware": {
"version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.74.87.tgz",
"integrity": "sha512-7TmZ3hTHwooYgIHqc/z87BMe1ryrIqAUi+AF7vsD+EHCGxHFdMjSpf1BZ2SUPXuLnF2cTiTfV2RwhbPzx0tYIA==",
"dependencies": {
"@isaacs/ttlcache": "^1.4.1",
"@react-native/debugger-frontend": "0.74.87",
"@rnx-kit/chromium-edge-launcher": "^1.0.0",
"chrome-launcher": "^0.15.2",
"connect": "^3.6.5",
"debug": "^2.2.0",
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
"open": "^7.0.3",
"selfsigned": "^2.4.1",
"serve-static": "^1.13.1",
"temp-dir": "^2.0.0",
"ws": "^6.2.2"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/ansi-styles": { "node_modules/@react-native/community-cli-plugin/node_modules/ansi-styles": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -7002,6 +7036,14 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}, },
"node_modules/@react-native/community-cli-plugin/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/execa": { "node_modules/@react-native/community-cli-plugin/node_modules/execa": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@@ -7062,6 +7104,11 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/@react-native/community-cli-plugin/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/@react-native/community-cli-plugin/node_modules/npm-run-path": { "node_modules/@react-native/community-cli-plugin/node_modules/npm-run-path": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@@ -7087,6 +7134,21 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@react-native/community-cli-plugin/node_modules/open": {
"version": "7.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
"integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
"dependencies": {
"is-docker": "^2.0.0",
"is-wsl": "^2.1.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@react-native/community-cli-plugin/node_modules/supports-color": { "node_modules/@react-native/community-cli-plugin/node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -7098,6 +7160,14 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@react-native/community-cli-plugin/node_modules/ws": {
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
"integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
"dependencies": {
"async-limiter": "~1.0.0"
}
},
"node_modules/@react-native/debugger-frontend": { "node_modules/@react-native/debugger-frontend": {
"version": "0.74.85", "version": "0.74.85",
"resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.74.85.tgz",
@@ -7166,28 +7236,28 @@
} }
}, },
"node_modules/@react-native/gradle-plugin": { "node_modules/@react-native/gradle-plugin": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.74.87.tgz",
"integrity": "sha512-1VQSLukJzaVMn1MYcs8Weo1nUW8xCas2XU1KuoV7OJPk6xPnEBFJmapmEGP5mWeEy7kcTXJmddEgy1wwW0tcig==", "integrity": "sha512-T+VX0N1qP+U9V4oAtn7FTX7pfsoVkd1ocyw9swYXgJqU2fK7hC9famW7b3s3ZiufPGPr1VPJe2TVGtSopBjL6A==",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@react-native/js-polyfills": { "node_modules/@react-native/js-polyfills": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.74.87.tgz",
"integrity": "sha512-gp4Rg9le3lVZeW7Cie6qLfekvRKZuhJ3LKgi1SFB4N154z1wIclypAJXVXgWBsy8JKJfTwRI+sffC4qZDlvzrg==", "integrity": "sha512-M5Evdn76CuVEF0GsaXiGi95CBZ4IWubHqwXxV9vG9CC9kq0PSkoM2Pn7Lx7dgyp4vT7ccJ8a3IwHbe+5KJRnpw==",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@react-native/metro-babel-transformer": { "node_modules/@react-native/metro-babel-transformer": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.74.87.tgz",
"integrity": "sha512-JIrXqEwhTvWPtGArgMptIPGstMdXQIkwSjKVYt+7VC4a9Pw1GurIWanIJheEW6ZuCVvTc0VZkwglFz9JVjzDjA==", "integrity": "sha512-UsJCO24sNax2NSPBmV1zLEVVNkS88kcgAiYrZHtYSwSjpl4WZ656tIeedBfiySdJ94Hr3kQmBYLipV5zk0NI1A==",
"dependencies": { "dependencies": {
"@babel/core": "^7.20.0", "@babel/core": "^7.20.0",
"@react-native/babel-preset": "0.74.85", "@react-native/babel-preset": "0.74.87",
"hermes-parser": "0.19.1", "hermes-parser": "0.19.1",
"nullthrows": "^1.1.1" "nullthrows": "^1.1.1"
}, },
@@ -7198,102 +7268,15 @@
"@babel/core": "*" "@babel/core": "*"
} }
}, },
"node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-plugin-codegen": {
"version": "0.74.85",
"resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.74.85.tgz",
"integrity": "sha512-48TSDclRB5OMXiImiJkLxyCfRyLsqkCgI8buugCZzvXcYslfV7gCvcyFyQldtcOmerV+CK4RAj7QS4hmB5Mr8Q==",
"dependencies": {
"@react-native/codegen": "0.74.85"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-preset": {
"version": "0.74.85",
"resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.74.85.tgz",
"integrity": "sha512-yMHUlN8INbK5BBwiBuQMftdWkpm1IgCsoJTKcGD2OpSgZhwwm8RUSvGhdRMzB2w7bsqqBmaEMleGtW6aCR7B9w==",
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/plugin-proposal-async-generator-functions": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.18.0",
"@babel/plugin-proposal-export-default-from": "^7.0.0",
"@babel/plugin-proposal-logical-assignment-operators": "^7.18.0",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.20.0",
"@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
"@babel/plugin-proposal-optional-chaining": "^7.20.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.0",
"@babel/plugin-syntax-export-default-from": "^7.0.0",
"@babel/plugin-syntax-flow": "^7.18.0",
"@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
"@babel/plugin-syntax-optional-chaining": "^7.0.0",
"@babel/plugin-transform-arrow-functions": "^7.0.0",
"@babel/plugin-transform-async-to-generator": "^7.20.0",
"@babel/plugin-transform-block-scoping": "^7.0.0",
"@babel/plugin-transform-classes": "^7.0.0",
"@babel/plugin-transform-computed-properties": "^7.0.0",
"@babel/plugin-transform-destructuring": "^7.20.0",
"@babel/plugin-transform-flow-strip-types": "^7.20.0",
"@babel/plugin-transform-function-name": "^7.0.0",
"@babel/plugin-transform-literals": "^7.0.0",
"@babel/plugin-transform-modules-commonjs": "^7.0.0",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
"@babel/plugin-transform-parameters": "^7.0.0",
"@babel/plugin-transform-private-methods": "^7.22.5",
"@babel/plugin-transform-private-property-in-object": "^7.22.11",
"@babel/plugin-transform-react-display-name": "^7.0.0",
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/plugin-transform-react-jsx-self": "^7.0.0",
"@babel/plugin-transform-react-jsx-source": "^7.0.0",
"@babel/plugin-transform-runtime": "^7.0.0",
"@babel/plugin-transform-shorthand-properties": "^7.0.0",
"@babel/plugin-transform-spread": "^7.0.0",
"@babel/plugin-transform-sticky-regex": "^7.0.0",
"@babel/plugin-transform-typescript": "^7.5.0",
"@babel/plugin-transform-unicode-regex": "^7.0.0",
"@babel/template": "^7.0.0",
"@react-native/babel-plugin-codegen": "0.74.85",
"babel-plugin-transform-flow-enums": "^0.0.2",
"react-refresh": "^0.14.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@babel/core": "*"
}
},
"node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/codegen": {
"version": "0.74.85",
"resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.74.85.tgz",
"integrity": "sha512-N7QwoS4Hq/uQmoH83Ewedy6D0M7xbQsOU3OMcQf0eY3ltQ7S2hd9/R4UTalQWRn1OUJfXR6OG12QJ4FStKgV6Q==",
"dependencies": {
"@babel/parser": "^7.20.0",
"glob": "^7.1.1",
"hermes-parser": "0.19.1",
"invariant": "^2.2.4",
"jscodeshift": "^0.14.0",
"mkdirp": "^0.5.1",
"nullthrows": "^1.1.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@babel/preset-env": "^7.1.6"
}
},
"node_modules/@react-native/normalize-colors": { "node_modules/@react-native/normalize-colors": {
"version": "0.74.85", "version": "0.74.85",
"resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.85.tgz",
"integrity": "sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw==" "integrity": "sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw=="
}, },
"node_modules/@react-native/virtualized-lists": { "node_modules/@react-native/virtualized-lists": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.74.87.tgz",
"integrity": "sha512-jx2Zw0qlZteoQ+0KxRc7s4drsljLBEP534FaNZ950e9+CN9nVkLsV6rigcTjDR8wjKMSBWhKf0C0C3egYz7Ehg==", "integrity": "sha512-lsGxoFMb0lyK/MiplNKJpD+A1EoEUumkLrCjH4Ht+ZlG8S0BfCxmskLZ6qXn3BiDSkLjfjI/qyZ3pnxNBvkXpQ==",
"dependencies": { "dependencies": {
"invariant": "^2.2.4", "invariant": "^2.2.4",
"nullthrows": "^1.1.1" "nullthrows": "^1.1.1"
@@ -9241,6 +9224,26 @@
} }
} }
}, },
"node_modules/@zxing/library": {
"version": "0.21.2",
"resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.21.2.tgz",
"integrity": "sha512-VMCCSUJSld3tqG6aREJ6XBCxYuoQFcjrF1kowKPFqTA6QG1ixfm6bVfD7gP4jjfM0MX20wVB65DEXtjRsBmV6w==",
"dependencies": {
"ts-custom-error": "^3.2.1"
},
"engines": {
"node": ">= 10.4.0"
},
"optionalDependencies": {
"@zxing/text-encoding": "~0.9.0"
}
},
"node_modules/@zxing/text-encoding": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz",
"integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==",
"optional": true
},
"node_modules/abort-controller": { "node_modules/abort-controller": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -15940,21 +15943,21 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}, },
"node_modules/react-native": { "node_modules/react-native": {
"version": "0.74.3", "version": "0.74.5",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.74.3.tgz", "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.74.5.tgz",
"integrity": "sha512-UFutCC6WEw6HkxlcpQ2BemKqi0JkwrgDchYB5Svi8Sp4Xwt4HA6LGEjNQgZ+3KM44bjyFRpofQym0uh0jACGng==", "integrity": "sha512-Bgg2WvxaGODukJMTZFTZBNMKVaROHLwSb8VAGEdrlvKwfb1hHg/3aXTUICYk7dwgAnb+INbGMwnF8yeAgIUmqw==",
"dependencies": { "dependencies": {
"@jest/create-cache-key-function": "^29.6.3", "@jest/create-cache-key-function": "^29.6.3",
"@react-native-community/cli": "13.6.9", "@react-native-community/cli": "13.6.9",
"@react-native-community/cli-platform-android": "13.6.9", "@react-native-community/cli-platform-android": "13.6.9",
"@react-native-community/cli-platform-ios": "13.6.9", "@react-native-community/cli-platform-ios": "13.6.9",
"@react-native/assets-registry": "0.74.85", "@react-native/assets-registry": "0.74.87",
"@react-native/codegen": "0.74.85", "@react-native/codegen": "0.74.87",
"@react-native/community-cli-plugin": "0.74.85", "@react-native/community-cli-plugin": "0.74.87",
"@react-native/gradle-plugin": "0.74.85", "@react-native/gradle-plugin": "0.74.87",
"@react-native/js-polyfills": "0.74.85", "@react-native/js-polyfills": "0.74.87",
"@react-native/normalize-colors": "0.74.85", "@react-native/normalize-colors": "0.74.87",
"@react-native/virtualized-lists": "0.74.85", "@react-native/virtualized-lists": "0.74.87",
"abort-controller": "^3.0.0", "abort-controller": "^3.0.0",
"anser": "^1.4.9", "anser": "^1.4.9",
"ansi-regex": "^5.0.0", "ansi-regex": "^5.0.0",
@@ -16132,6 +16135,29 @@
"react-native": "*" "react-native": "*"
} }
}, },
"node_modules/react-native-vision-camera": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-4.5.1.tgz",
"integrity": "sha512-ob7gfBYin4lG2zlzRr5y4rYJN3NCCyJotFX1z3ul8V0N2GwkCGh31cko6hF9DXG4VocSPVYKt+K5W0CWLp3y0g==",
"peerDependencies": {
"@shopify/react-native-skia": "*",
"react": "*",
"react-native": "*",
"react-native-reanimated": "*",
"react-native-worklets-core": "*"
},
"peerDependenciesMeta": {
"@shopify/react-native-skia": {
"optional": true
},
"react-native-reanimated": {
"optional": true
},
"react-native-worklets-core": {
"optional": true
}
}
},
"node_modules/react-native-webview": { "node_modules/react-native-webview": {
"version": "13.10.5", "version": "13.10.5",
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.10.5.tgz", "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-13.10.5.tgz",
@@ -16153,25 +16179,10 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/react-native/node_modules/@react-native/codegen": { "node_modules/react-native/node_modules/@react-native/normalize-colors": {
"version": "0.74.85", "version": "0.74.87",
"resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.87.tgz",
"integrity": "sha512-N7QwoS4Hq/uQmoH83Ewedy6D0M7xbQsOU3OMcQf0eY3ltQ7S2hd9/R4UTalQWRn1OUJfXR6OG12QJ4FStKgV6Q==", "integrity": "sha512-Xh7Nyk/MPefkb0Itl5Z+3oOobeG9lfLb7ZOY2DKpFnoCE1TzBmib9vMNdFaLdSxLIP+Ec6icgKtdzYg8QUPYzA=="
"dependencies": {
"@babel/parser": "^7.20.0",
"glob": "^7.1.1",
"hermes-parser": "0.19.1",
"invariant": "^2.2.4",
"jscodeshift": "^0.14.0",
"mkdirp": "^0.5.1",
"nullthrows": "^1.1.1"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@babel/preset-env": "^7.1.6"
}
}, },
"node_modules/react-native/node_modules/ansi-styles": { "node_modules/react-native/node_modules/ansi-styles": {
"version": "4.3.0", "version": "4.3.0",
@@ -16629,6 +16640,10 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/safeqr": {
"resolved": "",
"link": true
},
"node_modules/sax": { "node_modules/sax": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
@@ -17880,6 +17895,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/ts-custom-error": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz",
"integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==",
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/ts-interface-checker": { "node_modules/ts-interface-checker": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",

View File

@@ -24,6 +24,7 @@
"@react-navigation/native": "^6.1.17", "@react-navigation/native": "^6.1.17",
"@react-navigation/stack": "^6.4.1", "@react-navigation/stack": "^6.4.1",
"@reduxjs/toolkit": "^2.2.6", "@reduxjs/toolkit": "^2.2.6",
"@zxing/library": "^0.21.2",
"aws-amplify": "^6.4.2", "aws-amplify": "^6.4.2",
"axios": "^1.7.2", "axios": "^1.7.2",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
@@ -35,7 +36,7 @@
"expo-sharing": "~12.0.1", "expo-sharing": "~12.0.1",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~1.12.1",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.74.3", "react-native": "0.74.5",
"react-native-dotenv": "^3.4.11", "react-native-dotenv": "^3.4.11",
"react-native-gesture-handler": "~2.16.1", "react-native-gesture-handler": "~2.16.1",
"react-native-get-random-values": "^1.11.0", "react-native-get-random-values": "^1.11.0",
@@ -44,6 +45,7 @@
"react-native-safe-area-context": "^4.10.5", "react-native-safe-area-context": "^4.10.5",
"react-native-screens": "3.31.1", "react-native-screens": "3.31.1",
"react-native-svg": "15.2.0", "react-native-svg": "15.2.0",
"react-native-vision-camera": "^4.5.1",
"react-native-webview": "^13.8.6", "react-native-webview": "^13.8.6",
"react-redux": "^9.1.2", "react-redux": "^9.1.2",
"redux": "^5.0.1", "redux": "^5.0.1",

View File

@@ -1,68 +1,28 @@
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect } from 'react';
import { View, Text, StyleSheet, ActivityIndicator, TouchableOpacity, Modal, Image, Dimensions } from 'react-native'; import { View, Text, StyleSheet, TouchableOpacity, Image, Dimensions, Modal } from 'react-native';
import { Camera, CameraView, scanFromURLAsync } from 'expo-camera'; import { Camera, useCameraDevice, useCameraPermission, useCodeScanner } from 'react-native-vision-camera';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import * as ImagePicker from 'expo-image-picker'; import * as ImagePicker from 'expo-image-picker';
import ScannedDataBox from '../components/ScannedDataBox'; import ScannedDataBox from '../components/ScannedDataBox';
import { useDispatch } from 'react-redux'; import { scanQRCode } from '../api/qrCodeAPI';
import { AppDispatch } from '../store';
import { scanQRCode, getUserInfo } from '../api/qrCodeAPI';
import SettingsScreen from './SettingsScreen'; import SettingsScreen from './SettingsScreen';
const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanData }) => { const QRScannerScreen: React.FC = () => {
const navigation = useNavigation(); // Navigation hook const [isSettingsModalVisible, setIsSettingsModalVisible] = useState<boolean>(false);
const dispatch = useDispatch<AppDispatch>(); // Use dispatch for Redux actions const [enableTorch, setEnableTorch] = useState<boolean>(false);
// State variables
const [showSplash, setShowSplash] = useState<boolean>(true); // State for splash screen visibility
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [scanned, setScanned] = useState<boolean>(false); const [scanned, setScanned] = useState<boolean>(false);
const [qrCodeId, setQRCodeId] = useState<string | null>(null); // State for QR code ID const [qrCodeId, setQRCodeId] = useState<string | null>(null); // State for QR code ID
const [enableTorch, setEnableTorch] = useState<boolean>(false); // State for torch const [isScannedDataBoxVisible, setIsScannedDataBoxVisible] = useState<boolean>(false); // State for ScannedDataBox visibility
const [cameraVisible, setCameraVisible] = useState<boolean>(true); // State to control camera visibility
const [isScannedDataBoxVisible, setIsScannedDataBoxVisible] = useState<boolean>(false); // State for ScannedDataBox modal visibility const { hasPermission, requestPermission } = useCameraPermission();
const [isSettingsModalVisible, setIsSettingsModalVisible] = useState<boolean>(false); // State for modal visibility const device = useCameraDevice('back');
// Request Camera Permission and initialize the app
useEffect(() => { useEffect(() => {
const initializeApp = async () => { requestPermission();
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === 'granted');
setShowSplash(false);
console.log("Camera permissions initialized");
// Fetch and log user information
fetchUserInformation();
};
initializeApp();
}, []); }, []);
// Focus effect to enable camera and clear data on focus
useFocusEffect(
useCallback(() => {
setCameraVisible(true);
clearScanDataInternal();
console.log("Screen focused, scan data cleared and camera enabled");
return () => {
setCameraVisible(false);
console.log("Screen unfocused, camera disabled");
};
}, [navigation])
);
// Clear Scan Data
const clearScanDataInternal = () => {
setScanned(false);
setQRCodeId(null);
console.log("Scan data cleared");
};
// Handle scanning of payload (QR code data) and get the QR-ID
const handlePayload = async (payload: string) => { const handlePayload = async (payload: string) => {
setScanned(true); setScanned(true);
console.info("Decoded QR Code, Payload is: ", payload); console.info("Decoded QR Code, Payload is: ", payload);
@@ -72,48 +32,36 @@ const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanDat
const qrCodeId = response.qrcode.data.id; const qrCodeId = response.qrcode.data.id;
// Store the QR code ID for later use // Store the QR code ID for later use
setQRCodeId(qrCodeId); setQRCodeId(qrCodeId);
setIsScannedDataBoxVisible(true); // Show ScannedDataBox modal setIsScannedDataBoxVisible(true); // Show ScannedDataBox pop-up
// Optionally, show a message or perform another action
console.log("QR code scanned successfully, ID:", qrCodeId); console.log("QR code scanned successfully, ID:", qrCodeId);
} catch (error) { } catch (error) {
console.error("Error scanning QR code:", error); console.error("Error scanning QR code:", error);
} }
}; };
// Fetch and log user information const codeScanner = useCodeScanner({
const fetchUserInformation = async () => { codeTypes: ['qr'], // Only scan QR codes
try { onCodeScanned: (codes) => {
const userInfo = await getUserInfo(); if (!scanned) {
console.log('User Info:', userInfo); handlePayload(codes[0]?.value); // Extract and handle the value only
} catch (error) {
console.error('Error fetching user information:', error);
} }
}; }
});
// Toggle torch (flashlight) on/off
const toggleTorch = () => {
setEnableTorch((prev) => !prev);
console.log("Torch toggled:", enableTorch ? "off" : "on");
};
// Read QR from image
const readQRFromImage = async () => {
clearScanDataInternal();
console.log("Reading QR code from image");
const openImagePicker = async () => {
const result = await ImagePicker.launchImageLibraryAsync({ const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images, mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: false, // Don't ask user to crop images allowsEditing: false,
quality: 1, quality: 1,
}); });
if (result && result.assets && result.assets.length > 0 && result.assets[0].uri) { // Ensure the uri is not empty if (!result.canceled && result.assets.length > 0) {
const { uri } = result.assets[0];
try { try {
const scannedResult = await scanFromURLAsync(result.assets[0].uri); // If using expo-camera or similar packages:
if (scannedResult && scannedResult[0] && scannedResult[0].data) { const scannedResult = await scanQRCodeFromURL(uri); // Function to scan QR code from the selected image URL
handlePayload(scannedResult[0].data); if (scannedResult) {
console.log('QR code data from image:', scannedResult[0].data); handlePayload(scannedResult);
} else { } else {
console.log("No QR code found in the selected image"); console.log("No QR code found in the selected image");
} }
@@ -123,21 +71,27 @@ const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanDat
} }
}; };
// Conditional rendering based on state const scanQRCodeFromURL = async (uri: string) => {
if (showSplash) { // This method can vary depending on the package used for scanning
return ( // For example, using expo-camera or other available options to scan QR code from an image URL
<View style={styles.splashContainer}> // Implement scanFromURLAsync if using expo-camera
<ActivityIndicator size="large" color="#ff69b4" />
</View> // If using expo-camera
); // const scannedResult = await scanFromURLAsync(uri);
// return scannedResult?.[0]?.data;
// If using other methods, implement them accordingly
// Here we simulate scanning with a placeholder result
const placeholderResult = "SIMULATED_PAYLOAD"; // Replace with actual scanning logic
return placeholderResult;
};
if (!hasPermission) {
return <Text>Requesting camera permission...</Text>;
} }
if (hasPermission === null) { if (!device) {
return <Text>Requesting for camera permission</Text>; return <Text>Loading camera...</Text>;
}
if (hasPermission === false) {
return <Text>No access to camera</Text>;
} }
return ( return (
@@ -147,33 +101,44 @@ const QRScannerScreen: React.FC<{ clearScanData: () => void }> = ({ clearScanDat
<Text style={styles.welcomeText}>Please point the camera at the QR Code</Text> <Text style={styles.welcomeText}>Please point the camera at the QR Code</Text>
<View style={styles.cameraContainer}> <View style={styles.cameraContainer}>
{cameraVisible && ( {device && (
<CameraView <Camera
onBarcodeScanned={scanned ? undefined : ({ data, type }) => { style={StyleSheet.absoluteFill}
console.log("Barcode Type:", type); // Log the type of barcode scanned device={device}
console.log("Raw Scanned Barcode Data:", data); // Log the raw barcode data isActive={true}
handlePayload(data); torch={enableTorch ? 'on' : 'off'}
}} codeScanner={codeScanner}
style={styles.camera}
enableTorch={enableTorch}
/> />
)} )}
<TouchableOpacity onPress={toggleTorch} style={styles.flashButton}> {/* Torch Button */}
<Ionicons name="flashlight" size={screenWidth * 0.06} color="#fff" /> <TouchableOpacity
onPress={() => device.hasFlash && setEnableTorch((prev) => !prev)}
style={styles.flashButton}
disabled={!device.hasFlash}
>
<Ionicons
name={device.hasFlash ? 'flashlight' : 'flashlight-outline'}
size={screenWidth * 0.06}
color={device.hasFlash ? "#fff" : "#888"}
/>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={readQRFromImage} style={styles.galleryButton}>
{/* Gallery Button */}
<TouchableOpacity onPress={openImagePicker} style={styles.galleryButton}>
<Ionicons name="image" size={screenWidth * 0.06} color="#fff" /> <Ionicons name="image" size={screenWidth * 0.06} color="#fff" />
</TouchableOpacity> </TouchableOpacity>
</View> </View>
{/* Scanned Data Box */} {/* Scanned Data Box as a pop-up */}
{isScannedDataBoxVisible && ( {isScannedDataBoxVisible && (
<View style={styles.scannedDataBoxPopup}> <View style={styles.scannedDataBoxPopup}>
<ScannedDataBox <ScannedDataBox
qrCodeId={qrCodeId} qrCodeId={qrCodeId!}
clearScanData={() => setIsScannedDataBoxVisible(false)} clearScanData={() => {
setScanned(false);
setIsScannedDataBoxVisible(false);
}}
/> />
</View> </View>
)} )}
@@ -230,7 +195,7 @@ const styles = StyleSheet.create({
color: 'black', color: 'black',
}, },
cameraContainer: { cameraContainer: {
height: '60%', height: '50%',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
borderRadius: 10, borderRadius: 10,
@@ -286,8 +251,6 @@ const styles = StyleSheet.create({
padding: screenWidth * 0.025, padding: screenWidth * 0.025,
elevation: 5, elevation: 5,
}, },
settingsModal: { settingsModal: {
backgroundColor: 'rgba(0, 0, 0, 0.5)', // Semi-transparent background backgroundColor: 'rgba(0, 0, 0, 0.5)', // Semi-transparent background
}, },