react-native-modern-qrscanner
Advanced tools
| import groovy.json.JsonSlurper | ||
| def computeVersionName() { | ||
| // dynamically retrieve version from package.json | ||
| def slurper = new JsonSlurper() | ||
| def json = slurper.parse(file('../package.json'), "utf-8") | ||
| return json.version | ||
| } | ||
| buildscript { | ||
| repositories { | ||
| jcenter() | ||
| google() | ||
| maven { | ||
| url 'https://maven.google.com/' | ||
| name 'Google' | ||
| } | ||
| } | ||
| dependencies { | ||
| classpath 'com.android.tools.build:gradle:7.2.1' | ||
| } | ||
| } | ||
| apply plugin: 'com.android.library' | ||
| android { | ||
| compileSdkVersion 31 | ||
| buildToolsVersion "31.0.0" | ||
| defaultConfig { | ||
| minSdkVersion 23 | ||
| targetSdkVersion 31 | ||
| versionCode 1 | ||
| versionName computeVersionName() | ||
| } | ||
| lintOptions { | ||
| abortOnError false | ||
| } | ||
| } | ||
| repositories { | ||
| mavenCentral() | ||
| google() | ||
| maven { | ||
| url "$projectDir/../Example/node_modules/react-native/android" | ||
| } | ||
| maven { | ||
| url "$projectDir/../../react-native/android" | ||
| } | ||
| maven { | ||
| url 'https://maven.google.com/' | ||
| name 'Google' | ||
| } | ||
| } | ||
| dependencies { | ||
| implementation 'com.facebook.react:react-native:+' | ||
| implementation 'com.google.zxing:core:3.4.0' | ||
| implementation 'com.google.mlkit:barcode-scanning:16.2.0' | ||
| } |
| # Project-wide Gradle settings. | ||
| # IDE (e.g. Android Studio) users: | ||
| # Gradle settings configured through the IDE *will override* | ||
| # any settings specified in this file. | ||
| # For more details on how to configure your build environment visit | ||
| # http://www.gradle.org/docs/current/userguide/build_environment.html | ||
| # Specifies the JVM arguments used for the daemon process. | ||
| # The setting is particularly useful for tweaking memory settings. | ||
| org.gradle.jvmargs=-Xmx1536m | ||
| # When configured, Gradle will run in incubating parallel mode. | ||
| # This option should only be used with decoupled projects. More details, visit | ||
| # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | ||
| # org.gradle.parallel=true |
Sorry, the diff of this file is not supported yet
| #Thu Dec 19 23:53:01 IST 2019 | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip |
Sorry, the diff of this file is not supported yet
| @if "%DEBUG%" == "" @echo off | ||
| @rem ########################################################################## | ||
| @rem | ||
| @rem Gradle startup script for Windows | ||
| @rem | ||
| @rem ########################################################################## | ||
| @rem Set local scope for the variables with windows NT shell | ||
| if "%OS%"=="Windows_NT" setlocal | ||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||
| set DEFAULT_JVM_OPTS= | ||
| set DIRNAME=%~dp0 | ||
| if "%DIRNAME%" == "" set DIRNAME=. | ||
| set APP_BASE_NAME=%~n0 | ||
| set APP_HOME=%DIRNAME% | ||
| @rem Find java.exe | ||
| if defined JAVA_HOME goto findJavaFromJavaHome | ||
| set JAVA_EXE=java.exe | ||
| %JAVA_EXE% -version >NUL 2>&1 | ||
| if "%ERRORLEVEL%" == "0" goto init | ||
| echo. | ||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||
| echo. | ||
| echo Please set the JAVA_HOME variable in your environment to match the | ||
| echo location of your Java installation. | ||
| goto fail | ||
| :findJavaFromJavaHome | ||
| set JAVA_HOME=%JAVA_HOME:"=% | ||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||
| if exist "%JAVA_EXE%" goto init | ||
| echo. | ||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||
| echo. | ||
| echo Please set the JAVA_HOME variable in your environment to match the | ||
| echo location of your Java installation. | ||
| goto fail | ||
| :init | ||
| @rem Get command-line arguments, handling Windowz variants | ||
| if not "%OS%" == "Windows_NT" goto win9xME_args | ||
| if "%@eval[2+2]" == "4" goto 4NT_args | ||
| :win9xME_args | ||
| @rem Slurp the command line arguments. | ||
| set CMD_LINE_ARGS= | ||
| set _SKIP=2 | ||
| :win9xME_args_slurp | ||
| if "x%~1" == "x" goto execute | ||
| set CMD_LINE_ARGS=%* | ||
| goto execute | ||
| :4NT_args | ||
| @rem Get arguments from the 4NT Shell from JP Software | ||
| set CMD_LINE_ARGS=%$ | ||
| :execute | ||
| @rem Setup the command line | ||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||
| @rem Execute Gradle | ||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | ||
| :end | ||
| @rem End local scope for the variables with windows NT shell | ||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||
| :fail | ||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||
| rem the _cmd.exe /c_ return code! | ||
| if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||
| exit /b 1 | ||
| :mainEnd | ||
| if "%OS%"=="Windows_NT" endlocal | ||
| :omega |
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
| package="com.npmhub.qrcode"> | ||
| </manifest> |
| package com.npmhub.qrcode; | ||
| import android.net.Uri; | ||
| import android.util.Log; | ||
| import androidx.annotation.NonNull; | ||
| import com.facebook.react.bridge.Promise; | ||
| import com.facebook.react.bridge.ReactApplicationContext; | ||
| import com.facebook.react.bridge.ReactContextBaseJavaModule; | ||
| import com.facebook.react.bridge.ReactMethod; | ||
| import com.google.android.gms.tasks.OnFailureListener; | ||
| import com.google.android.gms.tasks.OnSuccessListener; | ||
| import com.google.android.gms.tasks.Task; | ||
| import com.google.mlkit.vision.barcode.Barcode; | ||
| import com.google.mlkit.vision.barcode.BarcodeScanner; | ||
| import com.google.mlkit.vision.barcode.BarcodeScannerOptions; | ||
| import com.google.mlkit.vision.barcode.BarcodeScanning; | ||
| import com.google.mlkit.vision.common.InputImage; | ||
| import java.io.IOException; | ||
| import java.util.LinkedList; | ||
| import java.util.List; | ||
| public class QRScanReader extends ReactContextBaseJavaModule { | ||
| public QRScanReader(ReactApplicationContext reactContext) { | ||
| super(reactContext); | ||
| } | ||
| @Override | ||
| public String getName() { | ||
| return "QRScanReader"; | ||
| } | ||
| @ReactMethod | ||
| public void readerQR(String fileUrl, final Promise promise ) { | ||
| // ML Vision : https://developers.google.com/ml-kit/vision/barcode-scanning/android#java | ||
| try { | ||
| Uri uri = Uri.parse(fileUrl); | ||
| InputImage image = InputImage.fromFilePath(this.getReactApplicationContext(), uri); | ||
| BarcodeScannerOptions options = new BarcodeScannerOptions.Builder() | ||
| .setBarcodeFormats( | ||
| Barcode.FORMAT_AZTEC, | ||
| Barcode.FORMAT_QR_CODE | ||
| ) | ||
| .build(); | ||
| final BarcodeScanner scanner = BarcodeScanning.getClient(options); | ||
| Task<List<Barcode>> result = scanner.process(image) | ||
| .addOnSuccessListener(new OnSuccessListener<List<Barcode>>() { | ||
| @Override | ||
| public void onSuccess(List<Barcode> barcodes) { | ||
| Log.d("OK", " " + barcodes.toString()); | ||
| List<String> rawValues = new LinkedList<>(); | ||
| for (Barcode barcode: barcodes) { | ||
| String rawValue = barcode.getRawValue(); | ||
| rawValues.add(rawValue); | ||
| } | ||
| scanner.close(); | ||
| if (!rawValues.isEmpty()){ | ||
| promise.resolve(rawValues.get(0)); | ||
| } else { | ||
| promise.reject("NOT_OK", "Invalid or No related QR code"); | ||
| } | ||
| } | ||
| }) | ||
| .addOnFailureListener(new OnFailureListener() { | ||
| @Override | ||
| public void onFailure(@NonNull Exception e) { | ||
| Log.d("NOT_OK", "" + e.getMessage()); | ||
| scanner.close(); | ||
| promise.reject("NOT_OK", e.getMessage()); | ||
| } | ||
| }); | ||
| } catch (IOException e) { | ||
| Log.e("ERROR", "" + e.getMessage()); | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
| } |
| package com.npmhub.qrcode; | ||
| import com.facebook.react.ReactPackage; | ||
| import com.facebook.react.bridge.NativeModule; | ||
| import com.facebook.react.bridge.ReactApplicationContext; | ||
| import com.facebook.react.uimanager.ViewManager; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.List; | ||
| public class QRScanReaderPackage implements ReactPackage { | ||
| @Override | ||
| public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { | ||
| List<NativeModule> modules = new ArrayList<>(); | ||
| modules.add(new QRScanReader(reactContext)); | ||
| return modules; | ||
| } | ||
| @Override | ||
| public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { | ||
| return Collections.emptyList(); | ||
| } | ||
| } |
| <?xml version="1.0" encoding="utf-8"?> | ||
| <resources> | ||
| <color name="colorPrimary">#3F51B5</color> | ||
| <color name="colorPrimaryDark">#303F9F</color> | ||
| <color name="colorAccent">#FF4081</color> | ||
| </resources> |
| <resources> | ||
| <string name="app_name">My Application</string> | ||
| </resources> |
| <resources> | ||
| <!-- Base application theme. --> | ||
| <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | ||
| <!-- Customize your theme here. --> | ||
| <item name="colorPrimary">@color/colorPrimary</item> | ||
| <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ||
| <item name="colorAccent">@color/colorAccent</item> | ||
| </style> | ||
| </resources> |
| package com.npmhub.qrcode; | ||
| import org.junit.Test; | ||
| import static org.junit.Assert.*; | ||
| /** | ||
| * Example local unit test, which will execute on the development machine (host). | ||
| * | ||
| * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | ||
| */ | ||
| public class ExampleUnitTest { | ||
| @Test | ||
| public void addition_isCorrect() throws Exception { | ||
| assertEquals(4, 2 + 2); | ||
| } | ||
| } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <key>IDEDidComputeMac32BitWarning</key> | ||
| <true/> | ||
| </dict> | ||
| </plist> |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
| <plist version="1.0"> | ||
| <dict> | ||
| <key>SchemeUserState</key> | ||
| <dict> | ||
| <key>ModernQRScanner.xcscheme_^#shared#^_</key> | ||
| <dict> | ||
| <key>orderHint</key> | ||
| <integer>0</integer> | ||
| </dict> | ||
| </dict> | ||
| <key>SuppressBuildableAutocreation</key> | ||
| <dict> | ||
| <key>F37610FB2B6101DA00275D16</key> | ||
| <dict> | ||
| <key>primary</key> | ||
| <true/> | ||
| </dict> | ||
| </dict> | ||
| </dict> | ||
| </plist> |
| #import <React/RCTBridgeModule.h> | ||
| @interface ModernQRScanner : NSObject <RCTBridgeModule> | ||
| - (void)getOrientation:(RCTResponseSenderBlock)callback; | ||
| - (void)lockToPortrait; | ||
| - (void)lockToLandscape; | ||
| - (void)unlockAllOrientations; | ||
| @end | ||
| #import "ModernQRScanner.h" | ||
| #import <UIKit/UIKit.h> | ||
| @implementation ModernQRScanner | ||
| RCT_EXPORT_MODULE(); | ||
| RCT_EXPORT_METHOD(getOrientation:(RCTResponseSenderBlock)callback) { | ||
| UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; | ||
| NSString *orientationString; | ||
| switch (orientation) { | ||
| case UIDeviceOrientationPortrait: | ||
| orientationString = @"PORTRAIT"; | ||
| break; | ||
| case UIDeviceOrientationLandscapeLeft: | ||
| case UIDeviceOrientationLandscapeRight: | ||
| orientationString = @"LANDSCAPE"; | ||
| break; | ||
| default: | ||
| orientationString = @"UNKNOWN"; | ||
| break; | ||
| } | ||
| callback(@[[NSNull null], orientationString]); | ||
| } | ||
| RCT_EXPORT_METHOD(lockToPortrait) { | ||
| dispatch_async(dispatch_get_main_queue(), ^{ | ||
| [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationPortrait) forKey:@"orientation"]; | ||
| }); | ||
| } | ||
| RCT_EXPORT_METHOD(lockToLandscape) { | ||
| dispatch_async(dispatch_get_main_queue(), ^{ | ||
| [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationLandscapeRight) forKey:@"orientation"]; | ||
| }); | ||
| } | ||
| RCT_EXPORT_METHOD(unlockAllOrientations) { | ||
| dispatch_async(dispatch_get_main_queue(), ^{ | ||
| [[UIDevice currentDevice] setValue:@(UIInterfaceOrientationUnknown) forKey:@"orientation"]; | ||
| }); | ||
| } | ||
| - (UIInterfaceOrientationMask)getOrientationMask { | ||
| UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; | ||
| switch (orientation) { | ||
| case UIDeviceOrientationPortrait: | ||
| case UIDeviceOrientationPortraitUpsideDown: | ||
| return UIInterfaceOrientationMaskPortrait; | ||
| case UIDeviceOrientationLandscapeLeft: | ||
| case UIDeviceOrientationLandscapeRight: | ||
| return UIInterfaceOrientationMaskLandscape; | ||
| default: | ||
| return UIInterfaceOrientationMaskAll; | ||
| } | ||
| } | ||
| @end | ||
+21
| MIT License | ||
| Copyright (c) 2024 Jerry Lee | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| import React, { PureComponent } from "react"; | ||
| import { RNCamera } from "react-native-camera"; | ||
| import PropTypes from "prop-types"; | ||
| import { | ||
| StyleSheet, | ||
| View, | ||
| Text, | ||
| Image, | ||
| Vibration, | ||
| Platform, | ||
| PixelRatio, | ||
| StatusBar | ||
| } from "react-native"; | ||
| import ModernQRScannerView from "./ModernQRScannerView"; | ||
| const pixelRatio = PixelRatio.get(); | ||
| /** | ||
| * Scan interface | ||
| */ | ||
| export default class ModernQRScanner extends PureComponent { | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { | ||
| scanning: false, | ||
| barCodeSize: {} | ||
| }; | ||
| } | ||
| static defaultProps = { | ||
| onRead: () => {}, | ||
| renderTopView: () => {}, | ||
| renderBottomView: () => ( | ||
| <View style={{ flex: 1, backgroundColor: "#0000004D" }} /> | ||
| ), | ||
| rectHeight: 200, | ||
| rectWidth: 200, | ||
| flashMode: false, // Flashlight mode | ||
| finderX: 0, // Viewfinder X-axis offset | ||
| finderY: 0, // Viewfinder Y-axis offset | ||
| zoom: 0.2, // Zoom range 0 - 1 | ||
| translucent: false, | ||
| isRepeatScan: false, | ||
| cameraType: "back", | ||
| notAuthorizedView: () => ( | ||
| <View style={styles.authorizationContainer}> | ||
| <Text style={styles.notAuthorizedText}>Camera not authorized</Text> | ||
| </View> | ||
| ), | ||
| vibrate: true, | ||
| }; | ||
| render() { | ||
| return ( | ||
| <View | ||
| style={{ | ||
| flex: 1 | ||
| }} | ||
| > | ||
| <RNCamera | ||
| style={{ | ||
| flex: 1 | ||
| }} | ||
| captureAudio={false} | ||
| onBarCodeRead={this._handleBarCodeRead} | ||
| androidCameraPermissionOptions={null} | ||
| androidRecordAudioPermissionOptions={null} | ||
| notAuthorizedView={this.props.notAuthorizedView()} | ||
| barCodeTypes={[RNCamera.Constants.BarCodeType.qr]} | ||
| flashMode={ | ||
| !this.props.flashMode | ||
| ? RNCamera.Constants.FlashMode.off | ||
| : RNCamera.Constants.FlashMode.torch | ||
| } | ||
| zoom={this.props.zoom} | ||
| type={this.props.cameraType} | ||
| > | ||
| <View style={[styles.topButtonsContainer, this.props.topViewStyle]}> | ||
| {this.props.renderTopView()} | ||
| </View> | ||
| <ModernQRScannerView | ||
| maskColor={this.props.maskColor} | ||
| cornerColor={this.props.cornerColor} | ||
| borderColor={this.props.borderColor} | ||
| rectHeight={this.props.rectHeight} | ||
| rectWidth={this.props.rectWidth} | ||
| borderWidth={this.props.borderWidth} | ||
| cornerBorderWidth={this.props.cornerBorderWidth} | ||
| cornerBorderLength={this.props.cornerBorderLength} | ||
| cornerOffsetSize={this.props.cornerOffsetSize} | ||
| isCornerOffset={this.props.isCornerOffset} | ||
| bottomHeight={this.props.bottomHeight} | ||
| scanBarAnimateTime={this.props.scanBarAnimateTime} | ||
| scanBarColor={this.props.scanBarColor} | ||
| scanBarHeight={this.props.scanBarHeight} | ||
| scanBarMargin={this.props.scanBarMargin} | ||
| hintText={this.props.hintText} | ||
| hintTextStyle={this.props.hintTextStyle} | ||
| scanBarImage={this.props.scanBarImage} | ||
| hintTextPosition={this.props.hintTextPosition} | ||
| isShowScanBar={this.props.isShowScanBar} | ||
| finderX={this.props.finderX} | ||
| finderY={this.props.finderY} | ||
| returnSize={this.barCodeSize} | ||
| /> | ||
| <View | ||
| style={[styles.bottomButtonsContainer, this.props.bottomViewStyle]} | ||
| > | ||
| {this.props.renderBottomView()} | ||
| </View> | ||
| </RNCamera> | ||
| </View> | ||
| ); | ||
| } | ||
| isShowCode = false; | ||
| barCodeSize = size => this.setState({ barCodeSize: size }); | ||
| returnMax = (a, b) => (a > b ? a : b); | ||
| returnMin = (a, b) => (a < b ? a : b); | ||
| iosBarCode = e => { | ||
| let x = Number(e.bounds.origin.x); | ||
| let y = Number(e.bounds.origin.y); | ||
| let width = e.bounds.size.width; | ||
| let height = e.bounds.size.height; | ||
| let viewMinX = this.state.barCodeSize.x - this.props.finderX; | ||
| let viewMinY = this.state.barCodeSize.y - this.props.finderY; | ||
| let viewMaxX = | ||
| this.state.barCodeSize.x + | ||
| this.state.barCodeSize.width - | ||
| width - | ||
| this.props.finderX; | ||
| let viewMaxY = | ||
| this.state.barCodeSize.y + | ||
| this.state.barCodeSize.height - | ||
| height - | ||
| this.props.finderY; | ||
| if (x > viewMinX && y > viewMinY && x < viewMaxX && y < viewMaxY) { | ||
| if (this.props.isRepeatScan) { | ||
| if (this.props.vibrate) { | ||
| Vibration.vibrate(); | ||
| } | ||
| this.props.onRead(e); | ||
| } else { | ||
| if (!this.isShowCode) { | ||
| this.isShowCode = true; | ||
| if (this.props.vibrate) { | ||
| Vibration.vibrate(); | ||
| } | ||
| this.props.onRead(e); | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| androidBarCode = e => { | ||
| if (this.props.isRepeatScan) { | ||
| Vibration.vibrate(); | ||
| this.props.onRead(e); | ||
| } else { | ||
| if (!this.isShowCode) { | ||
| this.isShowCode = true; | ||
| Vibration.vibrate(); | ||
| this.props.onRead(e); | ||
| } | ||
| } | ||
| }; | ||
| _handleBarCodeRead = e => { | ||
| switch (Platform.OS) { | ||
| case "ios": | ||
| this.iosBarCode(e); | ||
| break; | ||
| case "android": | ||
| this.androidBarCode(e); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| }; | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| topButtonsContainer: { | ||
| position: "absolute", | ||
| height: 100, | ||
| top: 0, | ||
| left: 0, | ||
| right: 0 | ||
| }, | ||
| bottomButtonsContainer: { | ||
| position: "absolute", | ||
| height: 100, | ||
| bottom: 0, | ||
| left: 0, | ||
| right: 0 | ||
| }, | ||
| authorizationContainer: { | ||
| flex: 1, | ||
| alignItems: "center", | ||
| justifyContent: "center" | ||
| }, | ||
| notAuthorizedText: { | ||
| textAlign: "center", | ||
| fontSize: 16 | ||
| } | ||
| }); | ||
| ModernQRScanner.propTypes = { | ||
| isRepeatScan: PropTypes.bool, | ||
| onRead: PropTypes.func, | ||
| maskColor: PropTypes.string, | ||
| borderColor: PropTypes.string, | ||
| cornerColor: PropTypes.string, | ||
| borderWidth: PropTypes.number, | ||
| cornerBorderWidth: PropTypes.number, | ||
| cornerBorderLength: PropTypes.number, | ||
| rectHeight: PropTypes.number, | ||
| rectWidth: PropTypes.number, | ||
| isCornerOffset: PropTypes.bool, //Whether the corners are offset | ||
| cornerOffsetSize: PropTypes.number, | ||
| bottomHeight: PropTypes.number, | ||
| scanBarAnimateTime: PropTypes.number, | ||
| scanBarColor: PropTypes.string, | ||
| scanBarImage: PropTypes.any, | ||
| scanBarHeight: PropTypes.number, | ||
| scanBarMargin: PropTypes.number, | ||
| hintText: PropTypes.string, | ||
| hintTextStyle: PropTypes.object, | ||
| hintTextPosition: PropTypes.number, | ||
| renderTopView: PropTypes.func, | ||
| renderBottomView: PropTypes.func, | ||
| isShowScanBar: PropTypes.bool, | ||
| topViewStyle: PropTypes.object, | ||
| bottomViewStyle: PropTypes.object, | ||
| flashMode: PropTypes.bool, | ||
| finderX: PropTypes.number, | ||
| finderY: PropTypes.number, | ||
| zoom: PropTypes.number, | ||
| translucent: PropTypes.bool, | ||
| cameraType: PropTypes.string, | ||
| vibrate: PropTypes.bool, | ||
| }; |
| import React, { PureComponent } from "react"; | ||
| import { RNCamera } from "react-native-camera"; | ||
| import { StyleSheet, View, Text, Image, Vibration, Platform, PixelRatio, StatusBar } from "react-native"; | ||
| import ModernQRScannerView from "./ModernQRScannerView"; | ||
| export default class ModernQRScanner extends PureComponent { | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { | ||
| scanning: false, | ||
| barCodeSize: {} | ||
| }; | ||
| } | ||
| static defaultProps = { | ||
| onRead: () => {}, | ||
| renderTopView: () => {}, | ||
| renderBottomView: () => ( | ||
| <View style={{ flex: 1, backgroundColor: "#0000004D" }} /> | ||
| ), | ||
| rectHeight: 200, | ||
| rectWidth: 200, | ||
| flashMode: false, | ||
| finderX: 0, | ||
| finderY: 0, | ||
| zoom: 0.2, // Zoom range 0 - 1 | ||
| translucent: false, | ||
| isRepeatScan: false, | ||
| cameraType: "back", | ||
| notAuthorizedView: () => ( | ||
| <View style={styles.authorizationContainer}> | ||
| <Text style={styles.notAuthorizedText}>Camera not authorized</Text> | ||
| </View> | ||
| ), | ||
| vibrate: true, | ||
| }; | ||
| renderCamera = () => ( | ||
| <RNCamera | ||
| style={styles.cameraStyle} | ||
| captureAudio={false} | ||
| onBarCodeRead={this._handleBarCodeRead} | ||
| androidCameraPermissionOptions={null} | ||
| androidRecordAudioPermissionOptions={null} | ||
| notAuthorizedView={this.props.notAuthorizedView()} | ||
| barCodeTypes={[RNCamera.Constants.BarCodeType.qr]} | ||
| flashMode={this.props.flashMode ? RNCamera.Constants.FlashMode.torch : RNCamera.Constants.FlashMode.off} | ||
| zoom={this.props.zoom} | ||
| type={this.props.cameraType} | ||
| > | ||
| {this.renderCameraContent()} | ||
| </RNCamera> | ||
| ); | ||
| renderCameraContent = () => ( | ||
| <> | ||
| <View style={[styles.topButtonsContainer, this.props.topViewStyle]}> | ||
| {this.props.renderTopView()} | ||
| </View> | ||
| <ModernQRScannerView {...this.props} returnSize={this.barCodeSize} /> | ||
| <View style={[styles.bottomButtonsContainer, this.props.bottomViewStyle]}> | ||
| {this.props.renderBottomView()} | ||
| </View> | ||
| </> | ||
| ); | ||
| render() { | ||
| return <View style={styles.container}>{this.renderCamera()}</View>; | ||
| } | ||
| isShowCode = false; | ||
| barCodeSize = size => this.setState({ barCodeSize: size }); | ||
| returnMax = (a, b) => (a > b ? a : b); | ||
| returnMin = (a, b) => (a < b ? a : b); | ||
| iosBarCode = e => { | ||
| let x = Number(e.bounds.origin.x); | ||
| let y = Number(e.bounds.origin.y); | ||
| let width = e.bounds.size.width; | ||
| let height = e.bounds.size.height; | ||
| let viewMinX = this.state.barCodeSize.x - this.props.finderX; | ||
| let viewMinY = this.state.barCodeSize.y - this.props.finderY; | ||
| let viewMaxX = | ||
| this.state.barCodeSize.x + | ||
| this.state.barCodeSize.width - | ||
| width - | ||
| this.props.finderX; | ||
| let viewMaxY = | ||
| this.state.barCodeSize.y + | ||
| this.state.barCodeSize.height - | ||
| height - | ||
| this.props.finderY; | ||
| if (x > viewMinX && y > viewMinY && x < viewMaxX && y < viewMaxY) { | ||
| if (this.props.isRepeatScan) { | ||
| if (this.props.vibrate) { | ||
| Vibration.vibrate(); | ||
| } | ||
| this.props.onRead(e); | ||
| } else { | ||
| if (!this.isShowCode) { | ||
| this.isShowCode = true; | ||
| if (this.props.vibrate) { | ||
| Vibration.vibrate(); | ||
| } | ||
| this.props.onRead(e); | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| androidBarCode = e => { | ||
| if (this.props.isRepeatScan) { | ||
| Vibration.vibrate(); | ||
| this.props.onRead(e); | ||
| } else { | ||
| if (!this.isShowCode) { | ||
| this.isShowCode = true; | ||
| Vibration.vibrate(); | ||
| this.props.onRead(e); | ||
| } | ||
| } | ||
| }; | ||
| _handleBarCodeRead = e => { | ||
| switch (Platform.OS) { | ||
| case "ios": | ||
| this.iosBarCode(e); | ||
| break; | ||
| case "android": | ||
| this.androidBarCode(e); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| }; | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| flex: 1, | ||
| }, | ||
| cameraStyle: { | ||
| flex: 1, | ||
| }, | ||
| topButtonsContainer: { | ||
| position: "absolute", | ||
| height: 100, | ||
| top: 0, | ||
| left: 0, | ||
| right: 0, | ||
| }, | ||
| bottomButtonsContainer: { | ||
| position: "absolute", | ||
| height: 100, | ||
| bottom: 0, | ||
| left: 0, | ||
| right: 0, | ||
| }, | ||
| authorizationContainer: { | ||
| flex: 1, | ||
| alignItems: "center", | ||
| justifyContent: "center" | ||
| }, | ||
| notAuthorizedText: { | ||
| textAlign: "center", | ||
| fontSize: 16 | ||
| } | ||
| }); |
| import React, {Component} from 'react'; | ||
| import { | ||
| ActivityIndicator, | ||
| StyleSheet, | ||
| View, | ||
| Animated, | ||
| Easing, | ||
| Text, | ||
| Image, | ||
| Vibration, | ||
| Platform, | ||
| PixelRatio, | ||
| StatusBar | ||
| } from 'react-native'; | ||
| /** | ||
| * Scanning Interface Mask | ||
| * Write a separate class for easy copying | ||
| */ | ||
| export default class ModernQRScannerView extends Component { | ||
| static defaultProps = { | ||
| maskColor: '#0000004D', | ||
| cornerColor: '#22ff00', | ||
| borderColor: '#000000', | ||
| rectHeight: 200, | ||
| rectWidth: 200, | ||
| borderWidth: 0, | ||
| cornerBorderWidth: 4, | ||
| cornerBorderLength: 20, | ||
| cornerOffsetSize: 1, | ||
| isCornerOffset: true, | ||
| bottomHeight: 100, | ||
| scanBarAnimateTime: 2500, | ||
| scanBarColor: '#22ff00', | ||
| scanBarImage: null, | ||
| scanBarHeight: 1.5, | ||
| scanBarMargin: 6, | ||
| hintText: 'Put the QR code / bar code into the box and it will scan automatically', | ||
| hintTextStyle: { | ||
| color: '#fff', | ||
| fontSize: 14, | ||
| backgroundColor: 'transparent' | ||
| }, | ||
| hintTextPosition: 130, | ||
| isShowScanBar: true | ||
| }; | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { | ||
| topWidth: 0, | ||
| topHeight: 0, | ||
| leftWidth: 0, | ||
| animatedValue: new Animated.Value(0) | ||
| } | ||
| this.isClosed = false; | ||
| } | ||
| //Get background color | ||
| getBackgroundColor = () => { | ||
| return ({backgroundColor: this.props.maskColor}); | ||
| } | ||
| //Get scan box background size | ||
| getRectSize = () => { | ||
| return ({height: this.props.rectHeight, width: this.props.rectWidth}); | ||
| } | ||
| //Get scan frame border size | ||
| getBorderSize = () => { | ||
| if (this.props.isCornerOffset) { | ||
| return ({ | ||
| height: this.props.rectHeight - this.props.cornerOffsetSize * 2, | ||
| width: this.props.rectWidth - this.props.cornerOffsetSize * 2 | ||
| }); | ||
| } else { | ||
| return ({height: this.props.rectHeight, width: this.props.rectWidth}); | ||
| } | ||
| } | ||
| //Get the color of the corner of the scan frame | ||
| getCornerColor = () => { | ||
| return ({borderColor: this.props.cornerColor}); | ||
| } | ||
| //Get the size of the corner of the scan frame | ||
| getCornerSize = () => { | ||
| return ({height: this.props.cornerBorderLength, width: this.props.cornerBorderLength}); | ||
| } | ||
| //Get scan frame size | ||
| getBorderWidth = () => { | ||
| return ({borderWidth: this.props.borderWidth}); | ||
| } | ||
| //Get scan box color | ||
| getBorderColor = () => { | ||
| return ({borderColor: this.props.borderColor}); | ||
| } | ||
| //Measure the size of the entire scanning component | ||
| measureTotalSize = (e) => { | ||
| let totalSize = e.layout; | ||
| this.setState({topWidth: totalSize.width}) | ||
| } | ||
| //Measure the position of the scan frame | ||
| measureRectPosition = (e) => { | ||
| let rectSize = e.layout; | ||
| rectSize.x += this.props.finderX | ||
| rectSize.y += this.props.finderY | ||
| this.props.returnSize(rectSize) | ||
| this.setState({topHeight: rectSize.y, leftWidth: rectSize.x}) | ||
| } | ||
| //Get top mask height | ||
| getTopMaskHeight = () => { | ||
| if (this.props.isCornerOffset) { | ||
| return this.state.topHeight + this.props.rectHeight - this.props.cornerOffsetSize; | ||
| } else { | ||
| return this.state.topHeight + this.props.rectHeight; | ||
| } | ||
| } | ||
| //Get bottom mask height | ||
| getBottomMaskHeight = () => { | ||
| if (this.props.isCornerOffset) { | ||
| return this.props.rectHeight + this.state.topHeight - this.props.cornerOffsetSize; | ||
| } else { | ||
| return this.state.topHeight + this.props.rectHeight; | ||
| } | ||
| } | ||
| //Get the left and right mask height | ||
| getSideMaskHeight = () => { | ||
| if (this.props.isCornerOffset) { | ||
| return this.props.rectHeight - this.props.cornerOffsetSize * 2; | ||
| } else { | ||
| return this.props.rectHeight; | ||
| } | ||
| } | ||
| //Get left and right mask width | ||
| getSideMaskWidth = () => { | ||
| if (this.props.isCornerOffset) { | ||
| return this.state.leftWidth + this.props.cornerOffsetSize; | ||
| } else { | ||
| return this.state.leftWidth; | ||
| } | ||
| } | ||
| getBottomHeight = () => { | ||
| return ({bottom: this.props.bottomHeight}); | ||
| } | ||
| getScanBarMargin = () => { | ||
| return ({marginRight: this.props.scanBarMargin, marginLeft: this.props.scanBarMargin}) | ||
| } | ||
| getScanImageWidth = () => { | ||
| return this.props.rectWidth - this.props.scanBarMargin * 2 | ||
| } | ||
| //Draw scan lines | ||
| _renderScanBar = () => { | ||
| if (!this.props.isShowScanBar) | ||
| return; | ||
| if (this.props.scanBarImage) { | ||
| return <Image | ||
| style={{ | ||
| resizeMode: 'contain', | ||
| width: this.getScanImageWidth() | ||
| }} | ||
| source={this.props.scanBarImage}/> | ||
| } else { | ||
| return <View | ||
| style={[ | ||
| this.getScanBarMargin(), { | ||
| backgroundColor: this.props.scanBarColor, | ||
| height: this.props.scanBarHeight | ||
| } | ||
| ]}/> | ||
| } | ||
| } | ||
| render() { | ||
| const animatedStyle = { | ||
| transform: [ | ||
| { | ||
| translateY: this.state.animatedValue | ||
| } | ||
| ] | ||
| }; | ||
| return ( | ||
| <View | ||
| onLayout={({nativeEvent: e}) => this.measureTotalSize(e)} | ||
| style={[ | ||
| styles.container, this.getBottomHeight() | ||
| ]}> | ||
| {/* <View style={{flex:1}}></View> */} | ||
| <View | ||
| style={[ | ||
| styles.viewfinder, this.getRectSize(),{top:this.props.finderY,left:this.props.finderX} | ||
| ]} | ||
| onLayout={({nativeEvent: e}) => this.measureRectPosition(e)}> | ||
| <View | ||
| style={[ | ||
| this.getBorderSize(), | ||
| this.getBorderColor(), | ||
| this.getBorderWidth() | ||
| ]}> | ||
| {/* <Animated.View style={[animatedStyle]}> | ||
| {this._renderScanBar()} | ||
| </Animated.View> */} | ||
| </View> | ||
| <View | ||
| style={[ | ||
| this.getCornerColor(), | ||
| this.getCornerSize(), | ||
| styles.topLeftCorner, { | ||
| borderLeftWidth: this.props.cornerBorderWidth, | ||
| borderTopWidth: this.props.cornerBorderWidth | ||
| } | ||
| ]}/> | ||
| <View | ||
| style={[ | ||
| this.getCornerColor(), | ||
| this.getCornerSize(), | ||
| styles.topRightCorner, { | ||
| borderRightWidth: this.props.cornerBorderWidth, | ||
| borderTopWidth: this.props.cornerBorderWidth | ||
| } | ||
| ]}/> | ||
| <View | ||
| style={[ | ||
| this.getCornerColor(), | ||
| this.getCornerSize(), | ||
| styles.bottomLeftCorner, { | ||
| borderLeftWidth: this.props.cornerBorderWidth, | ||
| borderBottomWidth: this.props.cornerBorderWidth | ||
| } | ||
| ]}/> | ||
| <View | ||
| style={[ | ||
| this.getCornerColor(), | ||
| this.getCornerSize(), | ||
| styles.bottomRightCorner, { | ||
| borderRightWidth: this.props.cornerBorderWidth, | ||
| borderBottomWidth: this.props.cornerBorderWidth | ||
| } | ||
| ]}/> | ||
| </View> | ||
| <View | ||
| style={[ | ||
| this.getBackgroundColor(), | ||
| styles.topMask, { | ||
| bottom: this.getTopMaskHeight() - this.props.finderY * 3, | ||
| top: 0, | ||
| width: this.state.topWidth | ||
| } | ||
| ]}/> | ||
| <View | ||
| style={[ | ||
| this.getBackgroundColor(), | ||
| styles.leftMask, { | ||
| height: this.getSideMaskHeight(), | ||
| width: this.getSideMaskWidth() - this.props.finderX , | ||
| bottom: this.getTopMaskHeight() - this.props.finderY * 3 - this.getSideMaskHeight() | ||
| } | ||
| ]}/> | ||
| <View | ||
| style={[ | ||
| this.getBackgroundColor(), | ||
| styles.rightMask, { | ||
| height: this.getSideMaskHeight(), | ||
| width: this.getSideMaskWidth() - this.props.finderX * 3, | ||
| bottom: this.getTopMaskHeight() - this.props.finderY * 3 - this.getSideMaskHeight() | ||
| } | ||
| ]}/> | ||
| <View | ||
| style={[ | ||
| this.getBackgroundColor(), | ||
| styles.bottomMask, { | ||
| top: this.getBottomMaskHeight() - this.props.finderY, | ||
| width: this.state.topWidth | ||
| } | ||
| ]}/> | ||
| </View> | ||
| ); | ||
| } | ||
| componentDidMount() { | ||
| this.scannerLineMove(); | ||
| } | ||
| componentWillUnmount() { | ||
| this.isClosed = true; | ||
| } | ||
| scannerLineMove() { | ||
| if (this.isClosed) { | ||
| return; | ||
| } | ||
| this.state.animatedValue.setValue(0); //重置Rotate动画值为0 | ||
| Animated.timing( | ||
| this.state.animatedValue, | ||
| {toValue: this.props.rectHeight, | ||
| duration: this.props.scanBarAnimateTime, | ||
| easing: Easing.linear, | ||
| useNativeDriver: true | ||
| }).start(() => this.scannerLineMove()); | ||
| } | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| position: 'absolute', | ||
| top: 0, | ||
| right: 0, | ||
| left: 0 | ||
| }, | ||
| viewfinder: { | ||
| alignItems: 'center', | ||
| justifyContent: 'center' | ||
| }, | ||
| topLeftCorner: { | ||
| position: 'absolute', | ||
| top: 0, | ||
| left: 0 | ||
| }, | ||
| topRightCorner: { | ||
| position: 'absolute', | ||
| top: 0, | ||
| right: 0 | ||
| }, | ||
| bottomLeftCorner: { | ||
| position: 'absolute', | ||
| bottom: 0, | ||
| left: 0 | ||
| }, | ||
| bottomRightCorner: { | ||
| position: 'absolute', | ||
| bottom: 0, | ||
| right: 0 | ||
| }, | ||
| topMask: { | ||
| position: 'absolute', | ||
| top: 0 | ||
| }, | ||
| leftMask: { | ||
| position: 'absolute', | ||
| left: 0 | ||
| }, | ||
| rightMask: { | ||
| position: 'absolute', | ||
| right: 0 | ||
| }, | ||
| bottomMask: { | ||
| position: 'absolute', | ||
| bottom: 0 | ||
| } | ||
| }); |
| import React, { Component } from 'react'; | ||
| import { | ||
| StyleSheet, | ||
| View, | ||
| Animated, | ||
| Easing, | ||
| Image | ||
| } from 'react-native'; | ||
| // 별도의 유틸리티 파일로 이동 가능한 스타일 계산 함수들 | ||
| const calculateBorderSize = (props, isCornerOffset) => { | ||
| if (isCornerOffset) { | ||
| return { | ||
| height: props.rectHeight - props.cornerOffsetSize * 2, | ||
| width: props.rectWidth - props.cornerOffsetSize * 2 | ||
| }; | ||
| } else { | ||
| return { height: props.rectHeight, width: props.rectWidth }; | ||
| } | ||
| }; | ||
| export default class ModernQRScannerView extends Component { | ||
| static defaultProps = { | ||
| maskColor: '#0000004D', | ||
| cornerColor: 'red', | ||
| borderColor: '#000000', | ||
| rectHeight: 200, | ||
| rectWidth: 200, | ||
| borderWidth: 0, | ||
| cornerBorderWidth: 4, | ||
| cornerBorderLength: 20, | ||
| cornerOffsetSize: 1, | ||
| isCornerOffset: true, | ||
| bottomHeight: 100, | ||
| scanBarAnimateTime: 2500, | ||
| scanBarColor: 'red', | ||
| scanBarImage: null, | ||
| scanBarHeight: 1.5, | ||
| scanBarMargin: 6, | ||
| isShowScanBar: true | ||
| }; | ||
| constructor(props) { | ||
| super(props); | ||
| this.state = { | ||
| animatedValue: new Animated.Value(0), | ||
| }; | ||
| this.isClosed = false; | ||
| } | ||
| componentDidMount() { | ||
| this.startScannerLineMove(); | ||
| } | ||
| componentWillUnmount() { | ||
| this.isClosed = true; | ||
| } | ||
| startScannerLineMove = () => { | ||
| if (this.isClosed) return; | ||
| this.state.animatedValue.setValue(0); | ||
| Animated.loop( | ||
| Animated.timing(this.state.animatedValue, { | ||
| toValue: this.props.rectHeight, | ||
| duration: this.props.scanBarAnimateTime, | ||
| easing: Easing.linear, | ||
| useNativeDriver: true, | ||
| }) | ||
| ).start(); | ||
| }; | ||
| renderScanBar = () => { | ||
| if (!this.props.isShowScanBar) return null; | ||
| const scanBarStyle = { | ||
| backgroundColor: this.props.scanBarColor, | ||
| height: this.props.scanBarHeight, | ||
| marginHorizontal: this.props.scanBarMargin, | ||
| }; | ||
| if (this.props.scanBarImage) { | ||
| return ( | ||
| <Image | ||
| style={{ | ||
| resizeMode: 'contain', | ||
| width: this.props.rectWidth - this.props.scanBarMargin * 2, | ||
| }} | ||
| source={this.props.scanBarImage} | ||
| /> | ||
| ); | ||
| } else { | ||
| return <View style={scanBarStyle} />; | ||
| } | ||
| }; | ||
| render() { | ||
| const animatedStyle = { | ||
| transform: [{ translateY: this.state.animatedValue }], | ||
| }; | ||
| const borderSize = calculateBorderSize(this.props, this.props.isCornerOffset); | ||
| return ( | ||
| <View style={styles.container}> | ||
| <View style={[styles.viewfinder, this.props.rectHeight, this.props.rectWidth]}> | ||
| <View style={[borderSize, styles.borderStyle, { borderColor: this.props.borderColor, borderWidth: this.props.borderWidth }]} /> | ||
| {/* Corner Styles */} | ||
| <View style={[styles.cornerStyle, styles.topLeftCorner, { borderColor: this.props.cornerColor, borderLeftWidth: this.props.cornerBorderWidth, borderTopWidth: this.props.cornerBorderWidth }]} /> | ||
| <View style={[styles.cornerStyle, styles.topRightCorner, { borderColor: this.props.cornerColor, borderRightWidth: this.props.cornerBorderWidth, borderTopWidth: this.props.cornerBorderWidth }]} /> | ||
| <View style={[styles.cornerStyle, styles.bottomLeftCorner, { borderColor: this.props.cornerColor, borderLeftWidth: this.props.cornerBorderWidth, borderBottomWidth: this.props.cornerBorderWidth }]} /> | ||
| <View style={[styles.cornerStyle, styles.bottomRightCorner, { borderColor: this.props.cornerColor, borderRightWidth: this.props.cornerBorderWidth, borderBottomWidth: this.props.cornerBorderWidth }]} /> | ||
| {/* Scan Bar */} | ||
| <View> | ||
| {this.renderScanBar()} | ||
| </View> | ||
| </View> | ||
| </View> | ||
| ); | ||
| } | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| position: 'absolute', | ||
| top: 0, | ||
| right: 0, | ||
| left: 0, | ||
| }, | ||
| viewfinder: { | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| }, | ||
| borderStyle: { | ||
| // Border style properties | ||
| }, | ||
| cornerStyle: { | ||
| position: 'absolute', | ||
| height: 20, // 예시 값, 실제로는 props로부터 받은 값을 사용 | ||
| width: 20, // 예시 값, 실제로는 props로부터 받은 값을 사용 | ||
| }, | ||
| topLeftCorner: { | ||
| top: 0, | ||
| left: 0, | ||
| }, | ||
| topRightCorner: { | ||
| top: 0, | ||
| right: 0, | ||
| }, | ||
| bottomLeftCorner: { | ||
| bottom: 0, | ||
| left: 0, | ||
| }, | ||
| bottomRightCorner: { | ||
| bottom: 0, | ||
| right: 0, | ||
| }, | ||
| container: { | ||
| alignItems: 'center', | ||
| justifyContent: 'center', | ||
| position: 'absolute', | ||
| top: 0, | ||
| right: 0, | ||
| left: 0 | ||
| }, | ||
| viewfinder: { | ||
| alignItems: 'center', | ||
| justifyContent: 'center' | ||
| }, | ||
| topLeftCorner: { | ||
| position: 'absolute', | ||
| top: 0, | ||
| left: 0 | ||
| }, | ||
| topRightCorner: { | ||
| position: 'absolute', | ||
| top: 0, | ||
| right: 0 | ||
| }, | ||
| bottomLeftCorner: { | ||
| position: 'absolute', | ||
| bottom: 0, | ||
| left: 0 | ||
| }, | ||
| bottomRightCorner: { | ||
| position: 'absolute', | ||
| bottom: 0, | ||
| right: 0 | ||
| }, | ||
| topMask: { | ||
| position: 'absolute', | ||
| top: 0 | ||
| }, | ||
| leftMask: { | ||
| position: 'absolute', | ||
| left: 0 | ||
| }, | ||
| rightMask: { | ||
| position: 'absolute', | ||
| right: 0 | ||
| }, | ||
| bottomMask: { | ||
| position: 'absolute', | ||
| bottom: 0 | ||
| } | ||
| }); |
+8
-2
@@ -0,3 +1,9 @@ | ||
| import { NativeModules } from 'react-native'; | ||
| import ModernQRScanner from './src/ModernQRScanner'; | ||
| import QrcodeScanner from './src/QrcodeScanner'; | ||
| export default QrcodeScanner; | ||
| const QRReader = (fileUrl) => { | ||
| const { QRScanReader } = NativeModules; | ||
| return QRScanReader.readerQR(fileUrl); | ||
| }; | ||
| export { ModernQRScanner, QRReader }; |
+10
-2
| { | ||
| "name": "react-native-modern-qrscanner", | ||
| "version": "1.0.1", | ||
| "version": "1.0.2", | ||
| "description": "A modern-designed and powerful QR code scanner for React Native with advanced features.", | ||
| "main": "index.js", | ||
| "nativePackage": true, | ||
| "scripts": { | ||
@@ -40,3 +41,10 @@ "test": "jest" | ||
| }, | ||
| "homepage": "https://github.com/npmhub90/react-native-modern-qrscanner#readme" | ||
| "homepage": "https://github.com/npmhub90/react-native-modern-qrscanner#readme", | ||
| "dependencies": { | ||
| "prop-types": "^15.8.1" | ||
| }, | ||
| "devDependencies": { | ||
| "react": "^18.2.0", | ||
| "react-native": "^0.72.6" | ||
| } | ||
| } |
+24
-30
| # react-native-modern-qrscanner | ||
| # React Native Modern QR Scanner | ||
| A modern-designed and powerful QR code scanner for React Native with advanced features. | ||
| This project provides a modern-designed and powerful QR code scanner for React Native applications. | ||
| ## Features | ||
| - Modern and user-friendly interface | ||
| - Fast and efficient QR code scanning | ||
| - Customizable styles and themes | ||
| - Supports both Android and iOS devices | ||
| - Easy integration into React Native projects | ||
| - Scan QR codes using camera. | ||
| - Integrate easily with React Native projects. | ||
| - Support for Android and iOS. | ||
| ## Installation | ||
| To install the package, run: | ||
| ```bash | ||
@@ -20,40 +20,34 @@ npm install react-native-modern-qrscanner | ||
| ## Usage | ||
| or | ||
| Import the `QRScanner` component in your React Native application: | ||
| ```javascript | ||
| import QRScanner from 'react-native-modern-qrscanner'; | ||
| ```bash | ||
| yarn add react-native-modern-qrscanner | ||
| ``` | ||
| Then, use the component in your app: | ||
| ## Usage | ||
| Import `ModernQRScanner` in your React Native application: | ||
| ```javascript | ||
| <QRScanner onScanSuccess={this.handleScanSuccess} /> | ||
| import { ModernQRScanner } from 'react-native-modern-qrscanner'; | ||
| ``` | ||
| Define the callback function for successful scans: | ||
| Use the component in your app: | ||
| ```javascript | ||
| handleScanSuccess = (data) => { | ||
| // Process the scanned data | ||
| console.log("Scanned QR Code:", data); | ||
| }; | ||
| ```jsx | ||
| <ModernQRScanner onQRCodeScanned={(data) => console.log(data)} /> | ||
| ``` | ||
| ## Customization | ||
| ## Testing | ||
| You can customize the scanner's appearance and behavior using various props: | ||
| To test the module in your project, follow these steps: | ||
| ```javascript | ||
| <QRScanner | ||
| onScanSuccess={this.handleScanSuccess} | ||
| cameraStyle={{ ... }} | ||
| scannerAreaStyle={{ ... }} | ||
| /> | ||
| ``` | ||
| 1. Install the module in your React Native project. | ||
| 2. Import and integrate `ModernQRScanner` into your app. | ||
| 3. Run your app on a physical device or emulator. | ||
| 4. Test the QR scanning functionality. | ||
| ## Contributing | ||
| Contributions are welcome! Please open an issue or submit a pull request with any improvements or suggestions. | ||
| Contributions to the project are welcome. Please fork the repository and submit a pull request with your changes. | ||
@@ -60,0 +54,0 @@ ## License |
-1
| console.log('test'); |
| import React, { Component } from 'react'; | ||
| import PropTypes from 'prop-types'; | ||
| import { View, StyleSheet, Alert } from 'react-native'; | ||
| import { RNCamera } from 'react-native-camera'; | ||
| class QrcodeScanner extends Component { | ||
| onBarCodeRead = (e) => { | ||
| if (this.props.onScan) { | ||
| this.props.onScan(e); | ||
| } | ||
| }; | ||
| render() { | ||
| const { style, cameraProps } = this.props; | ||
| return ( | ||
| <View style={[styles.container, style]}> | ||
| <RNCamera | ||
| style={StyleSheet.absoluteFill} | ||
| onBarCodeRead={this.onBarCodeRead} | ||
| {...cameraProps} | ||
| /> | ||
| </View> | ||
| ); | ||
| } | ||
| } | ||
| const styles = StyleSheet.create({ | ||
| container: { | ||
| flex: 1, | ||
| justifyContent: 'center', | ||
| alignItems: 'center', | ||
| }, | ||
| }); | ||
| QrcodeScanner.propTypes = { | ||
| onScan: PropTypes.func, | ||
| style: PropTypes.object, | ||
| cameraProps: PropTypes.object, | ||
| }; | ||
| QrcodeScanner.defaultProps = { | ||
| style: {}, | ||
| cameraProps: {}, | ||
| }; | ||
| export default QrcodeScanner; |
-1
| console.log('testing 222'); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
141970
4048.74%37
516.67%1035
2252.27%1
Infinity%2
Infinity%56
-9.68%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added