Просмотр исходного кода

Merge pull request #213 from juliuscanute/86-select-camera-on-start

86 select camera on start
flutter-beta
Julian Steenbakker 5 лет назад
committed by GitHub
Родитель
Сommit
e80ac88edd
Не найден GPG ключ соответствующий данной подписи Идентификатор GPG ключа: 4AEE18F83AFDEB23
18 измененных файлов: 801 добавлений и 385 удалений
  1. +0
    -1
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt
  2. +130
    -60
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt
  3. +3
    -2
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt
  4. +0
    -1
      android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt
  5. +1
    -0
      example/.gitignore
  6. +39
    -39
      example/ios/Runner.xcodeproj/project.pbxproj
  7. +39
    -69
      example/lib/main.dart
  8. +1
    -1
      example/pubspec.yaml
  9. +160
    -58
      ios/Classes/QRView.swift
  10. +2
    -2
      ios/Classes/QRViewFactory.swift
  11. +5
    -0
      lib/qr_code_scanner.dart
  12. +196
    -151
      lib/src/qr_code_scanner.dart
  13. +16
    -0
      lib/src/types/barcode.dart
  14. +174
    -0
      lib/src/types/barcode_format.dart
  15. +7
    -0
      lib/src/types/camera.dart
  16. +14
    -0
      lib/src/types/camera_exception.dart
  17. +13
    -0
      lib/src/types/features.dart
  18. +1
    -1
      pubspec.yaml

+ 0
- 1
android/src/main/kotlin/net/touchcapture/qr/flutterqr/FlutterQrPlugin.kt Просмотреть файл

@@ -63,7 +63,6 @@ class FlutterQrPlugin : FlutterPlugin, ActivityAware {
inner class CameraRequestPermissionsListener : PluginRegistry.RequestPermissionsResultListener { inner class CameraRequestPermissionsListener : PluginRegistry.RequestPermissionsResultListener {
override fun onRequestPermissionsResult(id: Int, permissions: Array<String>, grantResults: IntArray): Boolean { override fun onRequestPermissionsResult(id: Int, permissions: Array<String>, grantResults: IntArray): Boolean {
if (id == Shared.CAMERA_REQUEST_ID && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (id == Shared.CAMERA_REQUEST_ID && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Shared.cameraPermissionContinuation?.run()
return true return true
} }
return false return false


+ 130
- 60
android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRView.kt Просмотреть файл

@@ -3,13 +3,13 @@ package net.touchcapture.qr.flutterqr
import android.Manifest import android.Manifest
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import com.google.zxing.ResultPoint import com.google.zxing.ResultPoint
import android.hardware.Camera.CameraInfo import android.hardware.Camera.CameraInfo
import android.os.Build import android.os.Build
import com.google.zxing.BarcodeFormat
import com.journeyapps.barcodescanner.BarcodeCallback import com.journeyapps.barcodescanner.BarcodeCallback
import com.journeyapps.barcodescanner.BarcodeResult import com.journeyapps.barcodescanner.BarcodeResult
import com.journeyapps.barcodescanner.BarcodeView import com.journeyapps.barcodescanner.BarcodeView
@@ -17,12 +17,11 @@ import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.platform.PlatformView import io.flutter.plugin.platform.PlatformView
class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) :
class QRView(messenger: BinaryMessenger, id: Int, private val params: HashMap<String, Any>) :
PlatformView, MethodChannel.MethodCallHandler { PlatformView, MethodChannel.MethodCallHandler {


private var isTorchOn: Boolean = false private var isTorchOn: Boolean = false
private var barcodeView: BarcodeView? = null private var barcodeView: BarcodeView? = null
private var requestingPermission = false
private val channel: MethodChannel private val channel: MethodChannel


init { init {
@@ -65,89 +64,173 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context)
} }


override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when(call.method){
"flipCamera" -> {
flipCamera()
}
"toggleFlash" -> {
toggleFlash()
}
"pauseCamera" -> {
pauseCamera()
}
"resumeCamera" -> {
resumeCamera()
}
when(call.method) {
"startScan" -> startScan(call.arguments as? List<Int>, result)
"stopScan" -> stopScan()
"flipCamera" -> flipCamera(result)
"toggleFlash" -> toggleFlash(result)
"pauseCamera" -> pauseCamera(result)
"resumeCamera" -> resumeCamera(result)
"requestPermissions" -> checkAndRequestPermission(result)
"getCameraInfo" -> getCameraInfo(result)
"getFlashInfo" -> getFlashInfo(result)
"getSystemFeatures" -> getSystemFeatures(result)
else -> result.notImplemented()
} }
} }


private fun flipCamera() {
barcodeView?.pause()
val settings = barcodeView?.cameraSettings
private fun getCameraInfo(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
result.success(barcodeView!!.cameraSettings.requestedCameraId)
}

private fun flipCamera(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
barcodeView!!.pause()
val settings = barcodeView!!.cameraSettings


if(settings?.requestedCameraId == CameraInfo.CAMERA_FACING_FRONT)
if(settings.requestedCameraId == CameraInfo.CAMERA_FACING_FRONT)
settings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK settings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK
else else
settings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT
settings.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT


barcodeView?.cameraSettings = settings
barcodeView?.resume()
barcodeView!!.cameraSettings = settings
barcodeView!!.resume()
result.success(settings.requestedCameraId)
} }


private fun toggleFlash() {
private fun getFlashInfo(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
result.success(isTorchOn)
}

private fun toggleFlash(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}

if (hasFlash()) { if (hasFlash()) {
barcodeView?.setTorch(!isTorchOn)
barcodeView!!.setTorch(!isTorchOn)
isTorchOn = !isTorchOn isTorchOn = !isTorchOn
result.success(isTorchOn)
} else {
result.error("404", "This device doesn't support flash", null)
} }


} }


private fun pauseCamera() {
private fun pauseCamera(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
if (barcodeView!!.isPreviewActive) { if (barcodeView!!.isPreviewActive) {
barcodeView?.pause()
barcodeView!!.pause()
} }
result.success(true)
} }


private fun resumeCamera() {
private fun resumeCamera(result: MethodChannel.Result) {
if (barcodeView == null) {
return barCodeViewNotSet(result)
}
if (!barcodeView!!.isPreviewActive) { if (!barcodeView!!.isPreviewActive) {
barcodeView?.resume()
barcodeView!!.resume()
} }
result.success(true)
} }


private fun hasFlash(): Boolean { private fun hasFlash(): Boolean {
return context.packageManager
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
return hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
}

private fun hasBackCamera(): Boolean {
return hasSystemFeature(PackageManager.FEATURE_CAMERA)
}

private fun hasFrontCamera(): Boolean {
return hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)
}

private fun hasSystemFeature(feature: String): Boolean {
return Shared.activity!!.packageManager
.hasSystemFeature(feature)
}

private fun barCodeViewNotSet(result: MethodChannel.Result) {
result.error("404", "No barcode view found", null)
} }


override fun getView(): View { override fun getView(): View {
return initBarCodeView()?.apply { return initBarCodeView()?.apply {
if (!hasBackCamera()) {
if (!hasFrontCamera()) {
// No camera available!
} else {
this.cameraSettings.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT
}
} else {
this.cameraSettings.requestedCameraId = CameraInfo.CAMERA_FACING_BACK
}
resume() resume()
}!! }!!
} }


private fun initBarCodeView(): BarcodeView? { private fun initBarCodeView(): BarcodeView? {
if (barcodeView == null) { if (barcodeView == null) {
barcodeView = createBarCodeView()
barcodeView = BarcodeView(Shared.activity)
if (params["cameraFacing"] as Int == 1) {
barcodeView?.cameraSettings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT
}
} }
return barcodeView return barcodeView
} }


private fun createBarCodeView(): BarcodeView {
val barcode = BarcodeView(Shared.activity)
barcode.decodeContinuous(
private fun startScan(arguments: List<Int>?, result: MethodChannel.Result) {
val allowedBarcodeTypes = mutableListOf<BarcodeFormat>()
try {
arguments?.forEach {
allowedBarcodeTypes.add(BarcodeFormat.values()[it])
}
} catch (e: java.lang.Exception) {
result.error(null, null, null)
}

barcodeView?.decodeContinuous(
object : BarcodeCallback { object : BarcodeCallback {
override fun barcodeResult(result: BarcodeResult) { override fun barcodeResult(result: BarcodeResult) {
val code = mapOf(
"code" to result.text,
"type" to result.barcodeFormat.name,
"rawBytes" to result.rawBytes)
channel.invokeMethod("onRecognizeQR", code)
if (allowedBarcodeTypes.size == 0 || allowedBarcodeTypes.contains(result.barcodeFormat)) {
val code = mapOf(
"code" to result.text,
"type" to result.barcodeFormat.name,
"rawBytes" to result.rawBytes)
channel.invokeMethod("onRecognizeQR", code)
}

} }


override fun possibleResultPoints(resultPoints: List<ResultPoint>) {} override fun possibleResultPoints(resultPoints: List<ResultPoint>) {}
} }
) )
return barcode
}

private fun stopScan() {
barcodeView?.stopDecoding()
}

private fun getSystemFeatures(result: MethodChannel.Result) {
try {
result.success(mapOf("hasFrontCamera" to hasFrontCamera(),
"hasBackCamera" to hasBackCamera(), "hasFlash" to hasFlash(),
"activeCamera" to barcodeView?.cameraSettings?.requestedCameraId))
} catch (e: Exception) {
result.error(null, null, null)
}
} }


private fun hasCameraPermission(): Boolean { private fun hasCameraPermission(): Boolean {
@@ -156,29 +239,16 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context)
} }


