|
|
@ -5,10 +5,9 @@ import 'dart:math'; |
|
|
|
import 'package:camera/camera.dart'; |
|
|
|
import 'package:camera/camera.dart'; |
|
|
|
import 'package:flutter/material.dart'; |
|
|
|
import 'package:flutter/material.dart'; |
|
|
|
|
|
|
|
|
|
|
|
// import 'package:flutter_beep/flutter_beep.dart'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import '../../flutter_zxing.dart'; |
|
|
|
import '../../flutter_zxing.dart'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Widget to scan a code from the camera stream |
|
|
|
class ReaderWidget extends StatefulWidget { |
|
|
|
class ReaderWidget extends StatefulWidget { |
|
|
|
const ReaderWidget({ |
|
|
|
const ReaderWidget({ |
|
|
|
super.key, |
|
|
|
super.key, |
|
|
@ -18,7 +17,7 @@ class ReaderWidget extends StatefulWidget { |
|
|
|
this.codeFormat = Format.any, |
|
|
|
this.codeFormat = Format.any, |
|
|
|
this.tryHarder = false, |
|
|
|
this.tryHarder = false, |
|
|
|
this.tryInverted = false, |
|
|
|
this.tryInverted = false, |
|
|
|
this.showCroppingRect = true, |
|
|
|
this.showScannerOverlay = true, |
|
|
|
this.scannerOverlay, |
|
|
|
this.scannerOverlay, |
|
|
|
this.showFlashlight = true, |
|
|
|
this.showFlashlight = true, |
|
|
|
this.allowPinchZoom = true, |
|
|
|
this.allowPinchZoom = true, |
|
|
@ -30,20 +29,49 @@ class ReaderWidget extends StatefulWidget { |
|
|
|
const DecoratedBox(decoration: BoxDecoration(color: Colors.black)), |
|
|
|
const DecoratedBox(decoration: BoxDecoration(color: Colors.black)), |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Called when a code is detected |
|
|
|
final Function(Code) onScan; |
|
|
|
final Function(Code) onScan; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Called when a code is not detected |
|
|
|
final Function()? onScanFailure; |
|
|
|
final Function()? onScanFailure; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Called when the camera controller is created |
|
|
|
final Function(CameraController?)? onControllerCreated; |
|
|
|
final Function(CameraController?)? onControllerCreated; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Code format to scan |
|
|
|
final int codeFormat; |
|
|
|
final int codeFormat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Try harder to detect a code |
|
|
|
final bool tryHarder; |
|
|
|
final bool tryHarder; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Try to detect inverted code |
|
|
|
final bool tryInverted; |
|
|
|
final bool tryInverted; |
|
|
|
final bool showCroppingRect; |
|
|
|
|
|
|
|
|
|
|
|
/// Show cropping rect |
|
|
|
|
|
|
|
final bool showScannerOverlay; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Custom scanner overlay |
|
|
|
final ScannerOverlay? scannerOverlay; |
|
|
|
final ScannerOverlay? scannerOverlay; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Show flashlight button |
|
|
|
final bool showFlashlight; |
|
|
|
final bool showFlashlight; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Allow pinch zoom |
|
|
|
final bool allowPinchZoom; |
|
|
|
final bool allowPinchZoom; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delay between scans when no code is detected |
|
|
|
final Duration scanDelay; |
|
|
|
final Duration scanDelay; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Crop percent of the screen |
|
|
|
final double cropPercent; |
|
|
|
final double cropPercent; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Camera resolution |
|
|
|
final ResolutionPreset resolution; |
|
|
|
final ResolutionPreset resolution; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Delay between scans when a code is detected |
|
|
|
final Duration scanDelaySuccess; |
|
|
|
final Duration scanDelaySuccess; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Loading widget while camera is initializing. Default is a black screen |
|
|
|
final Widget loading; |
|
|
|
final Widget loading; |
|
|
|
|
|
|
|
|
|
|
|
@override |
|
|
|
@override |
|
|
@ -130,34 +158,37 @@ class _ReaderWidgetState extends State<ReaderWidget> |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Future<void> onNewCameraSelected(CameraDescription cameraDescription) async { |
|
|
|
Future<void> onNewCameraSelected(CameraDescription cameraDescription) async { |
|
|
|
if (controller != null) { |
|
|
|
final CameraController? oldController = controller; |
|
|
|
controller?.removeListener(rebuildOnMount); |
|
|
|
if (oldController != null) { |
|
|
|
await controller!.dispose(); |
|
|
|
// controller?.removeListener(rebuildOnMount); |
|
|
|
|
|
|
|
controller = null; |
|
|
|
|
|
|
|
await oldController.dispose(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
controller = CameraController( |
|
|
|
final CameraController cameraController = CameraController( |
|
|
|
cameraDescription, |
|
|
|
cameraDescription, |
|
|
|
widget.resolution, |
|
|
|
widget.resolution, |
|
|
|
enableAudio: false, |
|
|
|
enableAudio: false, |
|
|
|
imageFormatGroup: |
|
|
|
imageFormatGroup: |
|
|
|
isAndroid() ? ImageFormatGroup.yuv420 : ImageFormatGroup.bgra8888, |
|
|
|
isAndroid() ? ImageFormatGroup.yuv420 : ImageFormatGroup.bgra8888, |
|
|
|
); |
|
|
|
); |
|
|
|
if (controller == null) { |
|
|
|
controller = cameraController; |
|
|
|
return; |
|
|
|
cameraController.addListener(rebuildOnMount); |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
await controller!.initialize(); |
|
|
|
await cameraController.initialize(); |
|
|
|
await controller!.setFlashMode(FlashMode.off); |
|
|
|
await cameraController.setFlashMode(FlashMode.off); |
|
|
|
_maxZoomLevel = await controller!.getMaxZoomLevel(); |
|
|
|
cameraController |
|
|
|
_minZoomLevel = await controller!.getMinZoomLevel(); |
|
|
|
.getMaxZoomLevel() |
|
|
|
controller!.startImageStream(processImageStream); |
|
|
|
.then((double value) => _maxZoomLevel = value); |
|
|
|
|
|
|
|
cameraController |
|
|
|
|
|
|
|
.getMinZoomLevel() |
|
|
|
|
|
|
|
.then((double value) => _minZoomLevel = value); |
|
|
|
|
|
|
|
cameraController.startImageStream(processImageStream); |
|
|
|
} on CameraException catch (e) { |
|
|
|
} on CameraException catch (e) { |
|
|
|
debugPrint('${e.code}: ${e.description}'); |
|
|
|
debugPrint('${e.code}: ${e.description}'); |
|
|
|
} catch (e) { |
|
|
|
} catch (e) { |
|
|
|
debugPrint('Error: $e'); |
|
|
|
debugPrint('Error: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
controller!.addListener(rebuildOnMount); |
|
|
|
|
|
|
|
rebuildOnMount(); |
|
|
|
rebuildOnMount(); |
|
|
|
widget.onControllerCreated?.call(controller); |
|
|
|
widget.onControllerCreated?.call(controller); |
|
|
|
} |
|
|
|
} |
|
|
@ -167,7 +198,7 @@ class _ReaderWidgetState extends State<ReaderWidget> |
|
|
|
_isProcessing = true; |
|
|
|
_isProcessing = true; |
|
|
|
try { |
|
|
|
try { |
|
|
|
final double cropPercent = |
|
|
|
final double cropPercent = |
|
|
|
widget.showCroppingRect ? widget.cropPercent : 0; |
|
|
|
widget.showScannerOverlay ? widget.cropPercent : 0; |
|
|
|
final int cropSize = |
|
|
|
final int cropSize = |
|
|
|
(min(image.width, image.height) * cropPercent).round(); |
|
|
|
(min(image.width, image.height) * cropPercent).round(); |
|
|
|
final Params params = Params( |
|
|
|
final Params params = Params( |
|
|
@ -230,7 +261,7 @@ class _ReaderWidgetState extends State<ReaderWidget> |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
), |
|
|
|
if (widget.showCroppingRect) |
|
|
|
if (widget.showScannerOverlay) |
|
|
|
Container( |
|
|
|
Container( |
|
|
|
decoration: ShapeDecoration( |
|
|
|
decoration: ShapeDecoration( |
|
|
|
shape: widget.scannerOverlay ?? |
|
|
|
shape: widget.scannerOverlay ?? |
|
|
|