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() 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/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..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 @@ -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,28 @@ 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 + else -> CameraPosition.back + } + initCamera() + } + private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { ContextCompat.checkSelfPermission(activity!!.applicationContext, it) == PackageManager.PERMISSION_GRANTED } @@ -148,12 +170,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..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,8 @@ 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/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 2ced323c..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(); @@ -15,6 +16,18 @@ class ScannerScreen extends StatefulWidget { class _ScannerScreenState extends State { final _torchIconState = ValueNotifier(false); + bool _canChangeCamera = false; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) => _checkCanChangeCamera()); + } + + Future _checkCanChangeCamera() async { + _canChangeCamera = await CameraController.instance.canChangeCamera(); + setState(() {}); + } @override Widget build(BuildContext context) { @@ -32,25 +45,22 @@ 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; }, ), ), + if (_canChangeCamera) + IconButton( + icon: const Icon(Icons.cameraswitch), + onPressed: 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/example/pubspec.yaml b/fast_barcode_scanner/example/pubspec.yaml index fc386e2a..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' @@ -15,5 +16,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/BarcodeReader.swift b/fast_barcode_scanner/ios/Classes/BarcodeReader.swift index b1c2a333..d1793f1f 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,43 +88,65 @@ 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 position: AVCaptureDevice.Position + let framerate: Framerate + let resolution: Resolution + let codes: [String] + var torchActiveOnStop = false + var isForcePaused = false var previewSize: CMVideoDimensions! init(textureRegistry: FlutterTextureRegistry, - arguments: StartArgs, - codeCallback: @escaping ([String]) -> Void) throws { + 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 + + 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 + } + } + + 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 - } + 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) + captureSession.addOutput(dataOutput) + captureSession.addOutput(metadataOutput) dataOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] dataOutput.connection(with: .video)?.videoOrientation = .portrait @@ -146,45 +168,45 @@ class BarcodeReader: NSObject { 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) - } + 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 { @@ -195,21 +217,23 @@ 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 } func pauseIfRequired(force: Bool = false) { if force { + isForcePaused = true stop(pause: true) } else { switch detectionMode { @@ -224,20 +248,61 @@ 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 } + 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() + } +} + +private extension AVCaptureDevice.Position { + func toggled() -> AVCaptureDevice.Position { + switch self { + case .back: + return .front + default: + return .back + } + } } extension BarcodeReader: FlutterTexture { @@ -248,9 +313,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) } @@ -258,13 +324,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() @@ -279,7 +346,7 @@ extension FourCharCode { CChar(self >> 16 & 0xFF), CChar(self >> 8 & 0xFF), CChar(self & 0xFF), - 0 + 0, ]) } } diff --git a/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift b/fast_barcode_scanner/ios/Classes/FastBarcodeScannerPlugin.swift index 83e6ceb8..1cff79e6 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 @@ -55,7 +63,10 @@ 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) + case "changeCamera": changeCamera(call: call, result: result) + case "toggleCamera": toggleCamera(result: result) default: result(FlutterMethodNotImplemented) } } catch { @@ -131,9 +142,27 @@ 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 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) + } } 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/lib/src/camera_controller.dart b/fast_barcode_scanner/lib/src/camera_controller.dart index d88e69b0..f68e2133 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; @@ -73,13 +79,15 @@ 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(); @@ -168,6 +176,18 @@ 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 canChangeCamera() => _platform.canChangeCamera(); + Future changeCamera(CameraPosition position) async { try { await _platform.changeCamera(position); 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/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; 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: