From 7936225e8fce718df6752ba46e6b05763d2f8378 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Tue, 15 Feb 2022 17:14:31 +0100 Subject: [PATCH 1/7] Delete LICENSE --- LICENSE | 1 - 1 file changed, 1 deletion(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index ba75c69f7..000000000 --- a/LICENSE +++ /dev/null @@ -1 +0,0 @@ -TODO: Add your license here. From 763227f17ab47e5c3697bbe7b68b1a2ef21122a5 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Tue, 15 Feb 2022 17:17:09 +0100 Subject: [PATCH 2/7] Create LICENSE --- LICENSE | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..8e665deca --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2022, Julian Steenbakker +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From d548efb000206cfd39b580ea12ce4244b6f5434f Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Tue, 15 Feb 2022 17:18:12 +0100 Subject: [PATCH 3/7] release of v0.0.1 --- CHANGELOG.md | 8 +++++++- pubspec.yaml | 4 +--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41cc7d819..757b9ffce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ ## 0.0.1 +Initial release! +Things working on Android: +* Scanning barcodes using the latest version of MLKit and CameraX! +* Switching camera's +* Toggling of the torch (flash) -* TODO: Describe initial release. +Things working on iOS: +* Scanning barcodes using the latest version of MLKit and AVFoundation! diff --git a/pubspec.yaml b/pubspec.yaml index 8f42f8045..648d696d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,6 +23,4 @@ flutter: package: dev.steenbakker.mobile_scanner pluginClass: MobileScannerPlugin ios: - pluginClass: MobileScannerPlugin - macos: - pluginClass: MobileScannerPlugin + pluginClass: MobileScannerPlugin \ No newline at end of file From 7764df237345ba5df47a697d38007f1c7c95aa89 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Wed, 16 Feb 2022 08:49:44 +0100 Subject: [PATCH 4/7] imp: upgrade gradle and iOS improvements --- example/android/build.gradle | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- ios/Classes/SwiftMobileScanner.swift | 8 + ios/Classes/SwiftMobileScannerPlugin.swift | 166 ++++++++++-------- 4 files changed, 101 insertions(+), 79 deletions(-) create mode 100644 ios/Classes/SwiftMobileScanner.swift diff --git a/example/android/build.gradle b/example/android/build.gradle index 2778fe6fe..cba6c84b6 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.1.0' + classpath 'com.android.tools.build:gradle:7.1.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 37d37cb3b..5e7d0f120 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Feb 08 10:35:11 CET 2022 +#Tue Feb 15 22:11:04 CET 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/ios/Classes/SwiftMobileScanner.swift b/ios/Classes/SwiftMobileScanner.swift new file mode 100644 index 000000000..82d78ed64 --- /dev/null +++ b/ios/Classes/SwiftMobileScanner.swift @@ -0,0 +1,8 @@ +// +// SwiftMobileScanner.swift +// mobile_scanner +// +// Created by Julian Steenbakker on 15/02/2022. +// + +import Foundation diff --git a/ios/Classes/SwiftMobileScannerPlugin.swift b/ios/Classes/SwiftMobileScannerPlugin.swift index 79050a212..c4204f93a 100644 --- a/ios/Classes/SwiftMobileScannerPlugin.swift +++ b/ios/Classes/SwiftMobileScannerPlugin.swift @@ -5,40 +5,53 @@ import MLKitBarcodeScanning public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler, FlutterTexture, AVCaptureVideoDataOutputSampleBufferDelegate { - public static func register(with registrar: FlutterPluginRegistrar) { - let instance = SwiftMobileScannerPlugin(registrar.textures()) - - let method = FlutterMethodChannel(name: "dev.steenbakker.mobile_scanner/scanner/method", binaryMessenger: registrar.messenger()) - registrar.addMethodCallDelegate(instance, channel: method) - - let event = FlutterEventChannel(name: "dev.steenbakker.mobile_scanner/scanner/event", binaryMessenger: registrar.messenger()) - event.setStreamHandler(instance) - } - let registry: FlutterTextureRegistry + + // Sink for publishing event changes var sink: FlutterEventSink! + + // Texture id of the camera preview var textureId: Int64! + + // Capture session of the camera var captureSession: AVCaptureSession! + + // The selected camera var device: AVCaptureDevice! + + // Image to be sent to the texture var latestBuffer: CVImageBuffer! - var analyzeMode: Int - var analyzing: Bool + + + var analyzeMode: Int = 0 + var analyzing: Bool = false + var position = AVCaptureDevice.Position.back + + public static func register(with registrar: FlutterPluginRegistrar) { + let instance = SwiftMobileScannerPlugin(registrar.textures()) + + let method = FlutterMethodChannel(name: + "dev.steenbakker.mobile_scanner/scanner/method", binaryMessenger: registrar.messenger()) + let event = FlutterEventChannel(name: + "dev.steenbakker.mobile_scanner/scanner/event", binaryMessenger: registrar.messenger()) + registrar.addMethodCallDelegate(instance, channel: method) + event.setStreamHandler(instance) + } init(_ registry: FlutterTextureRegistry) { self.registry = registry - analyzeMode = 0 - analyzing = false super.init() } + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "state": - stateNative(call, result) + checkPermission(call, result) case "request": - requestNative(call, result) + requestPermission(call, result) case "start": - startNative(call, result) + start(call, result) case "torch": torchNative(call, result) case "analyze": @@ -50,16 +63,19 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan } } + // FlutterStreamHandler public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { sink = events return nil } + // FlutterStreamHandler public func onCancel(withArguments arguments: Any?) -> FlutterError? { sink = nil return nil } + // FlutterTexture public func copyPixelBuffer() -> Unmanaged? { if latestBuffer == nil { return nil @@ -67,60 +83,60 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan return Unmanaged.passRetained(latestBuffer) } - public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { - - latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) - registry.textureFrameAvailable(textureId) - - switch analyzeMode { - case 1: // barcode - if analyzing { - break - } - analyzing = true - let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) - let image = VisionImage(image: buffer!.image) - image.orientation = imageOrientation( - deviceOrientation: UIDevice.current.orientation, - defaultOrientation: .portrait - ) - - let scanner = BarcodeScanner.barcodeScanner() - scanner.process(image) { [self] barcodes, error in - if error == nil && barcodes != nil { - for barcode in barcodes! { - let event: [String: Any?] = ["name": "barcode", "data": barcode.data] - sink?(event) - } - } - analyzing = false - } - default: // none - break - } - } +// public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { +// +// latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) +// registry.textureFrameAvailable(textureId) +// +// switch analyzeMode { +// case 1: // barcode +// if analyzing { +// break +// } +// analyzing = true +// let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) +// let image = VisionImage(image: buffer!.image) +// image.orientation = imageOrientation( +// deviceOrientation: UIDevice.current.orientation, +// defaultOrientation: .portrait +// ) +// +// let scanner = BarcodeScanner.barcodeScanner() +// scanner.process(image) { [self] barcodes, error in +// if error == nil && barcodes != nil { +// for barcode in barcodes! { +// let event: [String: Any?] = ["name": "barcode", "data": barcode.data] +// sink?(event) +// } +// } +// analyzing = false +// } +// default: // none +// break +// } +// } - func imageOrientation( - deviceOrientation: UIDeviceOrientation, - defaultOrientation: UIDeviceOrientation - ) -> UIImage.Orientation { - switch deviceOrientation { - case .portrait: - return position == .front ? .leftMirrored : .right - case .landscapeLeft: - return position == .front ? .downMirrored : .up - case .portraitUpsideDown: - return position == .front ? .rightMirrored : .left - case .landscapeRight: - return position == .front ? .upMirrored : .down - case .faceDown, .faceUp, .unknown: - return .up - @unknown default: - return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait) - } - } +// func imageOrientation( +// deviceOrientation: UIDeviceOrientation, +// defaultOrientation: UIDeviceOrientation +// ) -> UIImage.Orientation { +// switch deviceOrientation { +// case .portrait: +// return position == .front ? .leftMirrored : .right +// case .landscapeLeft: +// return position == .front ? .downMirrored : .up +// case .portraitUpsideDown: +// return position == .front ? .rightMirrored : .left +// case .landscapeRight: +// return position == .front ? .upMirrored : .down +// case .faceDown, .faceUp, .unknown: +// return .up +// @unknown default: +// return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait) +// } +// } - func stateNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { let status = AVCaptureDevice.authorizationStatus(for: .video) switch status { case .notDetermined: @@ -132,20 +148,18 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan } } - func requestNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + func requestPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { AVCaptureDevice.requestAccess(for: .video, completionHandler: { result($0) }) } - - var position = AVCaptureDevice.Position.back - - func startNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + + func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { textureId = registry.register(self) captureSession = AVCaptureSession() let argReader = MapArgumentReader(call.arguments as? [String: Any]) - guard let targetWidth = argReader.int(key: "targetWidth"), - let targetHeight = argReader.int(key: "targetHeight"), + guard let ratio = argReader.int(key: "ratio"), + let torch = argReader.int(key: "torch"), let facing = argReader.int(key: "facing") else { result(FlutterError(code: "INVALID_ARGUMENT", message: "Missing a required argument", details: "Expecting targetWidth, targetHeight, formats, and optionally heartbeatTimeout")) return From e893f84fc86275123957090bde1105867ed10e61 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Wed, 16 Feb 2022 09:35:04 +0100 Subject: [PATCH 5/7] ios: fix scanning, torch on boot and camera facing --- ios/Classes/SwiftMobileScannerPlugin.swift | 149 ++++++++++++--------- 1 file changed, 84 insertions(+), 65 deletions(-) diff --git a/ios/Classes/SwiftMobileScannerPlugin.swift b/ios/Classes/SwiftMobileScannerPlugin.swift index c4204f93a..899b049cd 100644 --- a/ios/Classes/SwiftMobileScannerPlugin.swift +++ b/ios/Classes/SwiftMobileScannerPlugin.swift @@ -53,11 +53,11 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan case "start": start(call, result) case "torch": - torchNative(call, result) + switchTorch(call, result) case "analyze": - analyzeNative(call, result) + switchAnalyzeMode(call, result) case "stop": - stopNative(result) + stop(result) default: result(FlutterMethodNotImplemented) } @@ -83,58 +83,59 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan return Unmanaged.passRetained(latestBuffer) } -// public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { -// -// latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) -// registry.textureFrameAvailable(textureId) -// -// switch analyzeMode { -// case 1: // barcode -// if analyzing { -// break -// } -// analyzing = true -// let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) -// let image = VisionImage(image: buffer!.image) -// image.orientation = imageOrientation( -// deviceOrientation: UIDevice.current.orientation, -// defaultOrientation: .portrait -// ) -// -// let scanner = BarcodeScanner.barcodeScanner() -// scanner.process(image) { [self] barcodes, error in -// if error == nil && barcodes != nil { -// for barcode in barcodes! { -// let event: [String: Any?] = ["name": "barcode", "data": barcode.data] -// sink?(event) -// } -// } -// analyzing = false -// } -// default: // none -// break -// } -// } + // Gets called when a new image is added to the buffer + public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { + + latestBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) + registry.textureFrameAvailable(textureId) + + switch analyzeMode { + case 1: // barcode + if analyzing { + break + } + analyzing = true + let buffer = CMSampleBufferGetImageBuffer(sampleBuffer) + let image = VisionImage(image: buffer!.image) + image.orientation = imageOrientation( + deviceOrientation: UIDevice.current.orientation, + defaultOrientation: .portrait + ) + + let scanner = BarcodeScanner.barcodeScanner() + scanner.process(image) { [self] barcodes, error in + if error == nil && barcodes != nil { + for barcode in barcodes! { + let event: [String: Any?] = ["name": "barcode", "data": barcode.data] + sink?(event) + } + } + analyzing = false + } + default: // none + break + } + } -// func imageOrientation( -// deviceOrientation: UIDeviceOrientation, -// defaultOrientation: UIDeviceOrientation -// ) -> UIImage.Orientation { -// switch deviceOrientation { -// case .portrait: -// return position == .front ? .leftMirrored : .right -// case .landscapeLeft: -// return position == .front ? .downMirrored : .up -// case .portraitUpsideDown: -// return position == .front ? .rightMirrored : .left -// case .landscapeRight: -// return position == .front ? .upMirrored : .down -// case .faceDown, .faceUp, .unknown: -// return .up -// @unknown default: -// return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait) -// } -// } + func imageOrientation( + deviceOrientation: UIDeviceOrientation, + defaultOrientation: UIDeviceOrientation + ) -> UIImage.Orientation { + switch deviceOrientation { + case .portrait: + return position == .front ? .leftMirrored : .right + case .landscapeLeft: + return position == .front ? .downMirrored : .up + case .portraitUpsideDown: + return position == .front ? .rightMirrored : .left + case .landscapeRight: + return position == .front ? .upMirrored : .down + case .faceDown, .faceUp, .unknown: + return .up + @unknown default: + return imageOrientation(deviceOrientation: defaultOrientation, defaultOrientation: .portrait) + } + } func checkPermission(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { let status = AVCaptureDevice.authorizationStatus(for: .video) @@ -158,22 +159,35 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan let argReader = MapArgumentReader(call.arguments as? [String: Any]) - guard let ratio = argReader.int(key: "ratio"), - let torch = argReader.int(key: "torch"), - let facing = argReader.int(key: "facing") else { - result(FlutterError(code: "INVALID_ARGUMENT", message: "Missing a required argument", details: "Expecting targetWidth, targetHeight, formats, and optionally heartbeatTimeout")) - return - } - +// let ratio: Int = argReader.int(key: "ratio") + let torch: Bool = argReader.bool(key: "torch") ?? false + let facing: Int = argReader.int(key: "facing") ?? 1 + + // Set the camera to use position = facing == 0 ? AVCaptureDevice.Position.front : .back + + // Open the camera device if #available(iOS 10.0, *) { device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: position).devices.first } else { device = AVCaptureDevice.devices(for: .video).filter({$0.position == position}).first } + + // Enable the torch if parameter is set and torch is available + if (device.hasTorch && device.isTorchAvailable) { + do { + try device.lockForConfiguration() + device.torchMode = torch ? .on : .off + device.unlockForConfiguration() + } catch { + error.throwNative(result) + } + } + device.addObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode), options: .new, context: nil) captureSession.beginConfiguration() - // Add device input. + + // Add device input do { let input = try AVCaptureDeviceInput(device: device) captureSession.addInput(input) @@ -205,7 +219,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan result(answer) } - func torchNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + func switchTorch(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { do { try device.lockForConfiguration() device.torchMode = call.arguments as! Int == 1 ? .on : .off @@ -216,12 +230,12 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan } } - func analyzeNative(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { + func switchAnalyzeMode(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) { analyzeMode = call.arguments as! Int result(nil) } - func stopNative(_ result: FlutterResult) { + func stop(_ result: FlutterResult) { captureSession.stopRunning() for input in captureSession.inputs { captureSession.removeInput(input) @@ -241,6 +255,7 @@ public class SwiftMobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHan result(nil) } + // Observer for torch state public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { switch keyPath { case "torchMode": @@ -269,6 +284,10 @@ class MapArgumentReader { func int(key: String) -> Int? { return (args?[key] as? NSNumber)?.intValue } + + func bool(key: String) -> Bool? { + return (args?[key] as? NSNumber)?.boolValue + } func stringArray(key: String) -> [String]? { return args?[key] as? [String] From 24888522d87c15d62bde6fa69f38e100a2d14bf3 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Wed, 16 Feb 2022 09:35:31 +0100 Subject: [PATCH 6/7] style: flutter format --- example/lib/main.dart | 36 +++++++------- example/lib/mobile_scanner_overlay.dart | 63 +++++++++++++------------ lib/mobile_scanner.dart | 2 +- lib/src/mobile_scanner.dart | 10 ++-- lib/src/mobile_scanner_arguments.dart | 3 +- lib/src/mobile_scanner_controller.dart | 19 +++++--- test/mobile_scanner_test.dart | 1 - 7 files changed, 71 insertions(+), 63 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 03d092b06..b41badef9 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,8 +18,10 @@ class _AnalyzeViewState extends State with SingleTickerProviderStateMixin { String? barcode; - MobileScannerController controller = MobileScannerController(torchEnabled: true, - facing: CameraFacing.front,); + MobileScannerController controller = MobileScannerController( + torchEnabled: true, + facing: CameraFacing.front, + ); @override Widget build(BuildContext context) { @@ -30,7 +32,7 @@ class _AnalyzeViewState extends State return Stack( children: [ MobileScanner( - controller: controller, + controller: controller, fit: BoxFit.contain, // controller: MobileScannerController( // torchEnabled: true, @@ -55,20 +57,22 @@ class _AnalyzeViewState extends State children: [ IconButton( color: Colors.white, - icon: ValueListenableBuilder( - valueListenable: controller.torchState, - builder: (context, state, child) { - switch (state as TorchState) { - case TorchState.off: - return const Icon(Icons.flash_off, color: Colors.grey); - case TorchState.on: - return const Icon(Icons.flash_on, color: Colors.yellow); - } - }, - ), - iconSize: 32.0, - onPressed: () => controller.toggleTorch(), + icon: ValueListenableBuilder( + valueListenable: controller.torchState, + builder: (context, state, child) { + switch (state as TorchState) { + case TorchState.off: + return const Icon(Icons.flash_off, + color: Colors.grey); + case TorchState.on: + return const Icon(Icons.flash_on, + color: Colors.yellow); + } + }, ), + iconSize: 32.0, + onPressed: () => controller.toggleTorch(), + ), Center( child: SizedBox( width: MediaQuery.of(context).size.width - 120, diff --git a/example/lib/mobile_scanner_overlay.dart b/example/lib/mobile_scanner_overlay.dart index ec267d5a2..2990caf9d 100644 --- a/example/lib/mobile_scanner_overlay.dart +++ b/example/lib/mobile_scanner_overlay.dart @@ -30,40 +30,41 @@ class _AnalyzeViewState extends State return Stack( children: [ MobileScanner( - // fitScreen: false, + // fitScreen: false, // controller: cameraController, onDetect: (barcode, args) { - if (this.barcode != barcode.rawValue) { - this.barcode = barcode.rawValue; - if (barcode.corners != null) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text('${barcode.rawValue}'), - duration: const Duration(milliseconds: 200), - animation: null, - )); - setState(() { - final List points = []; - double factorWidth = args.size.width / 520; - // double factorHeight = wanted / args.size.height; - final size = MediaQuery.of(context).devicePixelRatio; - debugPrint('Size: ${barcode.corners}'); - for (var point in barcode.corners!) { - final adjustedWith = point.dx ; - final adjustedHeight= point.dy ; - points.add(Offset(adjustedWith / size, adjustedHeight / size)); - // points.add(Offset((point.dx ) / size, - // (point.dy) / size)); - // final differenceWidth = (args.wantedSize!.width - args.size.width) / 2; - // final differenceHeight = (args.wantedSize!.height - args.size.height) / 2; - // points.add(Offset((point.dx + differenceWidth) / size, - // (point.dy + differenceHeight) / size)); - } - this.points = points; - }); + if (this.barcode != barcode.rawValue) { + this.barcode = barcode.rawValue; + if (barcode.corners != null) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text('${barcode.rawValue}'), + duration: const Duration(milliseconds: 200), + animation: null, + )); + setState(() { + final List points = []; + double factorWidth = args.size.width / 520; + // double factorHeight = wanted / args.size.height; + final size = MediaQuery.of(context).devicePixelRatio; + debugPrint('Size: ${barcode.corners}'); + for (var point in barcode.corners!) { + final adjustedWith = point.dx; + final adjustedHeight = point.dy; + points.add( + Offset(adjustedWith / size, adjustedHeight / size)); + // points.add(Offset((point.dx ) / size, + // (point.dy) / size)); + // final differenceWidth = (args.wantedSize!.width - args.size.width) / 2; + // final differenceHeight = (args.wantedSize!.height - args.size.height) / 2; + // points.add(Offset((point.dx + differenceWidth) / size, + // (point.dy + differenceHeight) / size)); } - } - // Default 640 x480 - }), + this.points = points; + }); + } + } + // Default 640 x480 + }), CustomPaint( painter: OpenPainter(points), ), diff --git a/lib/mobile_scanner.dart b/lib/mobile_scanner.dart index c04766e63..bdbdf5d51 100644 --- a/lib/mobile_scanner.dart +++ b/lib/mobile_scanner.dart @@ -2,4 +2,4 @@ library mobile_scanner; export 'src/mobile_scanner.dart'; export 'src/mobile_scanner_controller.dart'; -export 'src/objects/barcode.dart'; \ No newline at end of file +export 'src/objects/barcode.dart'; diff --git a/lib/src/mobile_scanner.dart b/lib/src/mobile_scanner.dart index 1e5bcba63..aa6fc13d8 100644 --- a/lib/src/mobile_scanner.dart +++ b/lib/src/mobile_scanner.dart @@ -3,10 +3,7 @@ import 'package:mobile_scanner/mobile_scanner.dart'; import 'mobile_scanner_arguments.dart'; -enum Ratio { - ratio_4_3, - ratio_16_9 -} +enum Ratio { ratio_4_3, ratio_16_9 } /// A widget showing a live camera preview. class MobileScanner extends StatefulWidget { @@ -18,7 +15,8 @@ class MobileScanner extends StatefulWidget { /// Create a [MobileScanner] with a [controller], the [controller] must has been initialized. const MobileScanner( {Key? key, this.onDetect, this.controller, this.fit = BoxFit.cover}) - : assert((controller != null )), super(key: key); + : assert((controller != null)), + super(key: key); @override State createState() => _MobileScannerState(); @@ -91,4 +89,4 @@ class _MobileScannerState extends State controller.dispose(); super.dispose(); } -} \ No newline at end of file +} diff --git a/lib/src/mobile_scanner_arguments.dart b/lib/src/mobile_scanner_arguments.dart index 6cdda9508..3fb6dcda7 100644 --- a/lib/src/mobile_scanner_arguments.dart +++ b/lib/src/mobile_scanner_arguments.dart @@ -11,5 +11,6 @@ class MobileScannerArguments { final bool hasTorch; /// Create a [MobileScannerArguments]. - MobileScannerArguments({required this.textureId,required this.size, required this.hasTorch}); + MobileScannerArguments( + {required this.textureId, required this.size, required this.hasTorch}); } diff --git a/lib/src/mobile_scanner_controller.dart b/lib/src/mobile_scanner_controller.dart index cdaabd06b..7ed8f1a81 100644 --- a/lib/src/mobile_scanner_controller.dart +++ b/lib/src/mobile_scanner_controller.dart @@ -38,7 +38,6 @@ class MobileScannerController { int? _controllerHashcode; StreamSubscription? events; - final ValueNotifier args = ValueNotifier(null); final ValueNotifier torchState = ValueNotifier(TorchState.off); late final ValueNotifier cameraFacingState; @@ -107,7 +106,8 @@ class MobileScannerController { setAnalyzeMode(AnalyzeMode.barcode.index); // Check authorization status - MobileScannerState state = MobileScannerState.values[await methodChannel.invokeMethod('state')]; + MobileScannerState state = + MobileScannerState.values[await methodChannel.invokeMethod('state')]; switch (state) { case MobileScannerState.undetermined: final bool result = await methodChannel.invokeMethod('request'); @@ -129,13 +129,17 @@ class MobileScannerController { if (torchEnabled != null) arguments['torch'] = torchEnabled; // Start the camera with arguments - final Map? startResult = await methodChannel.invokeMapMethod( - 'start', arguments); + final Map? startResult = await methodChannel + .invokeMapMethod('start', arguments); - if (startResult == null) throw PlatformException(code: 'INITIALIZATION ERROR'); + if (startResult == null) + throw PlatformException(code: 'INITIALIZATION ERROR'); hasTorch = startResult['torchable']; - args.value = MobileScannerArguments(textureId: startResult['textureId'], size: toSize(startResult['size']), hasTorch: hasTorch); + args.value = MobileScannerArguments( + textureId: startResult['textureId'], + size: toSize(startResult['size']), + hasTorch: hasTorch); } Future stop() async => await methodChannel.invokeMethod('stop'); @@ -157,7 +161,8 @@ class MobileScannerController { Future switchCamera() async { ensure('switchCamera'); await stop(); - facing = facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back; + facing = + facing == CameraFacing.back ? CameraFacing.front : CameraFacing.back; start(); } diff --git a/test/mobile_scanner_test.dart b/test/mobile_scanner_test.dart index 64a664d9a..90e05876c 100644 --- a/test/mobile_scanner_test.dart +++ b/test/mobile_scanner_test.dart @@ -16,5 +16,4 @@ void main() { tearDown(() { channel.setMockMethodCallHandler(null); }); - } From dc7f855dd57a716a2e071641d2c0ecae404ea833 Mon Sep 17 00:00:00 2001 From: Julian Steenbakker Date: Wed, 16 Feb 2022 09:37:08 +0100 Subject: [PATCH 7/7] style: flutter lints --- example/lib/main.dart | 2 -- example/lib/mobile_scanner_overlay.dart | 8 ++++---- example/test/widget_test.dart | 3 --- lib/src/mobile_scanner_controller.dart | 3 ++- lib/src/objects/barcode.dart | 8 ++++---- lib/src/objects/barcode_utility.dart | 8 ++++---- test/mobile_scanner_test.dart | 1 - 7 files changed, 14 insertions(+), 19 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index b41badef9..3ba4deb1a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,3 @@ -import 'dart:ui'; - import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; diff --git a/example/lib/mobile_scanner_overlay.dart b/example/lib/mobile_scanner_overlay.dart index 2990caf9d..44238c5ef 100644 --- a/example/lib/mobile_scanner_overlay.dart +++ b/example/lib/mobile_scanner_overlay.dart @@ -20,7 +20,7 @@ class _AnalyzeViewState extends State // CameraController cameraController = CameraController(context, width: 320, height: 150); - String? barcode = null; + String? barcode; @override Widget build(BuildContext context) { @@ -37,13 +37,13 @@ class _AnalyzeViewState extends State this.barcode = barcode.rawValue; if (barcode.corners != null) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text('${barcode.rawValue}'), + content: Text(barcode.rawValue), duration: const Duration(milliseconds: 200), animation: null, )); setState(() { final List points = []; - double factorWidth = args.size.width / 520; + // double factorWidth = args.size.width / 520; // double factorHeight = wanted / args.size.height; final size = MediaQuery.of(context).devicePixelRatio; debugPrint('Size: ${barcode.corners}'); @@ -109,7 +109,7 @@ class OpenPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { var paint1 = Paint() - ..color = Color(0xff63aa65) + ..color = const Color(0xff63aa65) ..strokeWidth = 10; //draw points on canvas canvas.drawPoints(PointMode.points, points, paint1); diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 971d6db5a..7fdea585b 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -5,11 +5,8 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mobile_scanner_example/main.dart'; - void main() { testWidgets('Verify Platform version', (WidgetTester tester) async { // Build our app and trigger a frame. diff --git a/lib/src/mobile_scanner_controller.dart b/lib/src/mobile_scanner_controller.dart index 7ed8f1a81..01ba23a18 100644 --- a/lib/src/mobile_scanner_controller.dart +++ b/lib/src/mobile_scanner_controller.dart @@ -132,8 +132,9 @@ class MobileScannerController { final Map? startResult = await methodChannel .invokeMapMethod('start', arguments); - if (startResult == null) + if (startResult == null) { throw PlatformException(code: 'INITIALIZATION ERROR'); + } hasTorch = startResult['torchable']; args.value = MobileScannerArguments( diff --git a/lib/src/objects/barcode.dart b/lib/src/objects/barcode.dart index eca90f12f..8b9430084 100644 --- a/lib/src/objects/barcode.dart +++ b/lib/src/objects/barcode.dart @@ -490,7 +490,7 @@ enum BarcodeFormat { /// Barcode format constant for Data Matrix. /// /// Constant Value: 16 - data_matrix, + dataMatrix, /// Barcode format constant for EAN-13. /// @@ -510,17 +510,17 @@ enum BarcodeFormat { /// Barcode format constant for QR Code. /// /// Constant Value: 256 - qr_code, + qrCode, /// Barcode format constant for UPC-A. /// /// Constant Value: 512 - upc_a, + upcA, /// Barcode format constant for UPC-E. /// /// Constant Value: 1024 - upc_e, + upcE, /// Barcode format constant for PDF-417. /// diff --git a/lib/src/objects/barcode_utility.dart b/lib/src/objects/barcode_utility.dart index 9b122fff3..bc03d00b5 100644 --- a/lib/src/objects/barcode_utility.dart +++ b/lib/src/objects/barcode_utility.dart @@ -29,7 +29,7 @@ BarcodeFormat toFormat(int value) { case 8: return BarcodeFormat.codebar; case 16: - return BarcodeFormat.data_matrix; + return BarcodeFormat.dataMatrix; case 32: return BarcodeFormat.ean13; case 64: @@ -37,11 +37,11 @@ BarcodeFormat toFormat(int value) { case 128: return BarcodeFormat.itf; case 256: - return BarcodeFormat.qr_code; + return BarcodeFormat.qrCode; case 512: - return BarcodeFormat.upc_a; + return BarcodeFormat.upcA; case 1024: - return BarcodeFormat.upc_e; + return BarcodeFormat.upcE; case 2048: return BarcodeFormat.pdf417; case 4096: diff --git a/test/mobile_scanner_test.dart b/test/mobile_scanner_test.dart index 90e05876c..aa3608f52 100644 --- a/test/mobile_scanner_test.dart +++ b/test/mobile_scanner_test.dart @@ -1,6 +1,5 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:mobile_scanner/src/mobile_scanner.dart'; void main() { const MethodChannel channel = MethodChannel('mobile_scanner');