From 762a5594dda4eb0503e702c9508a10d6d2b8d4f6 Mon Sep 17 00:00:00 2001 From: WilliamVerhaeghe Date: Tue, 7 Dec 2021 17:15:18 +0100 Subject: [PATCH 1/8] Implement camera switching for Android --- .../fast_barcode_scanner/BarcodeReader.kt | 18 +++++---- .../FastBarcodeScannerPlugin.kt | 1 + .../example/lib/scanner_screen.dart | 20 +++++----- .../lib/src/camera_controller.dart | 38 +++++++++++++------ 4 files changed, 47 insertions(+), 30 deletions(-) diff --git a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt index b8b00366..793f38ac 100644 --- a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt +++ b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt @@ -23,7 +23,7 @@ import java.util.ArrayList import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -data class CameraConfig(val formats: IntArray, val mode: DetectionMode, val resolution: Resolution, val framerate: Framerate, val position: CameraPosition) +data class CameraConfig(val formats: IntArray, val mode: DetectionMode, val resolution: Resolution, val framerate: Framerate, var position: CameraPosition) class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceTextureEntry, private val listener: (List) -> Unit) : RequestPermissionsResultListener { /* Android Lifecycle */ @@ -106,6 +106,14 @@ class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceText }, ContextCompat.getMainExecutor(activity)) } + fun changeCamera(position: String, result: Result) { + cameraConfig.position = when (position) { + "front" -> CameraPosition.front + else -> CameraPosition.back + } + initCamera() + } + private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { ContextCompat.checkSelfPermission(activity!!.applicationContext, it) == PackageManager.PERMISSION_GRANTED } @@ -148,12 +156,8 @@ class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceText // Select camera val selectorBuilder = CameraSelector.Builder() when (cameraConfig.position) { - CameraPosition.front -> { - selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_FRONT) - } - CameraPosition.back -> { - selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_BACK) - } + CameraPosition.front -> selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_FRONT) + CameraPosition.back -> selectorBuilder.requireLensFacing(CameraSelector.LENS_FACING_BACK) } cameraSelector = selectorBuilder.build() diff --git a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt index a7223391..2f36d963 100644 --- a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt +++ b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt @@ -58,6 +58,7 @@ class FastBarcodeScannerPlugin: FlutterPlugin, MethodCallHandler, ActivityAware "pause" -> reader.stop(result) "resume" -> reader.resume(result) "toggleTorch" -> reader.toggleTorch(result) + "changeCamera" -> reader.changeCamera(call.arguments as String, result) else -> result.notImplemented() } } diff --git a/fast_barcode_scanner/example/lib/scanner_screen.dart b/fast_barcode_scanner/example/lib/scanner_screen.dart index 2ced323c..f3ff2ce8 100644 --- a/fast_barcode_scanner/example/lib/scanner_screen.dart +++ b/fast_barcode_scanner/example/lib/scanner_screen.dart @@ -32,25 +32,23 @@ class _ScannerScreenState extends State { ValueListenableBuilder( valueListenable: _torchIconState, builder: (context, state, _) => IconButton( - icon: state - ? const Icon(Icons.flash_on) - : const Icon(Icons.flash_off), + icon: state ? const Icon(Icons.flash_on) : const Icon(Icons.flash_off), onPressed: () async { await CameraController.instance.toggleTorch(); - _torchIconState.value = - CameraController.instance.state.torchState; + _torchIconState.value = CameraController.instance.state.torchState; }, ), ), + IconButton( + icon: const Icon(Icons.cameraswitch), + onPressed: () async { + await CameraController.instance.toggleCamera(); + }, + ), ], ), body: BarcodeCamera( - types: const [ - BarcodeType.ean8, - BarcodeType.ean13, - BarcodeType.code128, - BarcodeType.qr - ], + types: const [BarcodeType.ean8, BarcodeType.ean13, BarcodeType.code128, BarcodeType.qr], resolution: Resolution.hd720, framerate: Framerate.fps30, mode: DetectionMode.pauseVideo, diff --git a/fast_barcode_scanner/lib/src/camera_controller.dart b/fast_barcode_scanner/lib/src/camera_controller.dart index d88e69b0..e517d044 100644 --- a/fast_barcode_scanner/lib/src/camera_controller.dart +++ b/fast_barcode_scanner/lib/src/camera_controller.dart @@ -5,8 +5,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; class CameraConfiguration { - const CameraConfiguration(this.types, this.resolution, this.framerate, - this.detectionMode, this.position); + const CameraConfiguration( + this.types, + this.resolution, + this.framerate, + this.detectionMode, + this.position, + ); /// The types the scanner should look out for. /// @@ -38,6 +43,7 @@ class CameraState { PreviewConfiguration? _previewConfig; bool _torchState = false; bool _togglingTorch = false; + CameraPosition? position; Object? _error; Object? get error => _error; @@ -62,8 +68,7 @@ class CameraController { /// errors and events. final CameraState state; - FastBarcodeScannerPlatform get _platform => - FastBarcodeScannerPlatform.instance; + FastBarcodeScannerPlatform get _platform => FastBarcodeScannerPlatform.instance; // Intents @@ -73,18 +78,19 @@ class CameraController { /// method repeatedly. /// Events and errors are received via the current state's eventNotifier. Future initialize( - List types, - Resolution resolution, - Framerate framerate, - DetectionMode detectionMode, - CameraPosition position, - void Function(Barcode)? onScan) async { + List types, + Resolution resolution, + Framerate framerate, + DetectionMode detectionMode, + CameraPosition position, + void Function(Barcode)? onScan, + ) async { state.eventNotifier.value = CameraEvent.init; + state.position = position; try { if (state.isInitialized) await _platform.dispose(); - state._previewConfig = await _platform.init( - types, resolution, framerate, detectionMode, position); + state._previewConfig = await _platform.init(types, resolution, framerate, detectionMode, position); /// Notify the overlays when a barcode is detected and then call [onDetect]. _platform.setOnDetectHandler((code) { @@ -168,6 +174,14 @@ class CameraController { } } + /// Toggles the camera, if available. + /// + /// + Future toggleCamera() async { + state.position = state.position == CameraPosition.back ? CameraPosition.front : CameraPosition.back; + return changeCamera(state.position!); + } + Future changeCamera(CameraPosition position) async { try { await _platform.changeCamera(position); From c42e65a4ca5eaa022194c0ecf02b914c0e87e2b3 Mon Sep 17 00:00:00 2001 From: WilliamVerhaeghe Date: Wed, 8 Dec 2021 14:25:45 +0100 Subject: [PATCH 2/8] Add method canChangeCamera --- .../fast_barcode_scanner/BarcodeReader.kt | 14 +++++++++++ .../FastBarcodeScannerPlugin.kt | 1 + .../example/lib/scanner_screen.dart | 25 ++++++++++++++----- fast_barcode_scanner/example/pubspec.yaml | 4 +++ .../Classes/FastBarcodeScannerPlugin.swift | 5 ++++ .../lib/src/camera_controller.dart | 12 ++++++--- ...st_barcode_scanner_platform_interface.dart | 4 +++ .../method_channel_fast_barcode_scanner.dart | 4 +++ 8 files changed, 60 insertions(+), 9 deletions(-) diff --git a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt index 793f38ac..5b6295a8 100644 --- a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt +++ b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/BarcodeReader.kt @@ -106,6 +106,20 @@ class BarcodeReader(private val flutterTextureEntry: TextureRegistry.SurfaceText }, ContextCompat.getMainExecutor(activity)) } + fun canChangeCamera(result: Result) { + try { + val cameraProviderFuture = ProcessCameraProvider.getInstance(activity!!) + cameraProviderFuture.addListener(Runnable { + val cameraProviderForChangeCamera = cameraProviderFuture.get() + val hasFrontCamera = cameraProviderForChangeCamera.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) + val hasBackCamera = cameraProviderForChangeCamera.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) + result.success(hasFrontCamera && hasBackCamera) + }, ContextCompat.getMainExecutor(activity!!)) + } catch (exc: Exception) { + result.success(false) + } + } + fun changeCamera(position: String, result: Result) { cameraConfig.position = when (position) { "front" -> CameraPosition.front diff --git a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt index 2f36d963..0fa2505d 100644 --- a/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt +++ b/fast_barcode_scanner/android/src/main/kotlin/com/jhoogstraat/fast_barcode_scanner/FastBarcodeScannerPlugin.kt @@ -58,6 +58,7 @@ class FastBarcodeScannerPlugin: FlutterPlugin, MethodCallHandler, ActivityAware "pause" -> reader.stop(result) "resume" -> reader.resume(result) "toggleTorch" -> reader.toggleTorch(result) + "canChangeCamera" -> reader.canChangeCamera(result) "changeCamera" -> reader.changeCamera(call.arguments as String, result) else -> result.notImplemented() } diff --git a/fast_barcode_scanner/example/lib/scanner_screen.dart b/fast_barcode_scanner/example/lib/scanner_screen.dart index f3ff2ce8..2abb089c 100644 --- a/fast_barcode_scanner/example/lib/scanner_screen.dart +++ b/fast_barcode_scanner/example/lib/scanner_screen.dart @@ -15,6 +15,20 @@ class ScannerScreen extends StatefulWidget { class _ScannerScreenState extends State { final _torchIconState = ValueNotifier(false); + var _canChangeCamera = false; + + @override + void initState() { + super.initState(); + _checkCamera(); + } + + Future _checkCamera() async { + final canChangeCamera = await CameraController.instance.canChangeCamera(); + setState(() { + _canChangeCamera = canChangeCamera; + }); + } @override Widget build(BuildContext context) { @@ -39,12 +53,11 @@ class _ScannerScreenState extends State { }, ), ), - IconButton( - icon: const Icon(Icons.cameraswitch), - onPressed: () async { - await CameraController.instance.toggleCamera(); - }, - ), + if (_canChangeCamera) + IconButton( + icon: const Icon(Icons.cameraswitch), + onPressed: CameraController.instance.toggleCamera, + ), ], ), body: BarcodeCamera( diff --git a/fast_barcode_scanner/example/pubspec.yaml b/fast_barcode_scanner/example/pubspec.yaml index fc386e2a..79abea84 100644 --- a/fast_barcode_scanner/example/pubspec.yaml +++ b/fast_barcode_scanner/example/pubspec.yaml @@ -15,5 +15,9 @@ dependencies: dev_dependencies: flutter_lints: ^1.0.4 +dependency_overrides: + fast_barcode_scanner_platform_interface: + path: ../../fast_barcode_scanner_platform_interface/ + flutter: uses-material-design: true \ No newline at end of file diff --git a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift index 83e6ceb8..e0d773f6 100644 --- a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift +++ b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift @@ -55,6 +55,7 @@ public class FastBarcodeScannerPlugin: NSObject, FlutterPlugin { case "pause": pause(result: result) case "resume": try resume(result: result) case "toggleTorch": toggleTorch(result: result) + case "canChangeCamera": canChangeCamera(result: result) case "heartBeat": result(nil) default: result(FlutterMethodNotImplemented) } @@ -131,6 +132,10 @@ public class FastBarcodeScannerPlugin: NSObject, FlutterPlugin { result(reader?.toggleTorch()) } + func canChangeCamera(result: @escaping FlutterResult) { + result(true) + } + func stop(result: @escaping FlutterResult) { reader?.stop(pause: false) reader = nil diff --git a/fast_barcode_scanner/lib/src/camera_controller.dart b/fast_barcode_scanner/lib/src/camera_controller.dart index e517d044..f68e2133 100644 --- a/fast_barcode_scanner/lib/src/camera_controller.dart +++ b/fast_barcode_scanner/lib/src/camera_controller.dart @@ -68,7 +68,8 @@ class CameraController { /// errors and events. final CameraState state; - FastBarcodeScannerPlatform get _platform => FastBarcodeScannerPlatform.instance; + FastBarcodeScannerPlatform get _platform => + FastBarcodeScannerPlatform.instance; // Intents @@ -90,7 +91,8 @@ class CameraController { try { if (state.isInitialized) await _platform.dispose(); - state._previewConfig = await _platform.init(types, resolution, framerate, detectionMode, position); + state._previewConfig = await _platform.init( + types, resolution, framerate, detectionMode, position); /// Notify the overlays when a barcode is detected and then call [onDetect]. _platform.setOnDetectHandler((code) { @@ -178,10 +180,14 @@ class CameraController { /// /// Future toggleCamera() async { - state.position = state.position == CameraPosition.back ? CameraPosition.front : CameraPosition.back; + state.position = state.position == CameraPosition.back + ? CameraPosition.front + : CameraPosition.back; return changeCamera(state.position!); } + Future canChangeCamera() => _platform.canChangeCamera(); + Future changeCamera(CameraPosition position) async { try { await _platform.changeCamera(position); diff --git a/fast_barcode_scanner_platform_interface/lib/src/fast_barcode_scanner_platform_interface.dart b/fast_barcode_scanner_platform_interface/lib/src/fast_barcode_scanner_platform_interface.dart index c53f6c9b..b10ce0a3 100644 --- a/fast_barcode_scanner_platform_interface/lib/src/fast_barcode_scanner_platform_interface.dart +++ b/fast_barcode_scanner_platform_interface/lib/src/fast_barcode_scanner_platform_interface.dart @@ -68,6 +68,10 @@ abstract class FastBarcodeScannerPlatform extends PlatformInterface { throw UnimplementedError('changeCamera() has not been implemented'); } + Future canChangeCamera() { + throw UnimplementedError('canChangeCamera() has not been implemented'); + } + /// Set the method to be called when a barcode is detected void setOnDetectHandler(void Function(Barcode) handler) { throw UnimplementedError('setOnReadHandler() has not been implemented'); diff --git a/fast_barcode_scanner_platform_interface/lib/src/method_channel_fast_barcode_scanner.dart b/fast_barcode_scanner_platform_interface/lib/src/method_channel_fast_barcode_scanner.dart index 255bd42d..7d84da22 100644 --- a/fast_barcode_scanner_platform_interface/lib/src/method_channel_fast_barcode_scanner.dart +++ b/fast_barcode_scanner_platform_interface/lib/src/method_channel_fast_barcode_scanner.dart @@ -68,6 +68,10 @@ class MethodChannelFastBarcodeScanner extends FastBarcodeScannerPlatform { .invokeMethod('changeCamera', describeEnum(position)) .then((success) => success); + @override + Future canChangeCamera() => + _channel.invokeMethod('canChangeCamera').then((success) => success); + @override void setOnDetectHandler(void Function(Barcode) handler) => _onDetectHandler = handler; From 22d7372f3e9a03d57274683ea1a631a7a93d05a1 Mon Sep 17 00:00:00 2001 From: Herre Date: Thu, 9 Dec 2021 15:54:12 +0100 Subject: [PATCH 3/8] Switch camera on iOS --- .../ios/Classes/BarcodeReader.swift | 116 +++++++++++++----- .../Classes/FastBarcodeScannerPlugin.swift | 24 ++++ 2 files changed, 111 insertions(+), 29 deletions(-) diff --git a/fast_barcode_scanner/ios/Classes/BarcodeReader.swift b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift index b1c2a333..1316ecb4 100644 --- a/fast_barcode_scanner/ios/Classes/BarcodeReader.swift +++ b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift @@ -88,30 +88,50 @@ class BarcodeReader: NSObject { var captureDevice: AVCaptureDevice! var captureSession: AVCaptureSession let dataOutput: AVCaptureVideoDataOutput + var metadataOutput: AVCaptureMetadataOutput let codeCallback: ([String]) -> Void - let detectionMode: DetectionMode - let position: AVCaptureDevice.Position + + var position: AVCaptureDevice.Position + let detectionMode: DetectionMode + let framerate: Framerate + let resolution: Resolution + let codes: [String] + var torchActiveOnStop = false var previewSize: CMVideoDimensions! init(textureRegistry: FlutterTextureRegistry, - arguments: StartArgs, - codeCallback: @escaping ([String]) -> Void) throws { - self.textureRegistry = textureRegistry + arguments: StartArgs, + codeCallback: @escaping ([String]) -> Void) throws { + self.textureRegistry = textureRegistry self.codeCallback = codeCallback - self.captureSession = AVCaptureSession() + + self.captureSession = AVCaptureSession() self.dataOutput = AVCaptureVideoDataOutput() self.metadataOutput = AVCaptureMetadataOutput() - self.detectionMode = arguments.detectionMode + + self.detectionMode = arguments.detectionMode self.position = arguments.position + self.framerate = arguments.framerate + self.resolution = arguments.resolution + self.codes = arguments.codes + super.init() - captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) + do { + try setupCaptureDevice(arguments) + } catch { + throw error + } + } + + private func setupCaptureDevice(_ arguments: StartArgs) throws { + captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) - guard captureDevice != nil else { - throw ReaderError.noInputDevice - } + guard captureDevice != nil else { + throw ReaderError.noInputDevice + } do { let input = try AVCaptureDeviceInput(device: captureDevice) @@ -126,25 +146,25 @@ class BarcodeReader: NSObject { captureSession.addOutput(dataOutput) captureSession.addOutput(metadataOutput) - dataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] - dataOutput.connection(with: .video)?.videoOrientation = .portrait - dataOutput.alwaysDiscardsLateVideoFrames = true - dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: .default)) + dataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] + dataOutput.connection(with: .video)?.videoOrientation = .portrait + dataOutput.alwaysDiscardsLateVideoFrames = true + dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: .default)) - metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global(qos: .default)) - metadataOutput.metadataObjectTypes = arguments.codes.compactMap { avMetadataObjectTypes[$0] } + metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global(qos: .default)) + metadataOutput.metadataObjectTypes = arguments.codes.compactMap { avMetadataObjectTypes[$0] } - guard let optimalFormat = captureDevice.formats.first(where: { - let dimensions = CMVideoFormatDescriptionGetDimensions($0.formatDescription) - let mediaSubType = CMFormatDescriptionGetMediaSubType($0.formatDescription).toString() + guard let optimalFormat = captureDevice.formats.first(where: { + let dimensions = CMVideoFormatDescriptionGetDimensions($0.formatDescription) + let mediaSubType = CMFormatDescriptionGetMediaSubType($0.formatDescription).toString() - return $0.videoSupportedFrameRateRanges.first!.maxFrameRate >= arguments.framerate.doubleValue - && dimensions.height >= arguments.resolution.height - && dimensions.width >= arguments.resolution.width - && mediaSubType == "420f" // maybe 420v is also ok? Who knows... - }) else { - throw ReaderError.cameraNotSuitable(arguments.resolution, arguments.framerate) - } + return $0.videoSupportedFrameRateRanges.first!.maxFrameRate >= arguments.framerate.doubleValue + && dimensions.height >= arguments.resolution.height + && dimensions.width >= arguments.resolution.width + && mediaSubType == "420f" // maybe 420v is also ok? Who knows... + }) else { + throw ReaderError.cameraNotSuitable(arguments.resolution, arguments.framerate) + } do { try captureDevice.lockForConfiguration() @@ -158,8 +178,8 @@ class BarcodeReader: NSObject { throw ReaderError.configurationLockError(error) } - previewSize = CMVideoFormatDescriptionGetDimensions(captureDevice.activeFormat.formatDescription) - } + previewSize = CMVideoFormatDescriptionGetDimensions(captureDevice.activeFormat.formatDescription) + } func start(fromPause: Bool) throws { guard captureDevice != nil else { return } @@ -237,9 +257,47 @@ class BarcodeReader: NSObject { try start(fromPause: true) } } + + func changeCamera(type: String) { + position = type == "front" ? .front : .back + reloadCamera() + } + + func toggleCamera() { + position = position.toggled() + reloadCamera() + } + + private func reloadCamera() { + captureSession.stopRunning() + + captureSession.outputs.forEach { captureSession.removeOutput($0) } + captureSession.inputs.forEach { captureSession.removeInput($0) } + + do { + let arguments = StartArgs(position: position, detectionMode: detectionMode, framerate: framerate, resolution: resolution, codes: codes) + try setupCaptureDevice(arguments) + } catch { + print(error) + } + + captureSession.startRunning() + } } +private extension AVCaptureDevice.Position { + + func toggled() -> AVCaptureDevice.Position { + switch self { + case .back: + return .front + default: + return .back + } + } +} + extension BarcodeReader: FlutterTexture { func copyPixelBuffer() -> Unmanaged? { pixelBuffer == nil ? nil : .passRetained(pixelBuffer!) diff --git a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift index e0d773f6..69e371ed 100644 --- a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift +++ b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift @@ -20,6 +20,14 @@ struct StartArgs { self.detectionMode = detectionMode self.codes = codes } + + init(position: AVCaptureDevice.Position, detectionMode: DetectionMode, framerate: Framerate, resolution: Resolution, codes: [String]) { + self.position = position + self.detectionMode = detectionMode + self.framerate = framerate + self.resolution = resolution + self.codes = codes + } let position: AVCaptureDevice.Position let framerate: Framerate @@ -57,6 +65,8 @@ public class FastBarcodeScannerPlugin: NSObject, FlutterPlugin { case "toggleTorch": toggleTorch(result: result) case "canChangeCamera": canChangeCamera(result: result) case "heartBeat": result(nil) + case "changeCamera": changeCamera(call: call, result: result) + case "toggleCamera": toggleCamera(result) default: result(FlutterMethodNotImplemented) } } catch { @@ -141,4 +151,18 @@ public class FastBarcodeScannerPlugin: NSObject, FlutterPlugin { reader = nil result(nil) } + + func changeCamera(call: FlutterMethodCall, result: @escaping FlutterResult) { + guard let type = call.arguments as? String else { + result(false) + return + } + reader?.changeCamera(type: type) + result(true) + } + + func toggleCamera(result: @escaping FlutterResult) { + reader?.toggleCamera() + result(true) + } } From 7e5e25ee6d37f772fdb88c4ba6d6beaad7474d7c Mon Sep 17 00:00:00 2001 From: WilliamVerhaeghe Date: Thu, 9 Dec 2021 16:07:29 +0100 Subject: [PATCH 4/8] Fix build issue --- fast_barcode_scanner/example/pubspec.yaml | 1 + fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fast_barcode_scanner/example/pubspec.yaml b/fast_barcode_scanner/example/pubspec.yaml index 79abea84..4ce60a38 100644 --- a/fast_barcode_scanner/example/pubspec.yaml +++ b/fast_barcode_scanner/example/pubspec.yaml @@ -1,6 +1,7 @@ name: fast_barcode_scanner_example description: Demonstrates how to use the fast_barcode_scanner plugin. publish_to: 'none' +version: 0.0.1+1 environment: sdk: '>=2.12.0 <3.0.0' diff --git a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift index 69e371ed..1cff79e6 100644 --- a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift +++ b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift @@ -66,7 +66,7 @@ public class FastBarcodeScannerPlugin: NSObject, FlutterPlugin { case "canChangeCamera": canChangeCamera(result: result) case "heartBeat": result(nil) case "changeCamera": changeCamera(call: call, result: result) - case "toggleCamera": toggleCamera(result) + case "toggleCamera": toggleCamera(result: result) default: result(FlutterMethodNotImplemented) } } catch { From 8f5c69acfb58692bc8f232d74923cdc3aaebb704 Mon Sep 17 00:00:00 2001 From: WilliamVerhaeghe Date: Tue, 28 Dec 2021 16:50:31 +0100 Subject: [PATCH 5/8] Fixed PR Comments --- .../example/lib/scanner_screen.dart | 27 +- .../ios/Classes/BarcodeReader.swift | 320 +++++++++--------- 2 files changed, 177 insertions(+), 170 deletions(-) diff --git a/fast_barcode_scanner/example/lib/scanner_screen.dart b/fast_barcode_scanner/example/lib/scanner_screen.dart index 2abb089c..60819c9e 100644 --- a/fast_barcode_scanner/example/lib/scanner_screen.dart +++ b/fast_barcode_scanner/example/lib/scanner_screen.dart @@ -15,20 +15,17 @@ class ScannerScreen extends StatefulWidget { class _ScannerScreenState extends State { final _torchIconState = ValueNotifier(false); - var _canChangeCamera = false; + bool _canChangeCamera = false; @override void initState() { super.initState(); - _checkCamera(); + _checkCanChangeCamera(); } - Future _checkCamera() async { - final canChangeCamera = await CameraController.instance.canChangeCamera(); - setState(() { - _canChangeCamera = canChangeCamera; - }); - } + Future _checkCanChangeCamera() async => setState(() async { + _canChangeCamera = await CameraController.instance.canChangeCamera(); + }); @override Widget build(BuildContext context) { @@ -46,10 +43,13 @@ class _ScannerScreenState extends State { ValueListenableBuilder( valueListenable: _torchIconState, builder: (context, state, _) => IconButton( - icon: state ? const Icon(Icons.flash_on) : const Icon(Icons.flash_off), + icon: state + ? const Icon(Icons.flash_on) + : const Icon(Icons.flash_off), onPressed: () async { await CameraController.instance.toggleTorch(); - _torchIconState.value = CameraController.instance.state.torchState; + _torchIconState.value = + CameraController.instance.state.torchState; }, ), ), @@ -61,7 +61,12 @@ class _ScannerScreenState extends State { ], ), body: BarcodeCamera( - types: const [BarcodeType.ean8, BarcodeType.ean13, BarcodeType.code128, BarcodeType.qr], + types: const [ + BarcodeType.ean8, + BarcodeType.ean13, + BarcodeType.code128, + BarcodeType.qr + ], resolution: Resolution.hd720, framerate: Framerate.fps30, mode: DetectionMode.pauseVideo, diff --git a/fast_barcode_scanner/ios/Classes/BarcodeReader.swift b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift index 1316ecb4..8fd240b5 100644 --- a/fast_barcode_scanner/ios/Classes/BarcodeReader.swift +++ b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift @@ -23,22 +23,22 @@ let avMetadataObjectTypes: [String: AVMetadataObject.ObjectType] = "pdf417": .pdf417, "qr": .qr, "upcE": .upce, - "interleaved": .interleaved2of5 -] + "interleaved": .interleaved2of5, + ] -let cameraPositions: [String: AVCaptureDevice.Position] = [ - "front": .front, - "back": .back +let cameraPositions: [String: AVCaptureDevice.Position] = [ + "front": .front, + "back": .back, ] // Reverse lookup flutter type -let flutterMetadataObjectTypes = Dictionary(uniqueKeysWithValues: avMetadataObjectTypes.map({ ($1, $0) })) +let flutterMetadataObjectTypes = Dictionary(uniqueKeysWithValues: avMetadataObjectTypes.map { ($1, $0) }) enum ReaderError: Error { case noInputDevice case cameraNotSuitable(Resolution, Framerate) - case unauthorized - case configurationLockError(Error) + case unauthorized + case configurationLockError(Error) } enum Resolution: String { @@ -88,123 +88,124 @@ class BarcodeReader: NSObject { var captureDevice: AVCaptureDevice! var captureSession: AVCaptureSession let dataOutput: AVCaptureVideoDataOutput - - var metadataOutput: AVCaptureMetadataOutput + + var metadataOutput: AVCaptureMetadataOutput let codeCallback: ([String]) -> Void - - var position: AVCaptureDevice.Position - let detectionMode: DetectionMode - let framerate: Framerate - let resolution: Resolution - let codes: [String] - + + var position: AVCaptureDevice.Position + let detectionMode: DetectionMode + let framerate: Framerate + let resolution: Resolution + let codes: [String] + var torchActiveOnStop = false var previewSize: CMVideoDimensions! init(textureRegistry: FlutterTextureRegistry, - arguments: StartArgs, - codeCallback: @escaping ([String]) -> Void) throws { - self.textureRegistry = textureRegistry + arguments: StartArgs, + codeCallback: @escaping ([String]) -> Void) throws + { + self.textureRegistry = textureRegistry self.codeCallback = codeCallback - - self.captureSession = AVCaptureSession() - self.dataOutput = AVCaptureVideoDataOutput() - self.metadataOutput = AVCaptureMetadataOutput() - - self.detectionMode = arguments.detectionMode - self.position = arguments.position - self.framerate = arguments.framerate - self.resolution = arguments.resolution - self.codes = arguments.codes - + + captureSession = AVCaptureSession() + dataOutput = AVCaptureVideoDataOutput() + metadataOutput = AVCaptureMetadataOutput() + + detectionMode = arguments.detectionMode + position = arguments.position + framerate = arguments.framerate + resolution = arguments.resolution + codes = arguments.codes + super.init() - do { - try setupCaptureDevice(arguments) - } catch { - throw error - } + do { + try setupCaptureDevice(arguments) + } catch { + throw error + } + } + + private func setupCaptureDevice(_ arguments: StartArgs) throws { + captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) + + guard captureDevice != nil else { + throw ReaderError.noInputDevice + } + + do { + let input = try AVCaptureDeviceInput(device: captureDevice) + captureSession.addInput(input) + } catch let error as AVError { + if error.code == AVError.applicationIsNotAuthorizedToUseDevice { + throw ReaderError.unauthorized + } + throw error + } + + captureSession.addOutput(dataOutput) + captureSession.addOutput(metadataOutput) + + dataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] + dataOutput.connection(with: .video)?.videoOrientation = .portrait + dataOutput.alwaysDiscardsLateVideoFrames = true + dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: .default)) + + metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global(qos: .default)) + metadataOutput.metadataObjectTypes = arguments.codes.compactMap { avMetadataObjectTypes[$0] } + + guard let optimalFormat = captureDevice.formats.first(where: { + let dimensions = CMVideoFormatDescriptionGetDimensions($0.formatDescription) + let mediaSubType = CMFormatDescriptionGetMediaSubType($0.formatDescription).toString() + + return $0.videoSupportedFrameRateRanges.first!.maxFrameRate >= arguments.framerate.doubleValue + && dimensions.height >= arguments.resolution.height + && dimensions.width >= arguments.resolution.width + && mediaSubType == "420f" // maybe 420v is also ok? Who knows... + }) else { + throw ReaderError.cameraNotSuitable(arguments.resolution, arguments.framerate) + } + + do { + try captureDevice.lockForConfiguration() + captureDevice.activeFormat = optimalFormat + captureDevice.activeVideoMinFrameDuration = + optimalFormat.videoSupportedFrameRateRanges.first!.minFrameDuration + captureDevice.activeVideoMaxFrameDuration = + optimalFormat.videoSupportedFrameRateRanges.first!.minFrameDuration + captureDevice.unlockForConfiguration() + } catch { + throw ReaderError.configurationLockError(error) + } + + previewSize = CMVideoFormatDescriptionGetDimensions(captureDevice.activeFormat.formatDescription) } - - private func setupCaptureDevice(_ arguments: StartArgs) throws { - captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) - - guard captureDevice != nil else { - throw ReaderError.noInputDevice - } - - do { - let input = try AVCaptureDeviceInput(device: captureDevice) - captureSession.addInput(input) - } catch let error as AVError { - if error.code == AVError.applicationIsNotAuthorizedToUseDevice { - throw ReaderError.unauthorized - } - throw error - } - - captureSession.addOutput(dataOutput) - captureSession.addOutput(metadataOutput) - - dataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] - dataOutput.connection(with: .video)?.videoOrientation = .portrait - dataOutput.alwaysDiscardsLateVideoFrames = true - dataOutput.setSampleBufferDelegate(self, queue: DispatchQueue.global(qos: .default)) - - metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global(qos: .default)) - metadataOutput.metadataObjectTypes = arguments.codes.compactMap { avMetadataObjectTypes[$0] } - - guard let optimalFormat = captureDevice.formats.first(where: { - let dimensions = CMVideoFormatDescriptionGetDimensions($0.formatDescription) - let mediaSubType = CMFormatDescriptionGetMediaSubType($0.formatDescription).toString() - - return $0.videoSupportedFrameRateRanges.first!.maxFrameRate >= arguments.framerate.doubleValue - && dimensions.height >= arguments.resolution.height - && dimensions.width >= arguments.resolution.width - && mediaSubType == "420f" // maybe 420v is also ok? Who knows... - }) else { - throw ReaderError.cameraNotSuitable(arguments.resolution, arguments.framerate) - } - - do { - try captureDevice.lockForConfiguration() - captureDevice.activeFormat = optimalFormat - captureDevice.activeVideoMinFrameDuration = - optimalFormat.videoSupportedFrameRateRanges.first!.minFrameDuration - captureDevice.activeVideoMaxFrameDuration = - optimalFormat.videoSupportedFrameRateRanges.first!.minFrameDuration - captureDevice.unlockForConfiguration() - } catch { - throw ReaderError.configurationLockError(error) - } - - previewSize = CMVideoFormatDescriptionGetDimensions(captureDevice.activeFormat.formatDescription) - } func start(fromPause: Bool) throws { - guard captureDevice != nil else { return } + guard captureDevice != nil else { return } captureSession.startRunning() if !fromPause { - self.textureId = textureRegistry.register(self) + textureId = textureRegistry.register(self) } - if (torchActiveOnStop) { - do { - try captureDevice.lockForConfiguration() - captureDevice.torchMode = .on - captureDevice.unlockForConfiguration() - torchActiveOnStop = false - } catch { - throw ReaderError.configurationLockError(error) - } + if torchActiveOnStop { + do { + try captureDevice.lockForConfiguration() + captureDevice.torchMode = .on + captureDevice.unlockForConfiguration() + torchActiveOnStop = false + } catch { + throw ReaderError.configurationLockError(error) + } } } func stop(pause: Bool) { - guard captureDevice != nil else { return } - + guard captureDevice != nil else { return } + torchActiveOnStop = captureDevice.isTorchActive captureSession.stopRunning() if !pause { @@ -215,15 +216,16 @@ class BarcodeReader: NSObject { } func toggleTorch() -> Bool { - guard captureDevice != nil && captureDevice.isTorchAvailable else { return false } + guard captureDevice != nil, captureDevice.isTorchAvailable else { return false } do { - try captureDevice.lockForConfiguration() - captureDevice.torchMode = captureDevice.isTorchActive ? .off : .on - captureDevice.unlockForConfiguration() } catch { - print(error) - return false - } + try captureDevice.lockForConfiguration() + captureDevice.torchMode = captureDevice.isTorchActive ? .off : .on + captureDevice.unlockForConfiguration() + } catch { + print(error) + return false + } return captureDevice.isTorchActive } @@ -246,56 +248,54 @@ class BarcodeReader: NSObject { switch detectionMode { case .continuous: return case .pauseDetection: - guard !captureSession.outputs.contains(metadataOutput) else { return } + guard !captureSession.outputs.contains(metadataOutput) else { return } - let types = metadataOutput.metadataObjectTypes - metadataOutput = AVCaptureMetadataOutput() - metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global(qos: .default)) - metadataOutput.metadataObjectTypes = types + let types = metadataOutput.metadataObjectTypes + metadataOutput = AVCaptureMetadataOutput() + metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.global(qos: .default)) + metadataOutput.metadataObjectTypes = types captureSession.addOutput(metadataOutput) case .pauseVideo: try start(fromPause: true) } } - - func changeCamera(type: String) { - position = type == "front" ? .front : .back - reloadCamera() - } - - func toggleCamera() { - position = position.toggled() - reloadCamera() - } - - private func reloadCamera() { - captureSession.stopRunning() - - captureSession.outputs.forEach { captureSession.removeOutput($0) } - captureSession.inputs.forEach { captureSession.removeInput($0) } - - do { - let arguments = StartArgs(position: position, detectionMode: detectionMode, framerate: framerate, resolution: resolution, codes: codes) - try setupCaptureDevice(arguments) - } catch { - print(error) - } - - captureSession.startRunning() - } + func changeCamera(type: String) { + position = type == "front" ? .front : .back + reloadCamera() + } + + func toggleCamera() { + position = position.toggled() + reloadCamera() + } + + private func reloadCamera() { + captureSession.stopRunning() + + captureSession.outputs.forEach { captureSession.removeOutput($0) } + captureSession.inputs.forEach { captureSession.removeInput($0) } + + do { + let arguments = StartArgs(position: position, detectionMode: detectionMode, framerate: framerate, resolution: resolution, codes: codes) + try setupCaptureDevice(arguments) + } catch { + print(error) + } + + captureSession.startRunning() + } } private extension AVCaptureDevice.Position { - - func toggled() -> AVCaptureDevice.Position { - switch self { - case .back: - return .front - default: - return .back - } - } + func toggled() -> AVCaptureDevice.Position { + switch self { + case .back: + return .front + default: + return .back + } + } } extension BarcodeReader: FlutterTexture { @@ -306,9 +306,10 @@ extension BarcodeReader: FlutterTexture { extension BarcodeReader: AVCaptureVideoDataOutputSampleBufferDelegate { // runs on dispatch queue - func captureOutput(_ output: AVCaptureOutput, - didOutput sampleBuffer: CMSampleBuffer, - from connection: AVCaptureConnection) { + func captureOutput(_: AVCaptureOutput, + didOutput sampleBuffer: CMSampleBuffer, + from _: AVCaptureConnection) + { pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) textureRegistry.textureFrameAvailable(textureId) } @@ -316,13 +317,14 @@ extension BarcodeReader: AVCaptureVideoDataOutputSampleBufferDelegate { extension BarcodeReader: AVCaptureMetadataOutputObjectsDelegate { // runs on dispatch queue - func metadataOutput(_ output: AVCaptureMetadataOutput, - didOutput metadataObjects: [AVMetadataObject], - from connection: AVCaptureConnection) { + func metadataOutput(_: AVCaptureMetadataOutput, + didOutput metadataObjects: [AVMetadataObject], + from _: AVCaptureConnection) + { guard let metadata = metadataObjects.first, let readableCode = metadata as? AVMetadataMachineReadableCodeObject - else { return } + else { return } pauseIfRequired() @@ -337,7 +339,7 @@ extension FourCharCode { CChar(self >> 16 & 0xFF), CChar(self >> 8 & 0xFF), CChar(self & 0xFF), - 0 + 0, ]) } } From 4ff1eee7059b5f352b218eb08f64c8c2669dcc97 Mon Sep 17 00:00:00 2001 From: rafwillems Date: Thu, 21 Apr 2022 14:11:25 +0200 Subject: [PATCH 6/8] Enable pause & resume on continuous scanning mode in iOS --- fast_barcode_scanner/ios/Classes/BarcodeReader.swift | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fast_barcode_scanner/ios/Classes/BarcodeReader.swift b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift index 8fd240b5..d1793f1f 100644 --- a/fast_barcode_scanner/ios/Classes/BarcodeReader.swift +++ b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift @@ -99,6 +99,7 @@ class BarcodeReader: NSObject { let codes: [String] var torchActiveOnStop = false + var isForcePaused = false var previewSize: CMVideoDimensions! init(textureRegistry: FlutterTextureRegistry, @@ -232,6 +233,7 @@ class BarcodeReader: NSObject { func pauseIfRequired(force: Bool = false) { if force { + isForcePaused = true stop(pause: true) } else { switch detectionMode { @@ -246,7 +248,12 @@ class BarcodeReader: NSObject { func resume() throws { switch detectionMode { - case .continuous: return + case .continuous: + if(isForcePaused){ + isForcePaused = false + try start(fromPause: true) + } + return case .pauseDetection: guard !captureSession.outputs.contains(metadataOutput) else { return } From c734a89c354c488481e22f849fd67664e669c5f3 Mon Sep 17 00:00:00 2001 From: WilliamVerhaeghe Date: Mon, 17 Jul 2023 13:59:12 +0200 Subject: [PATCH 7/8] Update kotlin version --- fast_barcode_scanner/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fast_barcode_scanner/android/build.gradle b/fast_barcode_scanner/android/build.gradle index fe22c3a9..61e24b96 100644 --- a/fast_barcode_scanner/android/build.gradle +++ b/fast_barcode_scanner/android/build.gradle @@ -2,7 +2,7 @@ group 'com.jhoogstraat.fast_barcode_scanner' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.6.10' repositories { google() mavenCentral() From dfbd6ea2ffa8900ff91662381b8d43b706164d41 Mon Sep 17 00:00:00 2001 From: WilliamVerhaeghe Date: Thu, 26 Oct 2023 14:03:34 +0200 Subject: [PATCH 8/8] Flutter update --- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../android/app/src/main/AndroidManifest.xml | 3 ++- .../example/android/build.gradle | 6 ++--- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../example/lib/scanner_screen.dart | 24 +++++++------------ .../lib/src/barcode_camera.dart | 13 ++-------- fast_barcode_scanner/pubspec.yaml | 3 +-- .../test/fast_barcode_scanner_test.dart | 4 ++-- .../pubspec.yaml | 3 +-- 9 files changed, 22 insertions(+), 38 deletions(-) diff --git a/fast_barcode_scanner/android/gradle/wrapper/gradle-wrapper.properties b/fast_barcode_scanner/android/gradle/wrapper/gradle-wrapper.properties index 3c9d0852..3c472b99 100644 --- a/fast_barcode_scanner/android/gradle/wrapper/gradle-wrapper.properties +++ b/fast_barcode_scanner/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip diff --git a/fast_barcode_scanner/example/android/app/src/main/AndroidManifest.xml b/fast_barcode_scanner/example/android/app/src/main/AndroidManifest.xml index 791aa044..0d0f56b6 100644 --- a/fast_barcode_scanner/example/android/app/src/main/AndroidManifest.xml +++ b/fast_barcode_scanner/example/android/app/src/main/AndroidManifest.xml @@ -6,7 +6,8 @@ diff --git a/fast_barcode_scanner/example/android/build.gradle b/fast_barcode_scanner/example/android/build.gradle index 373f9326..f722dca2 100644 --- a/fast_barcode_scanner/example/android/build.gradle +++ b/fast_barcode_scanner/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.4.32' + ext.kotlin_version = '1.8.0' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' + classpath 'com.android.tools.build:gradle:7.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -24,6 +24,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/fast_barcode_scanner/example/android/gradle/wrapper/gradle-wrapper.properties b/fast_barcode_scanner/example/android/gradle/wrapper/gradle-wrapper.properties index bc6a58af..cc5527d7 100644 --- a/fast_barcode_scanner/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/fast_barcode_scanner/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/fast_barcode_scanner/example/lib/scanner_screen.dart b/fast_barcode_scanner/example/lib/scanner_screen.dart index 60819c9e..40e07338 100644 --- a/fast_barcode_scanner/example/lib/scanner_screen.dart +++ b/fast_barcode_scanner/example/lib/scanner_screen.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:fast_barcode_scanner/fast_barcode_scanner.dart'; import 'package:flutter/material.dart'; + import 'detections_counter.dart'; final codeStream = StreamController.broadcast(); @@ -20,12 +21,13 @@ class _ScannerScreenState extends State { @override void initState() { super.initState(); - _checkCanChangeCamera(); + WidgetsBinding.instance.addPostFrameCallback((_) => _checkCanChangeCamera()); } - Future _checkCanChangeCamera() async => setState(() async { - _canChangeCamera = await CameraController.instance.canChangeCamera(); - }); + Future _checkCanChangeCamera() async { + _canChangeCamera = await CameraController.instance.canChangeCamera(); + setState(() {}); + } @override Widget build(BuildContext context) { @@ -43,13 +45,10 @@ class _ScannerScreenState extends State { ValueListenableBuilder( valueListenable: _torchIconState, builder: (context, state, _) => IconButton( - icon: state - ? const Icon(Icons.flash_on) - : const Icon(Icons.flash_off), + icon: state ? const Icon(Icons.flash_on) : const Icon(Icons.flash_off), onPressed: () async { await CameraController.instance.toggleTorch(); - _torchIconState.value = - CameraController.instance.state.torchState; + _torchIconState.value = CameraController.instance.state.torchState; }, ), ), @@ -61,12 +60,7 @@ class _ScannerScreenState extends State { ], ), body: BarcodeCamera( - types: const [ - BarcodeType.ean8, - BarcodeType.ean13, - BarcodeType.code128, - BarcodeType.qr - ], + types: const [BarcodeType.ean8, BarcodeType.ean13, BarcodeType.code128, BarcodeType.qr], resolution: Resolution.hd720, framerate: Framerate.fps30, mode: DetectionMode.pauseVideo, diff --git a/fast_barcode_scanner/lib/src/barcode_camera.dart b/fast_barcode_scanner/lib/src/barcode_camera.dart index fb2c24d8..b93cdf4b 100644 --- a/fast_barcode_scanner/lib/src/barcode_camera.dart +++ b/fast_barcode_scanner/lib/src/barcode_camera.dart @@ -1,10 +1,6 @@ -import 'dart:ui'; - import 'package:fast_barcode_scanner/src/camera_controller.dart'; import 'package:fast_barcode_scanner_platform_interface/fast_barcode_scanner_platform_interface.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; typedef ErrorCallback = Widget Function(BuildContext context, Object? error); @@ -55,8 +51,7 @@ class BarcodeCameraState extends State { super.didChangeDependencies(); CameraController.instance - .initialize(widget.types, widget.resolution, widget.framerate, - widget.mode, widget.position, widget.onScan) + .initialize(widget.types, widget.resolution, widget.framerate, widget.mode, widget.position, widget.onScan) .whenComplete(() => setState(() => _opacity = 1.0)); } @@ -72,11 +67,7 @@ class BarcodeCameraState extends State { ? widget.onError(context, cameraState.error!) : Stack( fit: StackFit.expand, - children: [ - if (cameraState.isInitialized) - _buildPreview(cameraState.previewConfig!), - ...widget.children - ], + children: [if (cameraState.isInitialized) _buildPreview(cameraState.previewConfig!), ...widget.children], ), ), ); diff --git a/fast_barcode_scanner/pubspec.yaml b/fast_barcode_scanner/pubspec.yaml index d4038769..b782a44e 100644 --- a/fast_barcode_scanner/pubspec.yaml +++ b/fast_barcode_scanner/pubspec.yaml @@ -5,8 +5,7 @@ homepage: https://github.com/jhoogstraat/fast_barcode_scanner repository: https://github.com/jhoogstraat/fast_barcode_scanner environment: - sdk: ">=2.12.0 <3.0.0" - flutter: ">=2.0.0" + sdk: ">=3.0.0 <4.0.0" dependencies: flutter: diff --git a/fast_barcode_scanner/test/fast_barcode_scanner_test.dart b/fast_barcode_scanner/test/fast_barcode_scanner_test.dart index bce9dcff..2f738feb 100644 --- a/fast_barcode_scanner/test/fast_barcode_scanner_test.dart +++ b/fast_barcode_scanner/test/fast_barcode_scanner_test.dart @@ -7,13 +7,13 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, (MethodCall methodCall) async { return '42'; }); }); tearDown(() { - channel.setMockMethodCallHandler(null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, null); }); test('getPlatformVersion', () async { diff --git a/fast_barcode_scanner_platform_interface/pubspec.yaml b/fast_barcode_scanner_platform_interface/pubspec.yaml index c7d17b6a..a96ba385 100644 --- a/fast_barcode_scanner_platform_interface/pubspec.yaml +++ b/fast_barcode_scanner_platform_interface/pubspec.yaml @@ -5,8 +5,7 @@ repository: https://github.com/jhoogstraat/fast_barcode_scanner version: 1.0.4 environment: - sdk: '>=2.12.0 <3.0.0' - flutter: ">=2.0.0" + sdk: '>=3.0.0 <4.0.0' dependencies: flutter: