content: import 'dart:ui';
  
  import 'package:firebase_ml_vision/firebase_ml_vision.dart';
  import 'package:flutter/material.dart';
  import 'package:flutter_camera_ml_vision/flutter_camera_ml_vision.dart';
  
  void main() => runApp(MyApp());
  
  class MyApp extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Flutter Demo Home Page'),
      );
    }
  }
  
  class MyHomePage extends StatefulWidget {
    MyHomePage({Key key, this.title}) : super(key: key);
  
    final String title;
  
    @override
    _MyHomePageState createState() => _MyHomePageState();
  }
  
  class _MyHomePageState extends State<MyHomePage> {
    List<String> data = [];
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () async {
                final barcode = await Navigator.of(context).push<Barcode>(
                  MaterialPageRoute(
                    builder: (c) {
                      return ScanPage();
                    },
                  ),
                );
                if (barcode == null) {
                  return;
                }
  
                setState(() {
                  data.add(barcode.displayValue);
                });
              },
              child: Text('Scan product'),
            ),
            Expanded(
              child: ListView(
                children: data.map((d) => Text(d)).toList(),
              ),
            ),
          ],
        ), // This trailing comma makes auto-formatting nicer for build methods.
      );
    }
  }
  
  class ScanPage extends StatefulWidget {
    @override
    _ScanPageState createState() => _ScanPageState();
  }
  
  class _ScanPageState extends State<ScanPage> {
    bool resultSent = false;
    BarcodeDetector detector = FirebaseVision.instance.barcodeDetector();
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: SizedBox(
            width: MediaQuery.of(context).size.width,
            child: CameraMlVision<List<Barcode>>(
              overlayBuilder: (c) {
                return Container(
                  decoration: ShapeDecoration(
                    shape: _ScannerOverlayShape(
                      borderColor: Theme.of(context).primaryColor,
                      borderWidth: 3.0,
                    ),
                  ),
                );
              },
              detector: detector.detectInImage,
              onResult: (List<Barcode> barcodes) {
                if (!mounted ||
                    resultSent ||
                    barcodes == null ||
                    barcodes.isEmpty) {
                  return;
                }
                resultSent = true;
                Navigator.of(context).pop<Barcode>(barcodes.first);
              },
              onDispose: () {
                detector.close();
              },
            ),
          ),
        ),
      );
    }
  }
  
  class _ScannerOverlayShape extends ShapeBorder {
    final Color borderColor;
    final double borderWidth;
    final Color overlayColor;
  
    _ScannerOverlayShape({
      this.borderColor = Colors.white,
      this.borderWidth = 1.0,
      this.overlayColor = const Color(0x88000000),
    });
  
    @override
    EdgeInsetsGeometry get dimensions => EdgeInsets.all(10.0);
  
    @override
    Path getInnerPath(Rect rect, {TextDirection textDirection}) {
      return Path()
        ..fillType = PathFillType.evenOdd
        ..addPath(getOuterPath(rect), Offset.zero);
    }
  
    @override
    Path getOuterPath(Rect rect, {TextDirection textDirection}) {
      Path _getLeftTopPath(Rect rect) {
        return Path()
          ..moveTo(rect.left, rect.bottom)
          ..lineTo(rect.left, rect.top)
          ..lineTo(rect.right, rect.top);
      }
  
      return _getLeftTopPath(rect)
        ..lineTo(
          rect.right,
          rect.bottom,
        )
        ..lineTo(
          rect.left,
          rect.bottom,
        )
        ..lineTo(
          rect.left,
          rect.top,
        );
    }
  
    @override
    void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {
      const lineSize = 30;
  
      final width = rect.width;
      final borderWidthSize = width * 10 / 100;
      final height = rect.height;
      final borderHeightSize = height - (width - borderWidthSize);
      final borderSize = Size(borderWidthSize / 2, borderHeightSize / 2);
  
      var paint = Paint()
        ..color = overlayColor
        ..style = PaintingStyle.fill;
  
      canvas
        ..drawRect(
          Rect.fromLTRB(
              rect.left, rect.top, rect.right, borderSize.height + rect.top),
          paint,
        )
        ..drawRect(
          Rect.fromLTRB(rect.left, rect.bottom - borderSize.height, rect.right,
              rect.bottom),
          paint,
        )
        ..drawRect(
          Rect.fromLTRB(rect.left, rect.top + borderSize.height,
              rect.left + borderSize.width, rect.bottom - borderSize.height),
          paint,
        )
        ..drawRect(
          Rect.fromLTRB(
              rect.right - borderSize.width,
              rect.top + borderSize.height,
              rect.right,
              rect.bottom - borderSize.height),
          paint,
        );
  
      paint = Paint()
        ..color = borderColor
        ..style = PaintingStyle.stroke
        ..strokeWidth = borderWidth;
  
      final borderOffset = borderWidth / 2;
      final realReact = Rect.fromLTRB(
          borderSize.width + borderOffset,
          borderSize.height + borderOffset + rect.top,
          width - borderSize.width - borderOffset,
          height - borderSize.height - borderOffset + rect.top);
  
      //Draw top right corner
      canvas
        ..drawPath(
            Path()
              ..moveTo(realReact.right, realReact.top)
              ..lineTo(realReact.right, realReact.top + lineSize),
            paint)
        ..drawPath(
            Path()
              ..moveTo(realReact.right, realReact.top)
              ..lineTo(realReact.right - lineSize, realReact.top),
            paint)
        ..drawPoints(
          PointMode.points,
          [Offset(realReact.right, realReact.top)],
          paint,
        )
  
        //Draw top left corner
        ..drawPath(
            Path()
              ..moveTo(realReact.left, realReact.top)
              ..lineTo(realReact.left, realReact.top + lineSize),
            paint)
        ..drawPath(
            Path()
              ..moveTo(realReact.left, realReact.top)
              ..lineTo(realReact.left + lineSize, realReact.top),
            paint)
        ..drawPoints(
          PointMode.points,
          [Offset(realReact.left, realReact.top)],
          paint,
        )
  
        //Draw bottom right corner
        ..drawPath(
            Path()
              ..moveTo(realReact.right, realReact.bottom)
              ..lineTo(realReact.right, realReact.bottom - lineSize),
            paint)
        ..drawPath(
            Path()
              ..moveTo(realReact.right, realReact.bottom)
              ..lineTo(realReact.right - lineSize, realReact.bottom),
            paint)
        ..drawPoints(
          PointMode.points,
          [Offset(realReact.right, realReact.bottom)],
          paint,
        )
  
        //Draw bottom left corner
        ..drawPath(
            Path()
              ..moveTo(realReact.left, realReact.bottom)
              ..lineTo(realReact.left, realReact.bottom - lineSize),
            paint)
        ..drawPath(
            Path()
              ..moveTo(realReact.left, realReact.bottom)
              ..lineTo(realReact.left + lineSize, realReact.bottom),
            paint)
        ..drawPoints(
          PointMode.points,
          [Offset(realReact.left, realReact.bottom)],
          paint,
        );
    }
  
    @override
    ShapeBorder scale(double t) {
      return _ScannerOverlayShape(
        borderColor: borderColor,
        borderWidth: borderWidth,
        overlayColor: overlayColor,
      );
    }
  }
  