abimulya_

FlexibleScanBarcode

Dec 16th, 2024
7
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Dart 5.68 KB | None | 0 0
  1. import 'dart:async';
  2.  
  3. import 'package:accurate_lite/core/components/page/scan/scanner_error_view.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_hooks/flutter_hooks.dart';
  6. import 'package:mobile_scanner/mobile_scanner.dart';
  7.  
  8. class FlexibleScanBarcode extends StatefulHookWidget {
  9.   const FlexibleScanBarcode({
  10.     super.key,
  11.     this.descScannerText = '',
  12.     this.isUseExternalScanner = true,
  13.     required this.doOnDetect,
  14.     required this.controller,
  15.   });
  16.  
  17.   final String? descScannerText;
  18.   final bool isUseExternalScanner;
  19.   final Future Function(String _barcodeFound) doOnDetect;
  20.   final MobileScannerController controller;
  21.  
  22.   @override
  23.   State<FlexibleScanBarcode> createState() => _FlexibleScanBarcodeState();
  24. }
  25.  
  26. class _FlexibleScanBarcodeState extends State<FlexibleScanBarcode>
  27.     with SingleTickerProviderStateMixin {
  28.   late AnimationController _animationController;
  29.   String _barcodeFound = '';
  30.   bool _isDetected = false;
  31.   Barcode? barcode;
  32.   BarcodeCapture? capture;
  33.   Timer? _debounceTimer;
  34.  
  35.   @override
  36.   void initState() {
  37.     super.initState();
  38.     _animationController = AnimationController(
  39.       duration: const Duration(seconds: 1),
  40.       reverseDuration: const Duration(seconds: 1),
  41.       vsync: this,
  42.     );
  43.  
  44.     widget.controller.start();
  45.     _animationController.repeat(reverse: true);
  46.   }
  47.  
  48.   @override
  49.   void dispose() {
  50.     widget.controller.dispose();
  51.     _animationController.stop();
  52.     _animationController.dispose();
  53.     super.dispose();
  54.   }
  55.  
  56.   void onDetect(BarcodeCapture barcode) async {
  57.     if (_debounceTimer?.isActive ?? false) return;
  58.  
  59.     _debounceTimer = Timer(const Duration(milliseconds: 500), () async {
  60.       capture = barcode;
  61.       this.barcode = barcode.barcodes.first;
  62.  
  63.       for (final barcodes in capture!.barcodes) {
  64.         _barcodeFound = barcodes.rawValue!;
  65.  
  66.         if (!_isDetected) {
  67.           _isDetected = true;
  68.           await widget.doOnDetect(_barcodeFound).then((value) {
  69.             _isDetected = false;
  70.           });
  71.           _debounceTimer?.cancel();
  72.         }
  73.       }
  74.     });
  75.   }
  76.  
  77.   @override
  78.   Widget build(BuildContext context) {
  79.     const scanWindowWidthFactor = 0.9;
  80.     double scanWindowHeightFactor = 0.8;
  81.     double scanWindowTopFactor = 0.1;
  82.  
  83.     return LayoutBuilder(
  84.       builder: (context, constraints) {
  85.         if (constraints.maxHeight > 550) {
  86.           scanWindowHeightFactor = 0.4;
  87.           scanWindowTopFactor = 0.3;
  88.         }
  89.  
  90.         final scanWindow = Rect.fromLTWH(
  91.           constraints.maxWidth * (1 - scanWindowWidthFactor) / 2,
  92.           constraints.maxHeight *
  93.               scanWindowTopFactor, // Adjusted for half screen
  94.           constraints.maxWidth * scanWindowWidthFactor,
  95.           constraints.maxHeight * scanWindowHeightFactor,
  96.         );
  97.  
  98.         return SizedBox(
  99.           width: constraints.maxWidth,
  100.           height: constraints.maxHeight,
  101.           child: Stack(
  102.             children: [
  103.               MobileScanner(
  104.                 scanWindow: scanWindow,
  105.                 controller: widget.controller,
  106.                 errorBuilder: (context, error, child) {
  107.                   return ScannerErrorView(
  108.                     error: error,
  109.                     controller: widget.controller,
  110.                   );
  111.                 },
  112.                 onDetect: onDetect,
  113.               ),
  114.               // Overlay for scanner
  115.               CustomPaint(
  116.                 size: Size(constraints.maxWidth, constraints.maxHeight),
  117.                 painter: ScannerOverlay(scanWindow),
  118.               ),
  119.               // Red line
  120.               CustomPaint(
  121.                 size: Size(constraints.maxWidth, constraints.maxHeight),
  122.                 painter: RedLinePainter(
  123.                   animationController: _animationController,
  124.                   scanWindow: scanWindow,
  125.                 ),
  126.               ),
  127.             ],
  128.           ),
  129.         );
  130.       },
  131.     );
  132.   }
  133. }
  134.  
  135. class RedLinePainter extends CustomPainter {
  136.   RedLinePainter({
  137.     required this.animationController,
  138.     required this.scanWindow,
  139.   });
  140.  
  141.   final AnimationController animationController;
  142.   final Rect scanWindow;
  143.  
  144.   late final Animation<double> _animation =
  145.       Tween<double>(begin: 0, end: 1).animate(animationController);
  146.  
  147.   @override
  148.   void paint(Canvas canvas, Size size) {
  149.     final paint = Paint()
  150.       ..color = Colors.red.withOpacity(_animation.value)
  151.       ..strokeWidth = 2
  152.       ..style = PaintingStyle.stroke
  153.       ..strokeCap = StrokeCap.round;
  154.  
  155.     // Calculate line position based on scan window
  156.     final centerY = scanWindow.top + (scanWindow.height * 0.5);
  157.  
  158.     canvas.drawLine(
  159.       Offset(scanWindow.left + 20, centerY),
  160.       Offset(scanWindow.right - 20, centerY),
  161.       paint,
  162.     );
  163.   }
  164.  
  165.   @override
  166.   bool shouldRepaint(RedLinePainter oldDelegate) => true;
  167. }
  168.  
  169. class ScannerOverlay extends CustomPainter {
  170.   ScannerOverlay(this.scanWindow);
  171.  
  172.   final Rect scanWindow;
  173.  
  174.   @override
  175.   void paint(Canvas canvas, Size size) {
  176.     final backgroundPath = Path()..addRect(Rect.largest);
  177.     final cutoutPath = Path()..addRect(scanWindow);
  178.  
  179.     // Menggambar overlay hitam transparan
  180.     canvas.drawPath(
  181.       Path.combine(
  182.         PathOperation.difference,
  183.         backgroundPath,
  184.         cutoutPath,
  185.       ),
  186.       Paint()..color = Colors.black.withOpacity(0.5),
  187.     );
  188.  
  189.     // Menggambar border putih di sekitar area scanning
  190.     final borderPaint = Paint()
  191.       ..color = Colors.transparent
  192.       ..style = PaintingStyle.stroke
  193.       ..strokeWidth = 2.0;
  194.  
  195.     canvas.drawRect(scanWindow, borderPaint);
  196.   }
  197.  
  198.   @override
  199.   bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
  200. }
  201.  
Add Comment
Please, Sign In to add comment