private fun checkAndRequestPermission(result: MethodChannel.Result?) { private fun checkAndRequestPermission(result: MethodChannel.Result?) {
if (Shared.cameraPermissionContinuation != null) {
result?.error("cameraPermission", "Camera permission request ongoing", null)
}

Shared.cameraPermissionContinuation = Runnable {
Shared.cameraPermissionContinuation = null
if (!hasCameraPermission()) {
result?.error(
"cameraPermission", "MediaRecorderCamera permission not granted", null)
return@Runnable
}
}

requestingPermission = false
if (hasCameraPermission()) {
Shared.cameraPermissionContinuation?.run()
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestingPermission = true
when {
hasCameraPermission() -> result?.success(true)
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
Shared.activity?.requestPermissions( Shared.activity?.requestPermissions(
arrayOf(Manifest.permission.CAMERA), arrayOf(Manifest.permission.CAMERA),
Shared.CAMERA_REQUEST_ID) Shared.CAMERA_REQUEST_ID)
} }
else -> {
result?.error("cameraPermission", "Platform Version to low for camera permission check", null)
}
} }
} }
} }


+ 3
- 2
android/src/main/kotlin/net/touchcapture/qr/flutterqr/QRViewFactory.kt Просмотреть файл

@@ -10,8 +10,9 @@ import io.flutter.plugin.platform.PlatformViewFactory
class QRViewFactory(private val messenger: BinaryMessenger) : class QRViewFactory(private val messenger: BinaryMessenger) :
PlatformViewFactory(StandardMessageCodec.INSTANCE) { PlatformViewFactory(StandardMessageCodec.INSTANCE) {


override fun create(context: Context, id: Int, obj: Any?): PlatformView {
return QRView(messenger, id, context)
override fun create(context: Context, id: Int, args: Any?): PlatformView {
val params = args as HashMap<String, Any>
return QRView(messenger, id, params)
} }


} }

+ 0
- 1
android/src/main/kotlin/net/touchcapture/qr/flutterqr/Shared.kt Просмотреть файл

@@ -5,5 +5,4 @@ import android.app.Activity
object Shared { object Shared {
const val CAMERA_REQUEST_ID = 513469796 const val CAMERA_REQUEST_ID = 513469796
var activity: Activity? = null var activity: Activity? = null
var cameraPermissionContinuation: Runnable? = null
} }

+ 1
- 0
example/.gitignore Просмотреть файл

@@ -9,6 +9,7 @@
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
.last_build_id


# IntelliJ related # IntelliJ related
*.iml *.iml


+ 39
- 39
example/ios/Runner.xcodeproj/project.pbxproj Просмотреть файл

@@ -9,11 +9,11 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
4FA3805501F593094264678B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 75B64521967C76C845268E71 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F50BD2AA150CE43D961DBB69 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C211BF4383BB3311CB0313D6 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */


/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -30,15 +30,14 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */


