diff --git a/lib/components/scanner_overlay.dart b/lib/components/scanner_overlay.dart new file mode 100644 index 0000000000000000000000000000000000000000..5c1bdfc536d4adb5242016682a47ea6fed1bf49d --- /dev/null +++ b/lib/components/scanner_overlay.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; + +/// Main overlay widget that displays the scanner frame +class ScannerOverlay extends StatelessWidget { + const ScannerOverlay({super.key}); + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + // Calculate size and position of the scan area (square in center) + final size = constraints.maxWidth * 0.7; + final left = (constraints.maxWidth - size) / 2; + final top = (constraints.maxHeight - size) / 2; + + return Stack( + children: [ + /// Dark overlay with a transparent cut-out for scanning + CustomPaint( + size: Size(constraints.maxWidth, constraints.maxHeight), + painter: _ScannerMaskPainter( + holeRect: Rect.fromLTWH(left, top, size, size), + ), + ), + + /// Corner-only borders around the scan area + Positioned( + left: left, + top: top, + width: size, + height: size, + child: CustomPaint( + painter: _CornerBorderPainter(), + ), + ), + ], + ); + }, + ); + } +} + +/// Painter for the dark overlay with transparent center +class _ScannerMaskPainter extends CustomPainter { + final Rect holeRect; + + _ScannerMaskPainter({required this.holeRect}); + + @override + void paint(Canvas canvas, Size size) { + final paint = Paint() + ..color = Colors.black.withOpacity(0.6); // semi-transparent overlay + + final path = Path() + ..addRect(Rect.fromLTWH(0, 0, size.width, size.height)) // full screen + ..addRRect( + RRect.fromRectAndRadius( + holeRect, // center cut-out + const Radius.circular(16), + ), + ) + ..fillType = PathFillType.evenOdd; // cut-out effect + + canvas.drawPath(path, paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} + +/// Painter for corner borders (scanner style) +class _CornerBorderPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + const cornerLength = 28.0; // length of each corner line + const strokeWidth = 4.0; // thickness of corner lines + + final paint = Paint() + ..color = Colors.greenAccent + ..strokeWidth = strokeWidth + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.square; + + // Top-left corner + canvas.drawLine(const Offset(0, 0), const Offset(cornerLength, 0), paint); + canvas.drawLine(const Offset(0, 0), const Offset(0, cornerLength), paint); + + // Top-right corner + canvas.drawLine( + Offset(size.width, 0), + Offset(size.width - cornerLength, 0), + paint); + canvas.drawLine( + Offset(size.width, 0), + Offset(size.width, cornerLength), + paint); + + // Bottom-left corner + canvas.drawLine( + Offset(0, size.height), + Offset(cornerLength, size.height), + paint); + canvas.drawLine( + Offset(0, size.height), + Offset(0, size.height - cornerLength), + paint); + + // Bottom-right corner + canvas.drawLine( + Offset(size.width, size.height), + Offset(size.width - cornerLength, size.height), + paint); + canvas.drawLine( + Offset(size.width, size.height), + Offset(size.width, size.height - cornerLength), + paint); + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) => false; +} diff --git a/lib/views/qr_scanner_screen.dart b/lib/views/qr_scanner_screen.dart index 658afab38d1de56ea14c7c23a208fa0b43162d00..0544a0af9d09f816f431e6d1f12a954a2c5b0df0 100644 --- a/lib/views/qr_scanner_screen.dart +++ b/lib/views/qr_scanner_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; +import 'package:checkmein/components/scanner_overlay.dart'; -/// A simple screen that shows the camera and returns the scanned code class QrScannerScreen extends StatefulWidget { const QrScannerScreen({super.key}); @@ -10,31 +10,32 @@ class QrScannerScreen extends StatefulWidget { } class _QrScannerScreenState extends State { - // Flag to prevent multiple pops if the scanner detects the same code rapidly bool _hasScanned = false; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Scanner le QR Code")), - // MobileScanner handles permission requests automatically - body: MobileScanner( - onDetect: (capture) { - if (_hasScanned) return; + body: Stack( + children: [ + /// Camera + MobileScanner( + onDetect: (capture) { + if (_hasScanned) return; - final List barcodes = capture.barcodes; - for (final barcode in barcodes) { - if (barcode.rawValue != null) { - final code = barcode.rawValue!; - // Basic validation: ensure it looks like a URL - if (code.startsWith("http")) { - _hasScanned = true; - Navigator.pop(context, code); - break; + for (final barcode in capture.barcodes) { + final code = barcode.rawValue; + if (code != null && code.startsWith("http")) { + _hasScanned = true; + Navigator.pop(context, code); + break; + } } - } - } - }, + }, + ), + + const ScannerOverlay(), + ], ), ); }