Moved the size listener to plugin side.flutter-beta
| @@ -17,7 +17,7 @@ import io.flutter.plugin.common.BinaryMessenger | |||||
| import io.flutter.plugin.common.MethodCall | import io.flutter.plugin.common.MethodCall | ||||
| import io.flutter.plugin.common.MethodChannel | import io.flutter.plugin.common.MethodChannel | ||||
| import io.flutter.plugin.platform.PlatformView | import io.flutter.plugin.platform.PlatformView | ||||
| class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) : | |||||
| class QRView(messenger: BinaryMessenger, id: Int, private val context: Context, private val params: HashMap<String, Any>) : | |||||
| PlatformView, MethodChannel.MethodCallHandler { | PlatformView, MethodChannel.MethodCallHandler { | ||||
| private var isTorchOn: Boolean = false | private var isTorchOn: Boolean = false | ||||
| @@ -66,6 +66,12 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) | |||||
| override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { | override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { | ||||
| when(call.method){ | when(call.method){ | ||||
| "startScan" -> { | |||||
| startScan() | |||||
| } | |||||
| "stopScan" -> { | |||||
| stopScan() | |||||
| } | |||||
| "flipCamera" -> { | "flipCamera" -> { | ||||
| flipCamera() | flipCamera() | ||||
| } | } | ||||
| @@ -127,14 +133,16 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) | |||||
| private fun initBarCodeView(): BarcodeView? { | private fun initBarCodeView(): BarcodeView? { | ||||
| if (barcodeView == null) { | if (barcodeView == null) { | ||||
| barcodeView = createBarCodeView() | |||||
| barcodeView = BarcodeView(Shared.activity) | |||||
| if (params["cameraFacing"] as Int == 1) { | |||||
| barcodeView?.cameraSettings?.requestedCameraId = CameraInfo.CAMERA_FACING_FRONT | |||||
| } | |||||
| } | } | ||||
| return barcodeView | return barcodeView | ||||
| } | } | ||||
| private fun createBarCodeView(): BarcodeView { | |||||
| val barcode = BarcodeView(Shared.activity) | |||||
| barcode.decodeContinuous( | |||||
| private fun startScan() { | |||||
| barcodeView?.decodeContinuous( | |||||
| object : BarcodeCallback { | object : BarcodeCallback { | ||||
| override fun barcodeResult(result: BarcodeResult) { | override fun barcodeResult(result: BarcodeResult) { | ||||
| val code = mapOf( | val code = mapOf( | ||||
| @@ -147,7 +155,10 @@ class QRView(messenger: BinaryMessenger, id: Int, private val context: Context) | |||||
| override fun possibleResultPoints(resultPoints: List<ResultPoint>) {} | override fun possibleResultPoints(resultPoints: List<ResultPoint>) {} | ||||
| } | } | ||||
| ) | ) | ||||
| return barcode | |||||
| } | |||||
| private fun stopScan() { | |||||
| barcodeView?.stopDecoding() | |||||
| } | } | ||||
| private fun hasCameraPermission(): Boolean { | private fun hasCameraPermission(): Boolean { | ||||
| @@ -10,8 +10,9 @@ import io.flutter.plugin.platform.PlatformViewFactory | |||||
| class QRViewFactory(private val messenger: BinaryMessenger) : | class QRViewFactory(private val messenger: BinaryMessenger) : | ||||
| PlatformViewFactory(StandardMessageCodec.INSTANCE) { | PlatformViewFactory(StandardMessageCodec.INSTANCE) { | ||||
| override fun create(context: Context, id: Int, obj: Any?): PlatformView { | |||||
| return QRView(messenger, id, context) | |||||
| override fun create(context: Context, id: Int, args: Any?): PlatformView { | |||||
| val params = args as HashMap<String, Any> | |||||
| return QRView(messenger, id, context, params) | |||||
| } | } | ||||
| } | } | ||||
| @@ -9,6 +9,7 @@ | |||||
| .buildlog/ | .buildlog/ | ||||
| .history | .history | ||||
| .svn/ | .svn/ | ||||
| .last_build_id | |||||
| # IntelliJ related | # IntelliJ related | ||||
| *.iml | *.iml | ||||
| @@ -264,13 +264,11 @@ | |||||
| ); | ); | ||||
| inputPaths = ( | inputPaths = ( | ||||
| "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", | ||||
| "${PODS_ROOT}/../Flutter/Flutter.framework", | |||||
| "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", | "${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework", | ||||
| "${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework", | "${BUILT_PRODUCTS_DIR}/qr_code_scanner/qr_code_scanner.framework", | ||||
| ); | ); | ||||
| name = "[CP] Embed Pods Frameworks"; | name = "[CP] Embed Pods Frameworks"; | ||||
| outputPaths = ( | outputPaths = ( | ||||
| "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", | |||||
| "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework", | ||||
| "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework", | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/qr_code_scanner.framework", | ||||
| ); | ); | ||||
| @@ -154,25 +154,18 @@ class _QRViewExampleState extends State<QRViewExample> { | |||||
| : 300.0; | : 300.0; | ||||
| // To ensure the Scanner view is properly sizes after rotation | // To ensure the Scanner view is properly sizes after rotation | ||||
| // we need to listen for Flutter SizeChanged notification and update controller | // we need to listen for Flutter SizeChanged notification and update controller | ||||
| return NotificationListener<SizeChangedLayoutNotification>( | |||||
| onNotification: (notification) { | |||||
| Future.microtask( | |||||
| () => controller?.updateDimensions(qrKey, scanArea: scanArea)); | |||||
| return false; | |||||
| }, | |||||
| child: SizeChangedLayoutNotifier( | |||||
| key: const Key('qr-size-notifier'), | |||||
| child: QRView( | |||||
| key: qrKey, | |||||
| onQRViewCreated: _onQRViewCreated, | |||||
| overlay: QrScannerOverlayShape( | |||||
| borderColor: Colors.red, | |||||
| borderRadius: 10, | |||||
| borderLength: 30, | |||||
| borderWidth: 10, | |||||
| cutOutSize: scanArea, | |||||
| ), | |||||
| ))); | |||||
| return QRView( | |||||
| key: qrKey, | |||||
| cameraFacing: CameraFacing.front, | |||||
| onQRViewCreated: _onQRViewCreated, | |||||
| overlay: QrScannerOverlayShape( | |||||
| borderColor: Colors.red, | |||||
| borderRadius: 10, | |||||
| borderLength: 30, | |||||
| borderWidth: 10, | |||||
| cutOutSize: scanArea, | |||||
| ), | |||||
| ); | |||||
| } | } | ||||
| void _onQRViewCreated(QRViewController controller) { | void _onQRViewCreated(QRViewController controller) { | ||||
| @@ -13,67 +13,28 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| var scanner: MTBBarcodeScanner? | var scanner: MTBBarcodeScanner? | ||||
| var registrar: FlutterPluginRegistrar | var registrar: FlutterPluginRegistrar | ||||
| var channel: FlutterMethodChannel | var channel: FlutterMethodChannel | ||||
| var cameraFacing: MTBCamera | |||||
| public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64){ | |||||
| public init(withFrame frame: CGRect, withRegistrar registrar: FlutterPluginRegistrar, withId id: Int64, params: Dictionary<String, Any>){ | |||||
| self.registrar = registrar | self.registrar = registrar | ||||
| previewView = UIView(frame: frame) | previewView = UIView(frame: frame) | ||||
| cameraFacing = MTBCamera.init(rawValue: UInt(Int(params["cameraFacing"] as! Double))) ?? MTBCamera.back | |||||
| channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) | channel = FlutterMethodChannel(name: "net.touchcapture.qr.flutterqr/qrview_\(id)", binaryMessenger: registrar.messenger()) | ||||
| } | } | ||||
| func isCameraAvailable(success: Bool) -> Void { | |||||
| if success { | |||||
| do { | |||||
| try scanner?.startScanning(resultBlock: { [weak self] codes in | |||||
| if let codes = codes { | |||||
| for code in codes { | |||||
| var typeString: String; | |||||
| switch(code.type) { | |||||
| case AVMetadataObject.ObjectType.aztec: | |||||
| typeString = "AZTEC" | |||||
| case AVMetadataObject.ObjectType.code39: | |||||
| typeString = "CODE_39" | |||||
| case AVMetadataObject.ObjectType.code93: | |||||
| typeString = "CODE_93" | |||||
| case AVMetadataObject.ObjectType.code128: | |||||
| typeString = "CODE_128" | |||||
| case AVMetadataObject.ObjectType.dataMatrix: | |||||
| typeString = "DATA_MATRIX" | |||||
| case AVMetadataObject.ObjectType.ean8: | |||||
| typeString = "EAN_8" | |||||
| case AVMetadataObject.ObjectType.ean13: | |||||
| typeString = "EAN_13" | |||||
| case AVMetadataObject.ObjectType.itf14: | |||||
| typeString = "ITF" | |||||
| case AVMetadataObject.ObjectType.pdf417: | |||||
| typeString = "PDF_417" | |||||
| case AVMetadataObject.ObjectType.qr: | |||||
| typeString = "QR_CODE" | |||||
| case AVMetadataObject.ObjectType.upce: | |||||
| typeString = "UPC_E" | |||||
| default: | |||||
| return | |||||
| } | |||||
| guard let stringValue = code.stringValue else { continue } | |||||
| let result = ["code": stringValue, "type": typeString] | |||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: result) | |||||
| } | |||||
| } | |||||
| }) | |||||
| } catch { | |||||
| NSLog("Unable to start scanning") | |||||
| } | |||||
| } else { | |||||
| UIAlertView(title: "Scanning Unavailable", message: "This app does not have permission to access the camera", delegate: nil, cancelButtonTitle: nil, otherButtonTitles: "Ok").show() | |||||
| } | |||||
| deinit { | |||||
| scanner?.stopScanning() | |||||
| } | } | ||||
| public func view() -> UIView { | public func view() -> UIView { | ||||
| channel.setMethodCallHandler({ | channel.setMethodCallHandler({ | ||||
| [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in | |||||
| [weak self] (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in | |||||
| switch(call.method){ | switch(call.method){ | ||||
| case "setDimensions": | case "setDimensions": | ||||
| let arguments = call.arguments as! Dictionary<String, Double> | let arguments = call.arguments as! Dictionary<String, Double> | ||||
| self?.setDimensions(width: arguments["width"] ?? 0, height: arguments["height"] ?? 0, scanArea: arguments["scanArea"] ?? 0) | self?.setDimensions(width: arguments["width"] ?? 0, height: arguments["height"] ?? 0, scanArea: arguments["scanArea"] ?? 0) | ||||
| case "startScan": | |||||
| self?.startScan(result) | |||||
| case "flipCamera": | case "flipCamera": | ||||
| self?.flipCamera() | self?.flipCamera() | ||||
| case "toggleFlash": | case "toggleFlash": | ||||
| @@ -106,9 +67,67 @@ public class QRView:NSObject,FlutterPlatformView { | |||||
| self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea) | self.scanner?.scanRect = CGRect(x: Double(midX) - (scanArea / 2), y: Double(midY) - (scanArea / 2), width: scanArea, height: scanArea) | ||||
| } | } | ||||
| } | } | ||||
| MTBBarcodeScanner.requestCameraPermission(success: isCameraAvailable) | |||||
| } | |||||
| } | |||||
| func startScan(_ result: @escaping FlutterResult) -> Void { | |||||
| scanner = MTBBarcodeScanner(previewView: previewView) | |||||
| MTBBarcodeScanner.requestCameraPermission(success: { permissionGranted in | |||||
| if permissionGranted { | |||||
| do { | |||||
| try self.scanner?.startScanning(with: self.cameraFacing, resultBlock: { [weak self] codes in | |||||
| if let codes = codes { | |||||
| for code in codes { | |||||
| var typeString: String; | |||||
| switch(code.type) { | |||||
| case AVMetadataObject.ObjectType.aztec: | |||||
| typeString = "AZTEC" | |||||
| case AVMetadataObject.ObjectType.code39: | |||||
| typeString = "CODE_39" | |||||
| case AVMetadataObject.ObjectType.code93: | |||||
| typeString = "CODE_93" | |||||
| case AVMetadataObject.ObjectType.code128: | |||||
| typeString = "CODE_128" | |||||
| case AVMetadataObject.ObjectType.dataMatrix: | |||||
| typeString = "DATA_MATRIX" | |||||
| case AVMetadataObject.ObjectType.ean8: | |||||
| typeString = "EAN_8" | |||||
| case AVMetadataObject.ObjectType.ean13: | |||||
| typeString = "EAN_13" | |||||
| case AVMetadataObject.ObjectType.itf14: | |||||
| typeString = "ITF" | |||||
| case AVMetadataObject.ObjectType.pdf417: | |||||
| typeString = "PDF_417" | |||||
| case AVMetadataObject.ObjectType.qr: | |||||
| typeString = "QR_CODE" | |||||
| case AVMetadataObject.ObjectType.upce: | |||||
| typeString = "UPC_E" | |||||
| default: | |||||
| return | |||||
| } | |||||
| guard let stringValue = code.stringValue else { continue } | |||||
| let result = ["code": stringValue, "type": typeString] | |||||
| self?.channel.invokeMethod("onRecognizeQR", arguments: result) | |||||
| } | |||||
| } | |||||
| }) | |||||
| } catch { | |||||
| let error = FlutterError(code: "unknown-error", message: "Unable to start scanning", details: nil) | |||||
| result(error) | |||||
| } | |||||
| } else { | |||||
| let error = FlutterError(code: "cameraPermission", message: "Permission denied to access the camera", details: nil) | |||||
| result(error) | |||||
| } | |||||
| }) | |||||
| } | |||||
| func stopScan(){ | |||||
| if let sc: MTBBarcodeScanner = scanner { | |||||
| if sc.isScanning() { | |||||
| sc.stopScanning() | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -17,8 +17,8 @@ public class QRViewFactory: NSObject, FlutterPlatformViewFactory { | |||||
| } | } | ||||
| public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { | public func create(withFrame frame: CGRect, viewIdentifier viewId: Int64, arguments args: Any?) -> FlutterPlatformView { | ||||
| let dictionary = args as! Dictionary<String, Double> | |||||
| return QRView(withFrame: CGRect(x: 0, y: 0, width: dictionary["width"] ?? 0, height: dictionary["height"] ?? 0), withRegistrar: registrar!,withId: viewId) | |||||
| let params = args as! Dictionary<String, Double> | |||||
| return QRView(withFrame: frame, withRegistrar: registrar!,withId: viewId, params: params) | |||||
| } | } | ||||
| public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { | public func createArgsCodec() -> FlutterMessageCodec & NSObjectProtocol { | ||||
| @@ -7,6 +7,14 @@ import 'package:qr_code_scanner/qr_code_scanner.dart'; | |||||
| typedef QRViewCreatedCallback = void Function(QRViewController); | typedef QRViewCreatedCallback = void Function(QRViewController); | ||||
| enum CameraFacing { | |||||
| /// Shows back facing camera. | |||||
| back, | |||||
| /// Shows front facing camera. | |||||
| front | |||||
| } | |||||
| enum BarcodeFormat { | enum BarcodeFormat { | ||||
| /// Aztec 2D barcode format. | /// Aztec 2D barcode format. | ||||
| aztec, | aztec, | ||||
| @@ -80,6 +88,11 @@ const _formatNames = <String, BarcodeFormat>{ | |||||
| 'UPC_EAN_EXTENSION': BarcodeFormat.upcEanExtension, | 'UPC_EAN_EXTENSION': BarcodeFormat.upcEanExtension, | ||||
| }; | }; | ||||
| /// The [Barcode] object holds information about the barcode or qr code. | |||||
| /// | |||||
| /// [code] is the content of the barcode. | |||||
| /// [format] displays which type the code is. | |||||
| /// Only for Android, [rawBytes] gives a list of bytes of the result. | |||||
| class Barcode { | class Barcode { | ||||
| Barcode(this.code, this.format, this.rawBytes); | Barcode(this.code, this.format, this.rawBytes); | ||||
| @@ -90,60 +103,84 @@ class Barcode { | |||||
| final List<int> rawBytes; | final List<int> rawBytes; | ||||
| } | } | ||||
| /// The [QRView] is the view where the camera and the barcode scanner gets displayed. | |||||
| class QRView extends StatefulWidget { | class QRView extends StatefulWidget { | ||||
| const QRView({ | const QRView({ | ||||
| @required Key key, | @required Key key, | ||||
| @required this.onQRViewCreated, | @required this.onQRViewCreated, | ||||
| this.overlay, | this.overlay, | ||||
| this.overlayMargin = EdgeInsets.zero, | this.overlayMargin = EdgeInsets.zero, | ||||
| this.cameraFacing = CameraFacing.back, | |||||
| }) : assert(key != null), | }) : assert(key != null), | ||||
| assert(onQRViewCreated != null), | assert(onQRViewCreated != null), | ||||
| super(key: key); | super(key: key); | ||||
| final QRViewCreatedCallback onQRViewCreated; | final QRViewCreatedCallback onQRViewCreated; | ||||
| final ShapeBorder overlay; | final ShapeBorder overlay; | ||||
| final EdgeInsetsGeometry overlayMargin; | final EdgeInsetsGeometry overlayMargin; | ||||
| final CameraFacing cameraFacing; | |||||
| @override | @override | ||||
| State<StatefulWidget> createState() => _QRViewState(); | State<StatefulWidget> createState() => _QRViewState(); | ||||
| } | } | ||||
| class _QRViewState extends State<QRView> { | class _QRViewState extends State<QRView> { | ||||
| var _channel; | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return NotificationListener( | |||||
| onNotification: onNotification, | |||||
| child: SizeChangedLayoutNotifier( | |||||
| child: (widget.overlay != null) ? | |||||
| _getPlatformQrViewWithOverlay() : | |||||
| _getPlatformQrView(), | |||||
| ), | |||||
| ); | |||||
| } | |||||
| bool onNotification(notification) { | |||||
| Future.microtask(() => { | |||||
| QRViewController.updateDimensions( | |||||
| widget.key, | |||||
| _channel, | |||||
| scanArea: widget.overlay != null ? | |||||
| (widget.overlay as QrScannerOverlayShape).cutOutSize : 0.0) | |||||
| }); | |||||
| return false; | |||||
| } | |||||
| Widget _getPlatformQrViewWithOverlay() { | |||||
| return Stack( | return Stack( | ||||
| children: [ | children: [ | ||||
| _getPlatformQrView(widget.key), | |||||
| if (widget.overlay != null) | |||||
| Container( | |||||
| padding: widget.overlayMargin, | |||||
| decoration: ShapeDecoration( | |||||
| shape: widget.overlay, | |||||
| ), | |||||
| ) | |||||
| else | |||||
| Container(), | |||||
| _getPlatformQrView(), | |||||
| Container( | |||||
| padding: widget.overlayMargin, | |||||
| decoration: ShapeDecoration( | |||||
| shape: widget.overlay, | |||||
| ), | |||||
| ) | |||||
| ], | ], | ||||
| ); | ); | ||||
| } | } | ||||
| Widget _getPlatformQrView(GlobalKey key) { | |||||
| Widget _getPlatformQrView() { | |||||
| Widget _platformQrView; | Widget _platformQrView; | ||||
| switch (defaultTargetPlatform) { | switch (defaultTargetPlatform) { | ||||
| case TargetPlatform.android: | case TargetPlatform.android: | ||||
| _platformQrView = AndroidView( | _platformQrView = AndroidView( | ||||
| viewType: 'net.touchcapture.qr.flutterqr/qrview', | viewType: 'net.touchcapture.qr.flutterqr/qrview', | ||||
| onPlatformViewCreated: _onPlatformViewCreated, | onPlatformViewCreated: _onPlatformViewCreated, | ||||
| creationParams: _QrCameraSettings(cameraFacing: widget.cameraFacing).toMap(), | |||||
| creationParamsCodec: StandardMessageCodec(), | |||||
| ); | ); | ||||
| break; | break; | ||||
| case TargetPlatform.iOS: | case TargetPlatform.iOS: | ||||
| _platformQrView = UiKitView( | _platformQrView = UiKitView( | ||||
| viewType: 'net.touchcapture.qr.flutterqr/qrview', | viewType: 'net.touchcapture.qr.flutterqr/qrview', | ||||
| onPlatformViewCreated: _onPlatformViewCreated, | onPlatformViewCreated: _onPlatformViewCreated, | ||||
| creationParams: | |||||
| _CreationParams.fromWidget(MediaQuery.of(context).size.width, 400) | |||||
| .toMap(), | |||||
| creationParams: _QrCameraSettings(cameraFacing: widget.cameraFacing).toMap(), | |||||
| creationParamsCodec: StandardMessageCodec(), | creationParamsCodec: StandardMessageCodec(), | ||||
| ); | ); | ||||
| break; | break; | ||||
| @@ -155,101 +192,109 @@ class _QRViewState extends State<QRView> { | |||||
| } | } | ||||
| void _onPlatformViewCreated(int id) { | void _onPlatformViewCreated(int id) { | ||||
| if (widget.onQRViewCreated == null) { | |||||
| return; | |||||
| } | |||||
| // We pass the cutout size so that the scanner respects the scan area. | // We pass the cutout size so that the scanner respects the scan area. | ||||
| var cutOutSize = 0.0; | var cutOutSize = 0.0; | ||||
| if (widget.overlay != null) { | if (widget.overlay != null) { | ||||
| cutOutSize = (widget.overlay as QrScannerOverlayShape).cutOutSize; | cutOutSize = (widget.overlay as QrScannerOverlayShape).cutOutSize; | ||||
| } | } | ||||
| widget.onQRViewCreated(QRViewController._(id, widget.key, cutOutSize)); | |||||
| } | |||||
| } | |||||
| _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id'); | |||||
| class _CreationParams { | |||||
| _CreationParams({this.width, this.height}); | |||||
| // Start scan after creation of the view | |||||
| final controller = QRViewController._(_channel, widget.key, cutOutSize) | |||||
| .._startScan(widget.key, cutOutSize); | |||||
| static _CreationParams fromWidget(double width, double height) { | |||||
| return _CreationParams( | |||||
| width: width, | |||||
| height: height, | |||||
| ); | |||||
| // Initialize the controller for controlling the QRView | |||||
| if (widget.onQRViewCreated != null) { | |||||
| widget.onQRViewCreated(controller); | |||||
| } | |||||
| } | } | ||||
| } | |||||
| class _QrCameraSettings { | |||||
| _QrCameraSettings({ | |||||
| this.cameraFacing, | |||||
| }); | |||||
| final double width; | |||||
| final double height; | |||||
| final CameraFacing cameraFacing; | |||||
| Map<String, dynamic> toMap() { | Map<String, dynamic> toMap() { | ||||
| return <String, dynamic>{ | return <String, dynamic>{ | ||||
| 'width': width, | |||||
| 'height': height, | |||||
| 'cameraFacing': cameraFacing.index, | |||||
| }; | }; | ||||
| } | } | ||||
| } | } | ||||
| class QRViewController { | class QRViewController { | ||||
| QRViewController._(int id, GlobalKey qrKey, double scanArea) | |||||
| : _channel = MethodChannel('net.touchcapture.qr.flutterqr/qrview_$id') { | |||||
| updateDimensions(qrKey, scanArea: scanArea); | |||||
| _channel.setMethodCallHandler( | |||||
| (call) async { | |||||
| switch (call.method) { | |||||
| case scanMethodCall: | |||||
| if (call.arguments != null) { | |||||
| final args = call.arguments as Map; | |||||
| final code = args['code'] as String; | |||||
| final rawType = args['type'] as String; | |||||
| // Raw bytes are only supported by Android. | |||||
| final rawBytes = args['rawBytes'] as List<int>; | |||||
| final format = _formatNames[rawType]; | |||||
| if (format != null) { | |||||
| final barcode = Barcode(code, format, rawBytes); | |||||
| _scanUpdateController.sink.add(barcode); | |||||
| } else { | |||||
| throw Exception('Unexpected barcode type $rawType'); | |||||
| } | |||||
| } | |||||
| } | |||||
| }, | |||||
| ); | |||||
| QRViewController._(MethodChannel channel, GlobalKey qrKey, double scanArea) | |||||
| : _channel = channel { | |||||
| _channel.setMethodCallHandler(_onMethodCall); | |||||
| } | } | ||||
| static const scanMethodCall = 'onRecognizeQR'; | |||||
| final MethodChannel _channel; | final MethodChannel _channel; | ||||
| final StreamController<Barcode> _scanUpdateController = | final StreamController<Barcode> _scanUpdateController = | ||||
| StreamController<Barcode>(); | StreamController<Barcode>(); | ||||
| Stream<Barcode> get scannedDataStream => _scanUpdateController.stream; | Stream<Barcode> get scannedDataStream => _scanUpdateController.stream; | ||||
| Future<void> _onMethodCall(MethodCall call) async { | |||||
| switch (call.method) { | |||||
| case 'onRecognizeQR': | |||||
| if (call.arguments != null) { | |||||
| final args = call.arguments as Map; | |||||
| final code = args['code'] as String; | |||||
| final rawType = args['type'] as String; | |||||
| // Raw bytes are only supported by Android. | |||||
| final rawBytes = args['rawBytes'] as List<int>; | |||||
| final format = _formatNames[rawType]; | |||||
| if (format != null) { | |||||
| final barcode = Barcode(code, format, rawBytes); | |||||
| _scanUpdateController.sink.add(barcode); | |||||
| } else { | |||||
| throw Exception('Unexpected barcode type $rawType'); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /// Starts the barcode scanner | |||||
| Future<void> _startScan(GlobalKey key, double cutOutSize, ) async { | |||||
| // We need to update the dimension before the scan is started. | |||||
| QRViewController.updateDimensions(key, _channel, scanArea: cutOutSize); | |||||
| return _channel.invokeMethod('startScan'); | |||||
| } | |||||
| /// Flips the camera between available modes | |||||
| void flipCamera() { | void flipCamera() { | ||||
| _channel.invokeMethod('flipCamera'); | _channel.invokeMethod('flipCamera'); | ||||
| } | } | ||||
| /// Toggles the flashlight between available modes | |||||
| void toggleFlash() { | void toggleFlash() { | ||||
| _channel.invokeMethod('toggleFlash'); | _channel.invokeMethod('toggleFlash'); | ||||
| } | } | ||||
| /// Pauses barcode scanning | |||||
| void pauseCamera() { | void pauseCamera() { | ||||
| _channel.invokeMethod('pauseCamera'); | _channel.invokeMethod('pauseCamera'); | ||||
| } | } | ||||
| /// Resumes barcode scanning | |||||
| void resumeCamera() { | void resumeCamera() { | ||||
| _channel.invokeMethod('resumeCamera'); | _channel.invokeMethod('resumeCamera'); | ||||
| } | } | ||||
| /// Disposes the barcode stream. | |||||
| void dispose() { | void dispose() { | ||||
| _scanUpdateController.close(); | _scanUpdateController.close(); | ||||
| } | } | ||||
| void updateDimensions(GlobalKey key, {double scanArea}) { | |||||
| /// Updates the view dimensions for iOS. | |||||
| static void updateDimensions(GlobalKey key, MethodChannel channel, {double scanArea}) { | |||||
| if (defaultTargetPlatform == TargetPlatform.iOS) { | if (defaultTargetPlatform == TargetPlatform.iOS) { | ||||
| final RenderBox renderBox = key.currentContext.findRenderObject(); | final RenderBox renderBox = key.currentContext.findRenderObject(); | ||||
| _channel.invokeMethod('setDimensions', { | |||||
| channel.invokeMethod('setDimensions', { | |||||
| 'width': renderBox.size.width, | 'width': renderBox.size.width, | ||||
| 'height': renderBox.size.height, | 'height': renderBox.size.height, | ||||
| 'scanArea': scanArea ?? 0 | 'scanArea': scanArea ?? 0 | ||||