/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
11A772D5271EABFB7473B52C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
08F42BD28C1585A831B4FDA2 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4D86354DC939411D3F7E41EA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
75B64521967C76C845268E71 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
96DCE88542EFC8C39614159F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -46,7 +45,8 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C211BF4383BB3311CB0313D6 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DB8991B7B046D94B2E68CEAD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
EF8A0739582463E296AD6CB1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */


/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -54,21 +54,13 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
F50BD2AA150CE43D961DBB69 /* Pods_Runner.framework in Frameworks */,
4FA3805501F593094264678B /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */


/* Begin PBXGroup section */ /* Begin PBXGroup section */
509AC3E235E568B6DDAAEC7D /* Frameworks */ = {
isa = PBXGroup;
children = (
C211BF4383BB3311CB0313D6 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -87,7 +79,7 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
D7C58E57CAF69D9A14CC212F /* Pods */, D7C58E57CAF69D9A14CC212F /* Pods */,
509AC3E235E568B6DDAAEC7D /* Frameworks */,
AF031A634C9742F16BF4F89A /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -122,12 +114,20 @@
name = "Supporting Files"; name = "Supporting Files";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
AF031A634C9742F16BF4F89A /* Frameworks */ = {
isa = PBXGroup;
children = (
75B64521967C76C845268E71 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
D7C58E57CAF69D9A14CC212F /* Pods */ = { D7C58E57CAF69D9A14CC212F /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4D86354DC939411D3F7E41EA /* Pods-Runner.debug.xcconfig */,
11A772D5271EABFB7473B52C /* Pods-Runner.release.xcconfig */,
96DCE88542EFC8C39614159F /* Pods-Runner.profile.xcconfig */,
DB8991B7B046D94B2E68CEAD /* Pods-Runner.debug.xcconfig */,
EF8A0739582463E296AD6CB1 /* Pods-Runner.release.xcconfig */,
08F42BD28C1585A831B4FDA2 /* Pods-Runner.profile.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -139,14 +139,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
854A11C1BE2493D5A6BD85DB /* [CP] Check Pods Manifest.lock */,
7BEA526A4A0DFAAC4945EC09 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
FDE6A3C9913AC5840FF42544 /* [CP] Embed Pods Frameworks */,
8DB6578C615972DBF2DFAA0D /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -168,7 +168,7 @@
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 5LSCTACHT8;
DevelopmentTeam = RCH2VG82SH;
LastSwiftMigration = 1020; LastSwiftMigration = 1020;
ProvisioningStyle = Automatic; ProvisioningStyle = Automatic;
}; };
@@ -221,7 +221,7 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
854A11C1BE2493D5A6BD85DB /* [CP] Check Pods Manifest.lock */ = {
7BEA526A4A0DFAAC4945EC09 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@@ -243,41 +243,41 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
9740EEB61CF901F6004384FC /* Run Script */ = {
8DB6578C615972DBF2DFAA0D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
"${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework",
); );
name = "Run Script";
name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
}; };
FDE6A3C9913AC5840FF42544 /* [CP] Embed Pods Frameworks */ = {
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
"${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework",
); );
name = "[CP] Embed Pods Frameworks";
name = "Run Script";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */


@@ -372,7 +372,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5LSCTACHT8;
DEVELOPMENT_TEAM = RCH2VG82SH;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@@ -510,7 +510,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5LSCTACHT8;
DEVELOPMENT_TEAM = RCH2VG82SH;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@@ -541,7 +541,7 @@
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5LSCTACHT8;
DEVELOPMENT_TEAM = RCH2VG82SH;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",


+ 39
- 69
example/lib/main.dart Просмотреть файл

@@ -6,11 +6,6 @@ import 'package:qr_code_scanner/qr_code_scanner.dart';


void main() => runApp(MaterialApp(home: QRViewExample())); void main() => runApp(MaterialApp(home: QRViewExample()));


const flashOn = 'FLASH ON';
const flashOff = 'FLASH OFF';
const frontCamera = 'FRONT CAMERA';
const backCamera = 'BACK CAMERA';

class QRViewExample extends StatefulWidget { class QRViewExample extends StatefulWidget {
const QRViewExample({ const QRViewExample({
Key key, Key key,
@@ -22,8 +17,6 @@ class QRViewExample extends StatefulWidget {


class _QRViewExampleState extends State<QRViewExample> { class _QRViewExampleState extends State<QRViewExample> {
Barcode result; Barcode result;
var flashState = flashOn;
var cameraState = frontCamera;
QRViewController controller; QRViewController controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');


@@ -64,44 +57,33 @@ class _QRViewExampleState extends State<QRViewExample> {
Container( Container(
margin: EdgeInsets.all(8), margin: EdgeInsets.all(8),
child: RaisedButton( child: RaisedButton(
onPressed: () {
if (controller != null) {
controller.toggleFlash();
if (_isFlashOn(flashState)) {
setState(() {
flashState = flashOff;
});
} else {
setState(() {
flashState = flashOn;
});
}
}
},
child:
Text(flashState, style: TextStyle(fontSize: 20)),
),
onPressed: () => setState(() {
controller?.toggleFlash();
}),
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
), ),
Container( Container(
margin: EdgeInsets.all(8), margin: EdgeInsets.all(8),
child: RaisedButton( child: RaisedButton(
onPressed: () {
if (controller != null) {
controller.flipCamera();
if (_isBackCamera(cameraState)) {
setState(() {
cameraState = frontCamera;
});
} else {
setState(() {
cameraState = backCamera;
});
}
}
},
child:
Text(cameraState, style: TextStyle(fontSize: 20)),
),
onPressed: () => setState(() {
controller?.flipCamera();
}),
child: FutureBuilder(
future: controller?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(snapshot.data)}');
} else {
return Text('loading');
}
},
)),
) )
], ],
), ),
@@ -138,14 +120,6 @@ class _QRViewExampleState extends State<QRViewExample> {
); );
} }


bool _isFlashOn(String current) {
return flashOn == current;
}

bool _isBackCamera(String current) {
return backCamera == current;
}

Widget _buildQrView(BuildContext context) { Widget _buildQrView(BuildContext context) {
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly. // For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
var scanArea = (MediaQuery.of(context).size.width < 400 || var scanArea = (MediaQuery.of(context).size.width < 400 ||
@@ -154,29 +128,25 @@ class _QRViewExampleState extends State<QRViewExample> {
: 300.0; : 300.0;
// To ensure the Scanner view is properly sizes after rotation // To ensure the Scanner view is properly sizes after rotation
// we need to listen for Flutter SizeChanged notification and update controller // we need to listen for Flutter SizeChanged notification and update controller
return NotificationListener<SizeChangedLayoutNotification>(
onNotification: (notification) {
Future.microtask(
() => controller?.updateDimensions(qrKey, scanArea: scanArea));
return false;
},
child: SizeChangedLayoutNotifier(
key: const Key('qr-size-notifier'),
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea,
),
)));
return QRView(
key: qrKey,
cameraFacing: CameraFacing.front,
onQRViewCreated: _onQRViewCreated,
formatsAllowed: [BarcodeFormat.qrcode],
overlay: QrScannerOverlayShape(
borderColor: Colors.red,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea,
),
);
} }


void _onQRViewCreated(QRViewController controller) { void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) { controller.scannedDataStream.listen((scanData) {
setState(() { setState(() {
result = scanData; result = scanData;


+ 1
- 1
example/pubspec.yaml Просмотреть файл

@@ -3,7 +3,7 @@ description: Demonstrates how to use the flutter_qr plugin.
publish_to: 'none' publish_to: 'none'


environment: environment:
sdk: ">=2.3.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"


dependencies: dependencies:
flutter: flutter:


+ 160
- 58
ios/Classes/QRView.swift Просмотреть файл

@@ -13,75 +13,56 @@ public class QRView:NSObject,FlutterPlatformView {
var scanner: MTBBarcodeScanner? var scanner: MTBBarcodeScanner?
var registrar: FlutterPluginRegistrar var registrar: FlutterPluginRegistrar
var channel: FlutterMethodChannel var channel: FlutterMethodChannel
var cameraFacing: MTBCamera
public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64){
var QRCodeTypes = [
0: AVMetadataObject.ObjectType.aztec,
2: AVMetadataObject.ObjectType.code39,
3: AVMetadataObject.ObjectType.code93,
4: AVMetadataObject.ObjectType.code128,
5: AVMetadataObject.ObjectType.dataMatrix,
6: AVMetadataObject.ObjectType.ean8,
7: AVMetadataObject.ObjectType.ean13,
8: AVMetadataObject.ObjectType.interleaved2of5,
10: AVMetadataObject.ObjectType.pdf417,
11: AVMetadataObject.ObjectType.qr,
15: AVMetadataObject.ObjectType.upce
]
public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64, params: Dictionary<String, Any>){
self.registrar = registrar self.registrar = registrar
previewView = UIView(frame: frame) previewView = UIView(frame: frame)
cameraFacing = MTBCamera.init(rawValue: UInt(Int(params["cameraFacing"] as! Double))) ?? MTBCamera.back
channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger())
} }
func isCameraAvailable(success: Bool) -> Void {
if success {
do {
try scanner?.startScanning(resultBlock: { [weak self] codes in
if let codes = codes {
for code in codes {
var typeString: String;
switch(code.type) {
case AVMetadataObject.ObjectType.aztec:
typeString = "AZTEC"
case AVMetadataObject.ObjectType.code39:
typeString = "CODE_39"
case AVMetadataObject.ObjectType.code93:
typeString = "CODE_93"
case AVMetadataObject.ObjectType.code128:
typeString = "CODE_128"
case AVMetadataObject.ObjectType.dataMatrix:
typeString = "DATA_MATRIX"
case AVMetadataObject.ObjectType.ean8:
typeString = "EAN_8"
case AVMetadataObject.ObjectType.ean13:
typeString = "EAN_13"
case AVMetadataObject.ObjectType.itf14:
typeString = "ITF"
case AVMetadataObject.ObjectType.pdf417:
typeString = "PDF_417"
case AVMetadataObject.ObjectType.qr:
typeString = "QR_CODE"
case AVMetadataObject.ObjectType.upce:
typeString = "UPC_E"
default:
return
}
guard let stringValue = code.stringValue else { continue }
let result = ["code": stringValue, "type": typeString]
self?.channel.invokeMethod("onRecognizeQR", arguments: result)
}
}
})
} catch {
NSLog("Unable to start scanning")
}
} else {
UIAlertView(title: "Scanning Unavailable", message: "This app does not have permission to access the camera", delegate: nil, cancelButtonTitle: nil, otherButtonTitles: "Ok").show()
}
deinit {
scanner?.stopScanning()
} }
public func view() -> UIView { public func view() -> UIView {
channel.setMethodCallHandler({ channel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
[weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
switch(call.method){ switch(call.method){
case "setDimensions": case "setDimensions":
let arguments = call.arguments as! Dictionary<String, Double> let arguments = call.arguments as! Dictionary<String, Double>
self?.setDimensions(width: arguments["width"] ?? 0, height: arguments["height"] ?? 0, scanArea: arguments["scanArea"] ?? 0) self?.setDimensions(width: arguments["width"] ?? 0, height: arguments["height"] ?? 0, scanArea: arguments["scanArea"] ?? 0)
case "startScan":
self?.startScan(call.arguments as! Array<Int>, result)
case "flipCamera": case "flipCamera":
self?.flipCamera()
self?.flipCamera(result)
case "toggleFlash": case "toggleFlash":
self?.toggleFlash()
self?.toggleFlash(result)
case "pauseCamera": case "pauseCamera":
self?.pauseCamera()
self?.pauseCamera(result)
case "resumeCamera": case "resumeCamera":
self?.resumeCamera()
self?.resumeCamera(result)
case "getCameraInfo":
self?.getCameraInfo(result)
case "getFlashInfo":
self?.getFlashInfo(result)
case "getSystemFeatures":
self?.getSystemFeatures(result)
default: default:
result(FlutterMethodNotImplemented) result(FlutterMethodNotImplemented)
return return
@@ -106,41 +87,162 @@ public class QRView:NSObject,FlutterPlatformView {
self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea) self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea)
} }
} }
}
}
func startScan(_ arguments: Array<Int>, _ result: @escaping FlutterResult) -> Void {
scanner = MTBBarcodeScanner(previewView: previewView)
var allowedBarcodeTypes: Array<AVMetadataObject.ObjectType> = []
arguments.forEach { arg in
allowedBarcodeTypes.append( QRCodeTypes[arg]!)
}



MTBBarcodeScanner.requestCameraPermission(success: isCameraAvailable)
MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in
if permissionGranted {
do {
try self.scanner?.startScanning(with: self.cameraFacing, resultBlock: { [weak self] codes in
if let codes = codes {
for code in codes {
var typeString: String;
switch(code.type) {
case AVMetadataObject.ObjectType.aztec:
typeString = "AZTEC"
case AVMetadataObject.ObjectType.code39:
typeString = "CODE_39"
case AVMetadataObject.ObjectType.code93:
typeString = "CODE_93"
case AVMetadataObject.ObjectType.code128:
typeString = "CODE_128"
case AVMetadataObject.ObjectType.dataMatrix:
typeString = "DATA_MATRIX"
case AVMetadataObject.ObjectType.ean8:
typeString = "EAN_8"
case AVMetadataObject.ObjectType.ean13:
typeString = "EAN_13"
case AVMetadataObject.ObjectType.itf14:
typeString = "ITF"
case AVMetadataObject.ObjectType.pdf417:
typeString = "PDF_417"
case AVMetadataObject.ObjectType.qr:
typeString = "QR_CODE"
case AVMetadataObject.ObjectType.upce:
typeString = "UPC_E"
default:
return
}
guard let stringValue = code.stringValue else { continue }
let result = ["code": stringValue, "type": typeString]
if allowedBarcodeTypes.count == 0 || allowedBarcodeTypes.contains(code.type) {
self?.channel.invokeMethod("onRecognizeQR", arguments: result)
}
}
}
})
} catch {
let error = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: nil)
result(error)
}
} else {
let error = FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil)
result(error)
}
})
}
func stopScan(){
if let sc: MTBBarcodeScanner = scanner {
if sc.isScanning() {
sc.stopScanning()
}
}
}
func getCameraInfo(_ result: @escaping FlutterResult) -> Void {
if let sc: MTBBarcodeScanner = scanner {
result(sc.camera.rawValue)
} else {
let error = FlutterError(code: "cameraInformationError", message: "Could not get camera information", details: nil)
result(error)
} }
} }
func flipCamera(){
func flipCamera(_ result: @escaping FlutterResult){
if let sc: MTBBarcodeScanner = scanner { if let sc: MTBBarcodeScanner = scanner {
if sc.hasOppositeCamera() { if sc.hasOppositeCamera() {
sc.flipCamera() sc.flipCamera()
} }
return result(sc.camera.rawValue)
}
return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
}
func getFlashInfo(_ result: @escaping FlutterResult) -> Void {
if let sc: MTBBarcodeScanner = scanner {
result(sc.torchMode.rawValue != 0)
} else {
let error = FlutterError(code: "cameraInformationError", message: "Could not get flash information", details: nil)
result(error)
} }
} }
func toggleFlash(){
func toggleFlash(_ result: @escaping FlutterResult){
if let sc: MTBBarcodeScanner = scanner { if let sc: MTBBarcodeScanner = scanner {
if sc.hasTorch() { if sc.hasTorch() {
sc.toggleTorch() sc.toggleTorch()
return result(sc.torchMode == MTBTorchMode(rawValue: 1))
} }
return result(FlutterError(code: "404", message: "This device doesn\'t support flash", details: nil))
} }
return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
} }
func pauseCamera() {
func pauseCamera(_ result: @escaping FlutterResult) {
if let sc: MTBBarcodeScanner = scanner { if let sc: MTBBarcodeScanner = scanner {
if sc.isScanning() { if sc.isScanning() {
sc.freezeCapture() sc.freezeCapture()
} }
return result(true)
} }
return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
} }
func resumeCamera() {
func resumeCamera(_ result: @escaping FlutterResult) {
if let sc: MTBBarcodeScanner = scanner { if let sc: MTBBarcodeScanner = scanner {
if !sc.isScanning() { if !sc.isScanning() {
sc.unfreezeCapture() sc.unfreezeCapture()
} }
return result(true)
}
return result(FlutterError(code: "404", message: "No barcode scanner found", details: nil))
}

func getSystemFeatures(_ result: @escaping FlutterResult) -> Void {
if let sc: MTBBarcodeScanner = scanner {
var hasBackCameraVar = false
var hasFrontCameraVar = false
let camera = sc.camera

if(camera == MTBCamera(rawValue: 0)){
hasBackCameraVar = true
if sc.hasOppositeCamera() {
hasFrontCameraVar = true
}
}else{
hasFrontCameraVar = true
if sc.hasOppositeCamera() {
hasBackCameraVar = true
}
}
return result([
"hasFrontCamera": hasFrontCameraVar,
"hasBackCamera": hasBackCameraVar,
"hasFlash": sc.hasTorch(),
"activeCamera": camera.rawValue
])
} }
return result(FlutterError(code: "404", message: nil, details: nil))
} }
}

}

+ 2
- 2
ios/Classes/QRViewFactory.swift Просмотреть файл

@@ -17,8 +17,8 @@ public class QRViewFactory: NSObject, FlutterPlatformViewFactory {
} }
public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView {
let dictionary = args as! Dictionary<String, Double>
return QRView(withFrame: CGRect(x: 0, y: 0, width: dictionary["width"] ?? 0, height: dictionary["height"] ?? 0), withRegistrar: registrar!,withId: viewId)
let params = args as! Dictionary<String, Double>
return QRView(withFrame: frame, withRegistrar: registrar!,withId: viewId, params: params)
} }
public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol {


+ 5
- 0
lib/qr_code_scanner.dart Просмотреть файл

@@ -1,2 +1,7 @@
export 'src/qr_code_scanner.dart'; export 'src/qr_code_scanner.dart';
export 'src/qr_scanner_overlay_shape.dart'; export 'src/qr_scanner_overlay_shape.dart';
export 'src/types/barcode.dart';
export 'src/types/barcode_format.dart';
export 'src/types/camera.dart';
export 'src/types/camera_exception.dart';
export 'src/types/features.dart';

+ 196
- 151
lib/src/qr_code_scanner.dart Просмотреть файл

@@ -3,138 +3,107 @@ import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';


typedef QRViewCreatedCallback = void Function(QRViewController);

enum BarcodeFormat {
/// Aztec 2D barcode format.
aztec,

/// CODABAR 1D format.
codabar,

/// Code 39 1D format.
code39,

/// Code 93 1D format.
code93,

/// Code 128 1D format.
code128,

/// Data Matrix 2D barcode format.
dataMatrix,

/// EAN-8 1D format.
ean8,

/// EAN-13 1D format.
ean13,

/// ITF (Interleaved Two of Five) 1D format.
itf,

/// MaxiCode 2D barcode format.
maxicode,

/// PDF417 format.
pdf417,

/// QR Code 2D barcode format.
qrcode,

/// RSS 14
rss14,

/// RSS EXPANDED
rssExpanded,

/// UPC-A 1D format.
upcA,
import 'qr_scanner_overlay_shape.dart';
import 'types/barcode.dart';
import 'types/barcode_format.dart';
import 'types/camera.dart';
import 'types/camera_exception.dart';
import 'types/features.dart';


/// UPC-E 1D format.
upcE,

/// UPC/EAN extension format. Not a stand-alone format.
upcEanExtension
}

const _formatNames = <String, BarcodeFormat>{
'AZTEC': BarcodeFormat.aztec,
'CODABAR': BarcodeFormat.codabar,
'CODE_39': BarcodeFormat.code39,
'CODE_93': BarcodeFormat.code93,
'CODE_128': BarcodeFormat.code128,
'DATA_MATRIX': BarcodeFormat.dataMatrix,
'EAN_8': BarcodeFormat.ean8,
'EAN_13': BarcodeFormat.ean13,
'ITF': BarcodeFormat.itf,
'MAXICODE': BarcodeFormat.maxicode,
'PDF_417': BarcodeFormat.pdf417,
'QR_CODE': BarcodeFormat.qrcode,
'RSS_14': BarcodeFormat.rss14,
'RSS_EXPANDED': BarcodeFormat.rssExpanded,
'UPC_A': BarcodeFormat.upcA,
'UPC_E': BarcodeFormat.upcE,
'UPC_EAN_EXTENSION': BarcodeFormat.upcEanExtension,
};

class Barcode {
Barcode(this.code, this.format, this.rawBytes);

final String code;
final BarcodeFormat format;

/// Raw bytes are only supported by Android.
final List<int> rawBytes;
}
typedef QRViewCreatedCallback = void Function(QRViewController);
typedef PermissionSetCallback = void Function(QRViewController, bool);


/// The [QRView] is the view where the camera
/// and the barcode scanner gets displayed.
class QRView extends StatefulWidget { class QRView extends StatefulWidget {
const QRView({ const QRView({
@required Key key, @required Key key,
@required this.onQRViewCreated, @required this.onQRViewCreated,
this.overlay, this.overlay,
this.overlayMargin = EdgeInsets.zero, this.overlayMargin = EdgeInsets.zero,
this.cameraFacing = CameraFacing.back,
this.onPermissionSet,
this.formatsAllowed,
}) : assert(key != null), }) : assert(key != null),
assert(onQRViewCreated != null), assert(onQRViewCreated != null),
super(key: key); super(key: key);


/// [onQRViewCreated] gets called when the view is created
final QRViewCreatedCallback onQRViewCreated; final QRViewCreatedCallback onQRViewCreated;


/// Use [overlay] to provide an overlay for the view.
/// This can be used to create a certain scan area.
final ShapeBorder overlay; final ShapeBorder overlay;

/// Use [overlayMargin] to provide a margin to [overlay]
final EdgeInsetsGeometry overlayMargin; final EdgeInsetsGeometry overlayMargin;


/// Set which camera to use on startup.
///
/// [cameraFacing] can either be CameraFacing.front or CameraFacing.back.
/// Defaults to CameraFacing.back
final CameraFacing cameraFacing;

/// Calls the provided [onPermissionSet] callback when the permission is set.
final PermissionSetCallback onPermissionSet;

/// Use [formatsAllowed] to specify which formats needs to be scanned.
final List<BarcodeFormat> formatsAllowed;

@override @override
State<StatefulWidget> createState() => _QRViewState(); State<StatefulWidget> createState() => _QRViewState();
} }


class _QRViewState extends State<QRView> { class _QRViewState extends State<QRView> {
var _channel;

@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return NotificationListener(
onNotification: onNotification,
child: SizeChangedLayoutNotifier(
child: (widget.overlay != null)
? _getPlatformQrViewWithOverlay()
: _getPlatformQrView(),
),
);
}

bool onNotification(notification) {
Future.microtask(() => {
QRViewController.updateDimensions(widget.key, _channel,
scanArea: widget.overlay != null
? (widget.overlay as QrScannerOverlayShape).cutOutSize
: 0.0)
});
return false;
}

Widget _getPlatformQrViewWithOverlay() {
return Stack( return Stack(
children: [ children: [
_getPlatformQrView(widget.key),
if (widget.overlay != null)
Container(
padding: widget.overlayMargin,
decoration: ShapeDecoration(
shape: widget.overlay,
),
)
else
Container(),
_getPlatformQrView(),
Container(
padding: widget.overlayMargin,
decoration: ShapeDecoration(
shape: widget.overlay,
),
)
], ],
); );
} }


Widget _getPlatformQrView(GlobalKey key) {
Widget _getPlatformQrView() {
Widget _platformQrView; Widget _platformQrView;
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.android: case TargetPlatform.android:
_platformQrView = AndroidView( _platformQrView = AndroidView(
viewType: 'net.touchcapture.qr.flutterqr/qrview', viewType: 'net.touchcapture.qr.flutterqr/qrview',
onPlatformViewCreated: _onPlatformViewCreated, onPlatformViewCreated: _onPlatformViewCreated,
creationParams:
_QrCameraSettings(cameraFacing: widget.cameraFacing).toMap(),
creationParamsCodec: StandardMessageCodec(),
); );
break; break;
case TargetPlatform.iOS: case TargetPlatform.iOS:
@@ -142,8 +111,7 @@ class _QRViewState extends State<QRView> {
viewType: 'net.touchcapture.qr.flutterqr/qrview', viewType: 'net.touchcapture.qr.flutterqr/qrview',
onPlatformViewCreated: _onPlatformViewCreated, onPlatformViewCreated: _onPlatformViewCreated,
creationParams: creationParams:
_CreationParams.fromWidget(MediaQuery.of(context).size.width, 400)
.toMap(),
_QrCameraSettings(cameraFacing: widget.cameraFacing).toMap(),
creationParamsCodec: StandardMessageCodec(), creationParamsCodec: StandardMessageCodec(),
); );
break; break;
@@ -155,101 +123,178 @@ class _QRViewState extends State<QRView> {
} }


void _onPlatformViewCreated(int id) { void _onPlatformViewCreated(int id) {
if (widget.onQRViewCreated == null) {
return;
}

// We pass the cutout size so that the scanner respects the scan area. // We pass the cutout size so that the scanner respects the scan area.
var cutOutSize = 0.0; var cutOutSize = 0.0;
if (widget.overlay != null) { if (widget.overlay != null) {
cutOutSize = (widget.overlay as QrScannerOverlayShape).cutOutSize; cutOutSize = (widget.overlay as QrScannerOverlayShape).cutOutSize;
} }


widget.onQRViewCreated(QRViewController._(id, widget.key, cutOutSize));
}
}
_channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id');


class _CreationParams {
_CreationParams({this.width, this.height});
// Start scan after creation of the view
final controller = QRViewController._(
_channel, widget.key, cutOutSize, widget.onPermissionSet)
.._startScan(widget.key, cutOutSize, widget.formatsAllowed);


static _CreationParams fromWidget(double width, double height) {
return _CreationParams(
width: width,
height: height,
);
// Initialize the controller for controlling the QRView
if (widget.onQRViewCreated != null) {
widget.onQRViewCreated(controller);
}
} }
}


