Showing
4 changed files
with
19 additions
and
296 deletions
| @@ -5,7 +5,6 @@ import 'package:flutter/services.dart'; | @@ -5,7 +5,6 @@ import 'package:flutter/services.dart'; | ||
| 5 | import 'package:mobile_scanner/mobile_scanner.dart'; | 5 | import 'package:mobile_scanner/mobile_scanner.dart'; |
| 6 | import 'package:mobile_scanner_example/picklist/classes/detect_collision.dart'; | 6 | import 'package:mobile_scanner_example/picklist/classes/detect_collision.dart'; |
| 7 | import 'package:mobile_scanner_example/picklist/widgets/crosshair.dart'; | 7 | import 'package:mobile_scanner_example/picklist/widgets/crosshair.dart'; |
| 8 | -import 'package:mobile_scanner_example/picklist/widgets/draw_detected_barcodes.dart'; | ||
| 9 | import 'package:mobile_scanner_example/scanner_error_widget.dart'; | 8 | import 'package:mobile_scanner_example/scanner_error_widget.dart'; |
| 10 | 9 | ||
| 11 | class BarcodeScannerPicklist extends StatefulWidget { | 10 | class BarcodeScannerPicklist extends StatefulWidget { |
| @@ -17,22 +16,16 @@ class BarcodeScannerPicklist extends StatefulWidget { | @@ -17,22 +16,16 @@ class BarcodeScannerPicklist extends StatefulWidget { | ||
| 17 | 16 | ||
| 18 | class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | 17 | class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> |
| 19 | with WidgetsBindingObserver { | 18 | with WidgetsBindingObserver { |
| 20 | - final _mobileScannerController = MobileScannerController(autoStart: false); | 19 | + final _mobileScannerController = MobileScannerController( |
| 20 | + autoStart: false, | ||
| 21 | + ); | ||
| 21 | StreamSubscription<Object?>? _barcodesSubscription; | 22 | StreamSubscription<Object?>? _barcodesSubscription; |
| 22 | 23 | ||
| 23 | final _scannerDisabled = ValueNotifier(false); | 24 | final _scannerDisabled = ValueNotifier(false); |
| 24 | 25 | ||
| 25 | - late final Offset _crosshair; | ||
| 26 | - | ||
| 27 | bool barcodeDetected = false; | 26 | bool barcodeDetected = false; |
| 28 | 27 | ||
| 29 | @override | 28 | @override |
| 30 | - void didChangeDependencies() { | ||
| 31 | - _crosshair = MediaQuery.sizeOf(context).center(Offset.zero); | ||
| 32 | - super.didChangeDependencies(); | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - @override | ||
| 36 | void initState() { | 29 | void initState() { |
| 37 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); | 30 | SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); |
| 38 | WidgetsBinding.instance.addObserver(this); | 31 | WidgetsBinding.instance.addObserver(this); |
| @@ -75,14 +68,17 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | @@ -75,14 +68,17 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | ||
| 75 | _mobileScannerController.dispose(); | 68 | _mobileScannerController.dispose(); |
| 76 | } | 69 | } |
| 77 | 70 | ||
| 78 | - void _handleBarcodes(BarcodeCapture barcodes) { | 71 | + void _handleBarcodes(BarcodeCapture capture) { |
| 79 | if (_scannerDisabled.value) { | 72 | if (_scannerDisabled.value) { |
| 80 | return; | 73 | return; |
| 81 | } | 74 | } |
| 82 | 75 | ||
| 83 | - for (final barcode in barcodes.barcodes) { | ||
| 84 | - if (isOffsetInsideShape( | ||
| 85 | - _crosshair, | 76 | + for (final barcode in capture.barcodes) { |
| 77 | + if (isPointInPolygon( | ||
| 78 | + Offset( | ||
| 79 | + _mobileScannerController.value.size.width / 2, | ||
| 80 | + _mobileScannerController.value.size.height / 2, | ||
| 81 | + ), | ||
| 86 | barcode.corners, | 82 | barcode.corners, |
| 87 | )) { | 83 | )) { |
| 88 | if (!barcodeDetected) { | 84 | if (!barcodeDetected) { |
| @@ -109,10 +105,6 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | @@ -109,10 +105,6 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | ||
| 109 | body: StreamBuilder( | 105 | body: StreamBuilder( |
| 110 | stream: _mobileScannerController.barcodes, | 106 | stream: _mobileScannerController.barcodes, |
| 111 | builder: (context, snapshot) { | 107 | builder: (context, snapshot) { |
| 112 | - final barcodes = snapshot.data; | ||
| 113 | - if (barcodes == null) { | ||
| 114 | - debugPrint('ISNULL'); | ||
| 115 | - } | ||
| 116 | return Listener( | 108 | return Listener( |
| 117 | behavior: HitTestBehavior.opaque, | 109 | behavior: HitTestBehavior.opaque, |
| 118 | onPointerDown: (_) => _scannerDisabled.value = true, | 110 | onPointerDown: (_) => _scannerDisabled.value = true, |
| @@ -123,14 +115,8 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | @@ -123,14 +115,8 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | ||
| 123 | children: [ | 115 | children: [ |
| 124 | MobileScanner( | 116 | MobileScanner( |
| 125 | controller: _mobileScannerController, | 117 | controller: _mobileScannerController, |
| 126 | - errorBuilder: (context, error, child) { | ||
| 127 | - return ScannerErrorWidget(error: error); | ||
| 128 | - }, | ||
| 129 | - fit: boxFit, | ||
| 130 | - ), | ||
| 131 | - ...drawDetectedBarcodes( | ||
| 132 | - barcodes: barcodes?.barcodes, | ||
| 133 | - cameraPreviewSize: _mobileScannerController.value.size, | 118 | + errorBuilder: (context, error, child) => |
| 119 | + ScannerErrorWidget(error: error), | ||
| 134 | fit: boxFit, | 120 | fit: boxFit, |
| 135 | ), | 121 | ), |
| 136 | ValueListenableBuilder( | 122 | ValueListenableBuilder( |
| @@ -145,51 +131,7 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | @@ -145,51 +131,7 @@ class _BarcodeScannerPicklistState extends State<BarcodeScannerPicklist> | ||
| 145 | ), | 131 | ), |
| 146 | ); | 132 | ); |
| 147 | }, | 133 | }, |
| 148 | - ) | ||
| 149 | - // body: Stack( | ||
| 150 | - // fit: StackFit.expand, | ||
| 151 | - // children: [ | ||
| 152 | - // MobileScanner( | ||
| 153 | - // controller: _mobileScannerController, | ||
| 154 | - // errorBuilder: (context, error, child) { | ||
| 155 | - // return ScannerErrorWidget(error: error); | ||
| 156 | - // }, | ||
| 157 | - // fit: boxFit, | ||
| 158 | - // ), | ||
| 159 | - // ...drawDetectedBarcodes( | ||
| 160 | - // controller: _mobileScannerController, | ||
| 161 | - // cameraPreviewSize: _mobileScannerController.value.size, | ||
| 162 | - // fit: boxFit, | ||
| 163 | - // ), | ||
| 164 | - // ...drawDetectedBarcodes( | ||
| 165 | - // controller: _mobileScannerController, | ||
| 166 | - // cameraPreviewSize: _mobileScannerController.value.size, | ||
| 167 | - // fit: boxFit, | ||
| 168 | - // ), | ||
| 169 | - // // barcodes: _mobileScannerController. value. _barcodes.value, | ||
| 170 | - // // cameraPreviewSize: _mobileScannerController.value.size, | ||
| 171 | - // // fit: boxFit, | ||
| 172 | - // // ), | ||
| 173 | - // CustomPaint( | ||
| 174 | - // painter: BarcodeOverlay( | ||
| 175 | - // barcodeCorners: [ | ||
| 176 | - // const Offset(0, 0), | ||
| 177 | - // const Offset(50, 0), | ||
| 178 | - // const Offset(50, 50), | ||
| 179 | - // const Offset(0, 50) | ||
| 180 | - // ], | ||
| 181 | - // barcodeSize: Size(50, 50), | ||
| 182 | - // boxFit: boxFit, | ||
| 183 | - // cameraPreviewSize: _mobileScannerController.value.size, | ||
| 184 | - // ), | ||
| 185 | - // ), | ||
| 186 | - // Crosshair( | ||
| 187 | - // crosshairRectangle: _crosshairRectangle, | ||
| 188 | - // scannerDisabled: _scannerDisabled.value, | ||
| 189 | - // ), | ||
| 190 | - // ], | ||
| 191 | - // ), | ||
| 192 | - , | 134 | + ), |
| 193 | ), | 135 | ), |
| 194 | ); | 136 | ); |
| 195 | } | 137 | } |
| 1 | -//Some magic created by chatGPT | ||
| 2 | - | ||
| 3 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 4 | 2 | ||
| 5 | -bool isOffsetInsideShape(Offset point, List<Offset> shape) { | ||
| 6 | - return _isPointInPolygon(shape, point); | ||
| 7 | -} | ||
| 8 | - | ||
| 9 | -bool _isPointInPolygon(List<Offset> polygon, Offset point) { | ||
| 10 | - // Use the ray-casting algorithm for checking if a point is inside a polygon | 3 | +bool isPointInPolygon(Offset point, List<Offset> polygon) { |
| 4 | + int i; | ||
| 5 | + int j = polygon.length - 1; | ||
| 11 | bool inside = false; | 6 | bool inside = false; |
| 12 | - for (int i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { | ||
| 13 | - if ((polygon[i].dy > point.dy) != (polygon[j].dy > point.dy) && | 7 | + |
| 8 | + for (i = 0; i < polygon.length; j = i++) { | ||
| 9 | + if (((polygon[i].dy > point.dy) != (polygon[j].dy > point.dy)) && | ||
| 14 | (point.dx < | 10 | (point.dx < |
| 15 | (polygon[j].dx - polygon[i].dx) * | 11 | (polygon[j].dx - polygon[i].dx) * |
| 16 | (point.dy - polygon[i].dy) / | 12 | (point.dy - polygon[i].dy) / |
| @@ -21,111 +17,3 @@ bool _isPointInPolygon(List<Offset> polygon, Offset point) { | @@ -21,111 +17,3 @@ bool _isPointInPolygon(List<Offset> polygon, Offset point) { | ||
| 21 | } | 17 | } |
| 22 | return inside; | 18 | return inside; |
| 23 | } | 19 | } |
| 24 | - | ||
| 25 | -// import 'package:flutter/material.dart'; | ||
| 26 | -// | ||
| 27 | -// bool crosshairFullyFitsIntoShape(Rect rect, List<Offset> shape) { | ||
| 28 | -// final List<Offset> rectCorners = [ | ||
| 29 | -// Offset(rect.left, rect.top), | ||
| 30 | -// Offset(rect.right, rect.top), | ||
| 31 | -// Offset(rect.right, rect.bottom), | ||
| 32 | -// Offset(rect.left, rect.bottom), | ||
| 33 | -// ]; | ||
| 34 | -// | ||
| 35 | -// // Check if all rect corners are inside the shape | ||
| 36 | -// for (final Offset corner in rectCorners) { | ||
| 37 | -// if (!_isPointInPolygon(shape, corner)) { | ||
| 38 | -// return false; // If any corner is outside, the rectangle doesn't fit fully | ||
| 39 | -// } | ||
| 40 | -// } | ||
| 41 | -// | ||
| 42 | -// return true; // All corners are inside the shape | ||
| 43 | -// } | ||
| 44 | -// | ||
| 45 | -// bool _isPointInPolygon(List<Offset> polygon, Offset point) { | ||
| 46 | -// // Use the ray-casting algorithm for checking if a point is inside a polygon | ||
| 47 | -// bool inside = false; | ||
| 48 | -// for (int i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { | ||
| 49 | -// if ((polygon[i].dy > point.dy) != (polygon[j].dy > point.dy) && | ||
| 50 | -// (point.dx < | ||
| 51 | -// (polygon[j].dx - polygon[i].dx) * | ||
| 52 | -// (point.dy - polygon[i].dy) / | ||
| 53 | -// (polygon[j].dy - polygon[i].dy) + | ||
| 54 | -// polygon[i].dx)) { | ||
| 55 | -// inside = !inside; | ||
| 56 | -// } | ||
| 57 | -// } | ||
| 58 | -// return inside; | ||
| 59 | -// } | ||
| 60 | -// // import 'package:flutter/material.dart'; | ||
| 61 | -// // | ||
| 62 | -// // bool crosshairTouchesBarcode(Rect rect, List<Offset> shape) { | ||
| 63 | -// // final List<Offset> rectCorners = [ | ||
| 64 | -// // Offset(rect.left, rect.top), | ||
| 65 | -// // Offset(rect.right, rect.top), | ||
| 66 | -// // Offset(rect.right, rect.bottom), | ||
| 67 | -// // Offset(rect.left, rect.bottom), | ||
| 68 | -// // ]; | ||
| 69 | -// // final List<Offset> edges = [shape[0], shape[1], shape[2], shape[3], shape[0]]; | ||
| 70 | -// // | ||
| 71 | -// // // Check edge intersection | ||
| 72 | -// // for (int i = 0; i < edges.length - 1; i++) { | ||
| 73 | -// // for (int j = 0; j < rectCorners.length; j++) { | ||
| 74 | -// // final int next = (j + 1) % rectCorners.length; | ||
| 75 | -// // if (_checkIntersection( | ||
| 76 | -// // edges[i], | ||
| 77 | -// // edges[i + 1], | ||
| 78 | -// // rectCorners[j], | ||
| 79 | -// // rectCorners[next], | ||
| 80 | -// // )) { | ||
| 81 | -// // return true; | ||
| 82 | -// // } | ||
| 83 | -// // } | ||
| 84 | -// // } | ||
| 85 | -// // | ||
| 86 | -// // // Check if any rect corner is inside the shape | ||
| 87 | -// // for (final Offset corner in rectCorners) { | ||
| 88 | -// // if (_isPointInPolygon(shape, corner)) { | ||
| 89 | -// // return true; | ||
| 90 | -// // } | ||
| 91 | -// // } | ||
| 92 | -// // | ||
| 93 | -// // return false; | ||
| 94 | -// // } | ||
| 95 | -// // | ||
| 96 | -// // bool _checkIntersection(Offset p1, Offset p2, Offset p3, Offset p4) { | ||
| 97 | -// // // Calculate the intersection of two line segments | ||
| 98 | -// // double s1X; | ||
| 99 | -// // double s1Y; | ||
| 100 | -// // double s2X; | ||
| 101 | -// // double s2Y; | ||
| 102 | -// // s1X = p2.dx - p1.dx; | ||
| 103 | -// // s1Y = p2.dy - p1.dy; | ||
| 104 | -// // s2X = p4.dx - p3.dx; | ||
| 105 | -// // s2Y = p4.dy - p3.dy; | ||
| 106 | -// // | ||
| 107 | -// // double s; | ||
| 108 | -// // double t; | ||
| 109 | -// // s = (-s1Y * (p1.dx - p3.dx) + s1X * (p1.dy - p3.dy)) / | ||
| 110 | -// // (-s2X * s1Y + s1X * s2Y); | ||
| 111 | -// // t = (s2X * (p1.dy - p3.dy) - s2Y * (p1.dx - p3.dx)) / | ||
| 112 | -// // (-s2X * s1Y + s1X * s2Y); | ||
| 113 | -// // | ||
| 114 | -// // return s >= 0 && s <= 1 && t >= 0 && t <= 1; | ||
| 115 | -// // } | ||
| 116 | -// // | ||
| 117 | -// // bool _isPointInPolygon(List<Offset> polygon, Offset point) { | ||
| 118 | -// // // Ray-casting algorithm for checking if a point is inside a polygon | ||
| 119 | -// // bool inside = false; | ||
| 120 | -// // for (int i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { | ||
| 121 | -// // if ((polygon[i].dy > point.dy) != (polygon[j].dy > point.dy) && | ||
| 122 | -// // (point.dx < | ||
| 123 | -// // (polygon[j].dx - polygon[i].dx) * | ||
| 124 | -// // (point.dy - polygon[i].dy) / | ||
| 125 | -// // (polygon[j].dy - polygon[i].dy) + | ||
| 126 | -// // polygon[i].dx)) { | ||
| 127 | -// // inside = !inside; | ||
| 128 | -// // } | ||
| 129 | -// // } | ||
| 130 | -// // return inside; | ||
| 131 | -// // } |
| 1 | -import 'package:flutter/foundation.dart'; | ||
| 2 | -import 'package:flutter/material.dart'; | ||
| 3 | - | ||
| 4 | -class BarcodeOverlay extends CustomPainter { | ||
| 5 | - BarcodeOverlay({ | ||
| 6 | - required this.barcodeCorners, | ||
| 7 | - required this.barcodeSize, | ||
| 8 | - required this.boxFit, | ||
| 9 | - required this.cameraPreviewSize, | ||
| 10 | - }); | ||
| 11 | - | ||
| 12 | - final List<Offset> barcodeCorners; | ||
| 13 | - final Size barcodeSize; | ||
| 14 | - final BoxFit boxFit; | ||
| 15 | - final Size cameraPreviewSize; | ||
| 16 | - | ||
| 17 | - @override | ||
| 18 | - void paint(Canvas canvas, Size size) { | ||
| 19 | - if (barcodeCorners.isEmpty || | ||
| 20 | - barcodeSize.isEmpty || | ||
| 21 | - cameraPreviewSize.isEmpty) { | ||
| 22 | - return; | ||
| 23 | - } | ||
| 24 | - | ||
| 25 | - final adjustedSize = applyBoxFit(boxFit, cameraPreviewSize, size); | ||
| 26 | - | ||
| 27 | - double verticalPadding = size.height - adjustedSize.destination.height; | ||
| 28 | - double horizontalPadding = size.width - adjustedSize.destination.width; | ||
| 29 | - if (verticalPadding > 0) { | ||
| 30 | - verticalPadding = verticalPadding / 2; | ||
| 31 | - } else { | ||
| 32 | - verticalPadding = 0; | ||
| 33 | - } | ||
| 34 | - | ||
| 35 | - if (horizontalPadding > 0) { | ||
| 36 | - horizontalPadding = horizontalPadding / 2; | ||
| 37 | - } else { | ||
| 38 | - horizontalPadding = 0; | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - final double ratioWidth; | ||
| 42 | - final double ratioHeight; | ||
| 43 | - | ||
| 44 | - if (!kIsWeb && defaultTargetPlatform == TargetPlatform.iOS) { | ||
| 45 | - ratioWidth = barcodeSize.width / adjustedSize.destination.width; | ||
| 46 | - ratioHeight = barcodeSize.height / adjustedSize.destination.height; | ||
| 47 | - } else { | ||
| 48 | - ratioWidth = cameraPreviewSize.width / adjustedSize.destination.width; | ||
| 49 | - ratioHeight = cameraPreviewSize.height / adjustedSize.destination.height; | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - final List<Offset> adjustedOffset = [ | ||
| 53 | - for (final offset in barcodeCorners) | ||
| 54 | - Offset( | ||
| 55 | - offset.dx / ratioWidth + horizontalPadding, | ||
| 56 | - offset.dy / ratioHeight + verticalPadding, | ||
| 57 | - ), | ||
| 58 | - ]; | ||
| 59 | - | ||
| 60 | - final cutoutPath = Path()..addPolygon(adjustedOffset, true); | ||
| 61 | - | ||
| 62 | - final backgroundPaint = Paint() | ||
| 63 | - ..color = Colors.red.withOpacity(1.0) | ||
| 64 | - ..style = PaintingStyle.fill | ||
| 65 | - ..blendMode = BlendMode.dstOut; | ||
| 66 | - | ||
| 67 | - canvas.drawPath(cutoutPath, backgroundPaint); | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - @override | ||
| 71 | - bool shouldRepaint(covariant CustomPainter oldDelegate) { | ||
| 72 | - return false; | ||
| 73 | - } | ||
| 74 | -} |
| 1 | -import 'package:flutter/material.dart'; | ||
| 2 | -import 'package:mobile_scanner/mobile_scanner.dart'; | ||
| 3 | -import 'package:mobile_scanner_example/picklist/widgets/barcode_overlay.dart'; | ||
| 4 | - | ||
| 5 | -List<Widget> drawDetectedBarcodes({ | ||
| 6 | - required List<Barcode>? barcodes, | ||
| 7 | - required Size cameraPreviewSize, | ||
| 8 | - required BoxFit fit, | ||
| 9 | -}) { | ||
| 10 | - final barcodeWidgets = <Widget>[]; | ||
| 11 | - if (barcodes == null || barcodes.isEmpty) { | ||
| 12 | - debugPrint('EMPTY!!!'); | ||
| 13 | - } | ||
| 14 | - if (barcodes != null) { | ||
| 15 | - for (final barcode in barcodes) { | ||
| 16 | - barcodeWidgets.add( | ||
| 17 | - CustomPaint( | ||
| 18 | - painter: BarcodeOverlay( | ||
| 19 | - barcodeCorners: barcode.corners, | ||
| 20 | - barcodeSize: barcode.size, | ||
| 21 | - boxFit: fit, | ||
| 22 | - cameraPreviewSize: cameraPreviewSize, | ||
| 23 | - ), | ||
| 24 | - ), | ||
| 25 | - ); | ||
| 26 | - debugPrint( | ||
| 27 | - 'barcodeCorners => ${barcode.corners.map((e) => 'x: ${e.dx}, y: ${e.dy} ')}, barcodeSize => width: ${barcode.size.width}, height: ${barcode.size.height}, cameraPreviewSize => width: ${cameraPreviewSize.width}, height: ${cameraPreviewSize.height} ', | ||
| 28 | - ); | ||
| 29 | - } | ||
| 30 | - debugPrint(barcodeWidgets.length.toString()); | ||
| 31 | - } | ||
| 32 | - return barcodeWidgets; | ||
| 33 | -} |
-
Please register or login to post a comment