final double width;
final double height;
class _QrCameraSettings {
_QrCameraSettings({
this.cameraFacing,
});

final CameraFacing cameraFacing;


Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return <String, dynamic>{ return <String, dynamic>{
'width': width,
'height': height,
'cameraFacing': cameraFacing.index,
}; };
} }
} }


class QRViewController { class QRViewController {
QRViewController._(int id, GlobalKey qrKey, double scanArea)
: _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id') {
updateDimensions(qrKey, scanArea: scanArea);
_channel.setMethodCallHandler(
(call) async {
switch (call.method) {
case scanMethodCall:
if (call.arguments != null) {
final args = call.arguments as Map;
final code = args['code'] as String;
final rawType = args['type'] as String;
// Raw bytes are only supported by Android.
final rawBytes = args['rawBytes'] as List<int>;
final format = _formatNames[rawType];
if (format != null) {
final barcode = Barcode(code, format, rawBytes);
_scanUpdateController.sink.add(barcode);
} else {
throw Exception('Unexpected barcode type $rawType');
}
QRViewController._(MethodChannel channel, GlobalKey qrKey, double scanArea,
PermissionSetCallback onPermissionSet)
: _channel = channel {
_channel.setMethodCallHandler((call) async {
switch (call.method) {
case 'onRecognizeQR':
if (call.arguments != null) {
final args = call.arguments as Map;
final code = args['code'] as String;
final rawType = args['type'] as String;
// Raw bytes are only supported by Android.
final rawBytes = args['rawBytes'] as List<int>;
final format = BarcodeTypesExtension.fromString(rawType);
if (format != null) {
final barcode = Barcode(code, format, rawBytes);
_scanUpdateController.sink.add(barcode);
} else {
throw Exception('Unexpected barcode type $rawType');
} }
}
},
);
}
break;
case 'onPermissionSet':
await getSystemFeatures(); // if we have no permission all features will not be avaible
if (call.arguments != null) {
if (call.arguments as bool) {
_hasPermissions = true;
} else {
_hasPermissions = false;
}
if (onPermissionSet != null) {
onPermissionSet(this, call.arguments as bool);
}
}
break;
}
});
} }


static const scanMethodCall = 'onRecognizeQR';

final MethodChannel _channel; final MethodChannel _channel;

final StreamController<Barcode> _scanUpdateController = final StreamController<Barcode> _scanUpdateController =
StreamController<Barcode>(); StreamController<Barcode>();


Stream<Barcode> get scannedDataStream => _scanUpdateController.stream; Stream<Barcode> get scannedDataStream => _scanUpdateController.stream;


void flipCamera() {
_channel.invokeMethod('flipCamera');
SystemFeatures _features;
bool _hasPermissions;

SystemFeatures get systemFeatures => _features;
bool get hasPermissions => _hasPermissions;

/// Starts the barcode scanner
Future<void> _startScan(GlobalKey key, double cutOutSize,
List<BarcodeFormat> barcodeFormats) async {
// We need to update the dimension before the scan is started.
QRViewController.updateDimensions(key, _channel, scanArea: cutOutSize);
return _channel.invokeMethod(
'startScan', barcodeFormats?.map((e) => e.asInt())?.toList() ?? []);
} }


void toggleFlash() {
_channel.invokeMethod('toggleFlash');
/// Gets information about which camera is active.
Future<CameraFacing> getCameraInfo() async {
try {
return CameraFacing
.values[await _channel.invokeMethod('getCameraInfo') as int];
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Flips the camera between available modes
Future<CameraFacing> flipCamera() async {
try {
return CameraFacing
.values[await _channel.invokeMethod('flipCamera') as int];
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
} }


void pauseCamera() {
_channel.invokeMethod('pauseCamera');
/// Get flashlight status
Future<bool> getFlashStatus() async {
try {
return await _channel.invokeMethod('getFlashInfo');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Toggles the flashlight between available modes
Future<void> toggleFlash() async {
try {
await _channel.invokeMethod('toggleFlash') as bool;
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
} }


void resumeCamera() {
_channel.invokeMethod('resumeCamera');
/// Pauses barcode scanning
Future<void> pauseCamera() async {
try {
await _channel.invokeMethod('pauseCamera');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Resumes barcode scanning
Future<void> resumeCamera() async {
try {
await _channel.invokeMethod('resumeCamera');
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
}

/// Returns which features are available on device.
Future<SystemFeatures> getSystemFeatures() async {
try {
var features =
await _channel.invokeMapMethod<String, dynamic>('getSystemFeatures');
return SystemFeatures.fromJson(features);
} on PlatformException catch (e) {
throw CameraException(e.code, e.message);
}
} }


/// Disposes the barcode stream.
void dispose() { void dispose() {
_scanUpdateController.close(); _scanUpdateController.close();
} }


void updateDimensions(GlobalKey key, {double scanArea}) {
/// Updates the view dimensions for iOS.
static void updateDimensions(GlobalKey key, MethodChannel channel,
{double scanArea}) {
if (defaultTargetPlatform == TargetPlatform.iOS) { if (defaultTargetPlatform == TargetPlatform.iOS) {
final RenderBox renderBox = key.currentContext.findRenderObject(); final RenderBox renderBox = key.currentContext.findRenderObject();
_channel.invokeMethod('setDimensions', {
channel.invokeMethod('setDimensions', {
'width': renderBox.size.width, 'width': renderBox.size.width,
'height': renderBox.size.height, 'height': renderBox.size.height,
'scanArea': scanArea ?? 0 'scanArea': scanArea ?? 0


+ 16
- 0
lib/src/types/barcode.dart Просмотреть файл

@@ -0,0 +1,16 @@
import 'barcode_format.dart';

/// The [Barcode] object holds information about the barcode or qr code.
///
/// [code] is the content of the barcode.
/// [format] displays which type the code is.
/// Only for Android, [rawBytes] gives a list of bytes of the result.
class Barcode {
Barcode(this.code, this.format, this.rawBytes);

final String code;
final BarcodeFormat format;

/// Raw bytes are only supported by Android.
final List<int> rawBytes;
}

+ 174
- 0
lib/src/types/barcode_format.dart Просмотреть файл

@@ -0,0 +1,174 @@
enum BarcodeFormat {
/// Aztec 2D barcode format.
aztec,

/// CODABAR 1D format.
codabar,

/// Code 39 1D format.
code39,

/// Code 93 1D format.
code93,

/// Code 128 1D format.
code128,

/// Data Matrix 2D barcode format.
dataMatrix,

/// EAN-8 1D format.
ean8,

/// EAN-13 1D format.
ean13,

/// ITF (Interleaved Two of Five) 1D format.
itf,

/// MaxiCode 2D barcode format.
maxicode,

/// PDF417 format.
pdf417,

/// QR Code 2D barcode format.
qrcode,

/// RSS 14
rss14,

/// RSS EXPANDED
rssExpanded,

/// UPC-A 1D format.
upcA,

/// UPC-E 1D format.
upcE,

/// UPC/EAN extension format. Not a stand-alone format.
upcEanExtension
}

extension BarcodeTypesExtension on BarcodeFormat {
int asInt() {
return index;
}

static BarcodeFormat fromString(String format) {
switch (format) {
case 'AZTEC':
return BarcodeFormat.aztec;
break;
case 'CODABAR':
return BarcodeFormat.codabar;
break;
case 'CODE_39':
return BarcodeFormat.code39;
break;
case 'CODE_93':
return BarcodeFormat.code93;
break;
case 'CODE_128':
return BarcodeFormat.code128;
break;
case 'DATA_MATRIX':
return BarcodeFormat.dataMatrix;
break;
case 'EAN_8':
return BarcodeFormat.ean8;
break;
case 'EAN_13':
return BarcodeFormat.ean13;
break;
case 'ITF':
return BarcodeFormat.itf;
break;
case 'MAXICODE':
return BarcodeFormat.maxicode;
break;
case 'PDF_417':
return BarcodeFormat.pdf417;
break;
case 'QR_CODE':
return BarcodeFormat.qrcode;
break;
case 'RSS14':
return BarcodeFormat.rss14;
break;
case 'RSS_EXPANDED':
return BarcodeFormat.rssExpanded;
break;
case 'UPC_A':
return BarcodeFormat.upcA;
break;
case 'UPC_E':
return BarcodeFormat.upcE;
break;
case 'UPC_EAN_EXTENSION':
return BarcodeFormat.upcEanExtension;
break;
default:
return null;
}
}

String get formatName {
switch (this) {
case BarcodeFormat.aztec:
return 'AZTEC';
break;
case BarcodeFormat.codabar:
return 'CODABAR';
break;
case BarcodeFormat.code39:
return 'CODE_39';
break;
case BarcodeFormat.code93:
return 'CODE_93';
break;
case BarcodeFormat.code128:
return 'CODE_128';
break;
case BarcodeFormat.dataMatrix:
return 'DATA_MATRIX';
break;
case BarcodeFormat.ean8:
return 'EAN_8';
break;
case BarcodeFormat.ean13:
return 'EAN_13';
break;
case BarcodeFormat.itf:
return 'ITF';
break;
case BarcodeFormat.maxicode:
return 'MAXICODE';
break;
case BarcodeFormat.pdf417:
return 'PDF_417';
break;
case BarcodeFormat.qrcode:
return 'QR_CODE';
break;
case BarcodeFormat.rss14:
return 'RSS14';
break;
case BarcodeFormat.rssExpanded:
return 'RSS_EXPANDED';
break;
case BarcodeFormat.upcA:
return 'UPC_A';
break;
case BarcodeFormat.upcE:
return 'UPC_E';
break;
case BarcodeFormat.upcEanExtension:
return 'UPC_EAN_EXTENSION';
break;
default:
return 'NOT_VALID';
}
}
}

+ 7
- 0
lib/src/types/camera.dart Просмотреть файл

@@ -0,0 +1,7 @@
enum CameraFacing {
/// Shows back facing camera.
back,

/// Shows front facing camera.
front
}

+ 14
- 0
lib/src/types/camera_exception.dart Просмотреть файл

@@ -0,0 +1,14 @@
/// This is thrown when the plugin reports an error.
class CameraException implements Exception {
/// Creates a new camera exception with the given error code and description.
CameraException(this.code, this.description);

/// Error code.
String code;

/// Textual description of the error.
String description;

@override
String toString() => 'CameraException($code, $description)';
}

+ 13
- 0
lib/src/types/features.dart Просмотреть файл

@@ -0,0 +1,13 @@
class SystemFeatures {
SystemFeatures(this.hasFlash, this.hasBackCamera, this.hasFrontCamera);

factory SystemFeatures.fromJson(Map<String, dynamic> features) =>
SystemFeatures(
features['hasFlash'] ?? false,
features['hasBackCamera'] ?? false,
features['hasFrontCamera'] ?? false);

final bool hasFlash;
final bool hasFrontCamera;
final bool hasBackCamera;
}

+ 1
- 1
pubspec.yaml Просмотреть файл

@@ -5,7 +5,7 @@ homepage: https://juliuscanute.com
repository: https://github.com/juliuscanute/qr_code_scanner repository: https://github.com/juliuscanute/qr_code_scanner


environment: environment:
sdk: ">=2.3.0 <3.0.0"
sdk: ">=2.6.0 <3.0.0"
flutter: ^1.10.0 flutter: ^1.10.0


dependencies: dependencies:


Загрузка…
Отмена
Сохранить