import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import '../gridscreen/amslergridScreen.dart';
import '../blinkdetection/blinkdetectionscreen.dart';

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            InkWell(
              onTap: () {
                Navigator.of(context).push(
                  MaterialPageRoute(builder: (context) => AmslerGridScreen())
                );
              },
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 60.0, vertical: 16.0),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(30.0),
                  border: Border.all(color: Colors.teal.shade200, width: 2),
                ),
                child: RichText(
                  text: const TextSpan(
                    children: [
                      TextSpan(
                        text: "Amsler Grid Test",
                        style: TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: 16,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
            SizedBox(height: 20),
            InkWell(
              onTap: () async {
                final cameras = await availableCameras();
                final firstCamera = cameras.first;
                Navigator.of(context).push(
                  MaterialPageRoute(
                    builder: (context) => BlinkDetectionScreen(camera: firstCamera)
                  )
                );
              },
              child: Container(
                padding: const EdgeInsets.symmetric(horizontal: 60.0, vertical: 16.0),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(30.0),
                  border: Border.all(color: Colors.teal.shade200, width: 2),
                ),
                child: RichText(
                  text: const TextSpan(
                    children: [
                      TextSpan(
                        text: "Blink Detection Test",
                        style: TextStyle(
                          color: Colors.black,
                          fontWeight: FontWeight.bold,
                          fontSize: 16,
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
//////////
import 'dart:ui';

import 'package:flutter/material.dart';
import 'dart:math';

class AmslerGridScreen extends StatefulWidget {
  const AmslerGridScreen({super.key});

  @override
  _AmslerGridScreenState createState() => _AmslerGridScreenState();
}

class _AmslerGridScreenState extends State<AmslerGridScreen> {
  // Variables for transformations
  double _scale = 1.0;
  late TransformationController _transformationController;
  TapDownDetails? _doubleTapDetails;

  // Variables for adjustable settings
  int _gridLines = 20;
  double _lineThickness = 1.0;
  Color _gridColor = Colors.black;
  Color _backgroundColor = Colors.white;
  bool _showCenterDot = true;

  // For contrast adjustment
  double _contrast = 1.0;

  // for Dot Radius Changes
  double _dotRadius = 4.0;

  // Variables for distortion effect
  double _distortionAmount = 50.0; // Range: 0.0 (minimum) to 100.0 (maximum), default is 50 (no distortion)
  double _darken = 1.0; // Range: 0.1 (darkest) to 1.0 (original color)

  @override
  void initState() {
    super.initState();
    _transformationController = TransformationController();
  }

  @override
  Widget build(BuildContext context) {
    // Get the screen size
    final screenSize = MediaQuery.of(context).size;

    // Determine if the device is a tablet based on screen width
    final bool isTablet = screenSize.shortestSide >= 600;

    // Calculate the desired margin based on the screen size
    final double marginWidth = screenSize.width * 0.04; // 4% of screen width as margin
    final double marginHeight = screenSize.height * 0.07; // 7% of screen height as margin

    return Scaffold(
      appBar: AppBar(
        title: const Text(
          'B+L Amsler Grid',
          style: TextStyle(
            color: Colors.teal,
            fontSize: 26,
          ),
        ),
        centerTitle: true,
        leading: IconButton(
          icon: const Icon(Icons.arrow_back_ios_new, color: Color.fromARGB(168, 21, 1, 1)),
          onPressed: () => Navigator.of(context).pop(),
        ),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _resetView,
            tooltip: 'Reset All',
          ),
          IconButton(
            icon: Icon(_showCenterDot ? Icons.visibility : Icons.visibility_off),
            onPressed: () {
              setState(() {
                _showCenterDot = !_showCenterDot;
              });
            },
            tooltip: 'Toggle Center Dot',
          ),
        ],
      ),
      body: isTablet
          ? Row(
              children: [
                // Grid on the left side
                Expanded(
                  flex: 2,
                  child: _buildGrid(marginWidth, marginHeight),
                ),
                // Controls on the right side
                Expanded(
                  child: _buildControls(),
                ),
              ],
            )
          : Column(
              children: [
                // Grid at the top on phones
                Expanded(
                  child: _buildGrid(marginWidth, marginHeight),
                ),
                // Controls at the bottom on phones
                _buildControls(),
              ],
            ),
    );
  }

  Widget _buildGrid(double marginWidth, double marginHeight) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return Container(
          color: _backgroundColor, // Apply the background color
          child: GestureDetector(
            onDoubleTapDown: (details) {
              _doubleTapDetails = details;
            },
            onDoubleTap: _handleDoubleTap,
            child: InteractiveViewer(
              transformationController: _transformationController,
              panEnabled: true,
              scaleEnabled: true,
              minScale: 1.0,
              maxScale: 5.0,
              onInteractionStart: (details) {
                // Store the focal point when interaction starts
                _doubleTapDetails = TapDownDetails(globalPosition: details.focalPoint);
              },
              onInteractionUpdate: (details) {
                // Update the scale while keeping the grid centered
                _onScaleChanged(details.scale);
              },
              child: CustomPaint(
                painter: BackgroundPaint(
                  marginWidth: marginWidth,
                  marginHeight: marginHeight,
                  gridLines: _gridLines,
                  lineThickness: _lineThickness,
                  gridColor: _gridColor,
                  backgroundColor: _backgroundColor,
                  showCenterDot: _showCenterDot,
                  contrast: _contrast,
                  distortionAmount: _distortionAmount,
                  darken: _darken,
                  dotRadius: _dotRadius
                ),
                size: Size.infinite,
              ),
            ),
          ),
        );
      },
    );
  }

  Widget _buildControls() {
    // Controls in a scrollable view
    return Container(
      color: Colors.grey[200],
      height: 470, // Adjust as needed
      child: SingleChildScrollView(
        child: Column(
          children: [
            // Zoom level slider
             const ListTile(
              title: Text('Amsler Grid Controls', style: TextStyle(fontSize: 25),), 
             ),
            ListTile(
              title: Text('Zoom Level: ${_scale.toStringAsFixed(1)}x'),
              subtitle: Slider(
                value: _scale,
                min: 1.0,
                max: 5.0,
                divisions: 40,
                label: 'Zoom',
                onChanged: (value) {
                  setState(() {
                    _scale = value;
                    _onScaleChanged(_scale);
                  });
                },
              ),
            ),
            // Grid size adjustment
            ListTile(
              title: Text('Grid Size: $_gridLines x $_gridLines'),
              subtitle: Slider(
                value: _gridLines.toDouble(),
                min: 10,
                max: 40,
                divisions: 30,
                label: 'Grid Lines',
                onChanged: (value) {
                  setState(() {
                    _gridLines = value.toInt();
                  });
                },
              ),
            ),
            // Line thickness adjustment
            ListTile(
              title: Text('Line Thickness: ${_lineThickness.toStringAsFixed(1)}'),
              subtitle: Slider(
                value: _lineThickness,
                min: 0.5,
                max: 5.0,
                divisions: 9,
                label: 'Line Thickness',
                onChanged: (value) {
                  setState(() {
                    _lineThickness = value;
                    _dotRadius = value * (value == 0.5 ? 7.0 : 4.0);
                  });
                },
              ),
            ),
            // Contrast adjustment
            // ListTile(
            //   title: Text('Contrast: ${(_contrast * 100).toInt()}%'),
            //   subtitle: Slider(
            //     value: _contrast,
            //     min: 0.1,
            //     max: 1.0,
            //     divisions: 9,
            //     label: 'Contrast',
            //     onChanged: (value) {
            //       setState(() {
            //         _contrast = value;
            //       });
            //     },
            //   ),
            // ),
            // Distortion amount adjustment
            ListTile(
              title: Text('Distortion Amount: ${_distortionAmount.toInt()}%'),
              subtitle: Slider(
                value: _distortionAmount,
                min: 0.0,
                max: 100.0,
                divisions: 100,
                label: 'Distortion Amount',
                onChanged: (value) {
                  setState(() {
                    _distortionAmount = value;
                  });
                },
              ),
            ),
            // // Darken adjustment
            // ListTile(
            //   title: Text('Darken: ${(_darken * 100).toInt()}%'),
            //   subtitle: Slider(
            //     value: _darken,
            //     min: 0.1,
            //     max: 1.0,
            //     divisions: 9,
            //     label: 'Darken',
            //     onChanged: (value) {
            //       setState(() {
            //         _darken = value;
            //       });
            //     },
            //   ),
            // ),
            // Color options for grid and background
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
              child: Row(
                children: [
                  const Text('Grid Color:'),
                  const SizedBox(width: 10),
                  DropdownButton<Color>(
                    value: _gridColor,
                    items: const [
                      DropdownMenuItem(
                        value: Colors.black,
                        child: Text('Black'),
                      ),
                      DropdownMenuItem(
                        value: Colors.white,
                        child: Text('White'),
                      ),
                    ],
                    onChanged: (value) {
                      setState(() {
                        _gridColor = value!;
                      });
                    },
                  ),
                  const SizedBox(width: 20),
                  const Text('Background Color:'),
                  const SizedBox(width: 10),
                  DropdownButton<Color>(
                    value: _backgroundColor,
                    items: const [
                      DropdownMenuItem(
                        value: Colors.white,
                        child: Text('White'),
                      ),
                      DropdownMenuItem(
                        value: Colors.black,
                        child: Text('Black'),
                      ),
                    ],
                    onChanged: (value) {
                      setState(() {
                        _backgroundColor = value!;
                      });
                    },
                  ),
                ],
              ),
            ),
            const SizedBox(height: 10),
          ],
        ),
      ),
    );
  }

  void _resetView() {
    setState(() {
      _scale = 1.0;
      _transformationController.value = Matrix4.identity();

      // Reset other variables to default values
      _gridLines = 20;
      _lineThickness = 1.0;
      _gridColor = Colors.black;
      _backgroundColor = Colors.white;
      _showCenterDot = true;
      _contrast = 1.0;
      _distortionAmount = 50.0; // default to 50 (no distortion)
      _darken = 1.0;
      _dotRadius = 4.0;
    });
  }

  void _handleDoubleTap() {
    if (_doubleTapDetails != null) {
      final position = _doubleTapDetails!.localPosition;
      // Zoom in or out on double tap
      setState(() {
        if (_scale == 1.0) {
          _scale = 2.0;
        } else {
          _scale = 1.0;
        }
        _onScaleChanged(_scale);
      });
    }
  }

  void _onScaleChanged(double scale) {
    final matrix = Matrix4.identity();
    matrix.translate(
      (1 - scale) * MediaQuery.of(context).size.width / 2,
      (1 - scale) * MediaQuery.of(context).size.height / 2,
    );
    matrix.scale(scale);
    _transformationController.value = matrix;
  }
}

class BackgroundPaint extends CustomPainter {
  final double marginWidth;
  final double marginHeight;
  final int gridLines;
  final double lineThickness;
  final Color gridColor;
  final Color backgroundColor;
  final bool showCenterDot;
  final double contrast;
  final double distortionAmount;
  final double darken;
  final double dotRadius;

  BackgroundPaint({
    required this.marginWidth,
    required this.marginHeight,
    required this.gridLines,
    required this.lineThickness,
    required this.gridColor,
    required this.backgroundColor,
    required this.showCenterDot,
    required this.contrast,
    required this.distortionAmount,
    required this.darken,
    required this.dotRadius,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // Apply background color
    final bgPaint = Paint()..color = backgroundColor;
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), bgPaint);

    // Adjust grid color for contrast and darken
    Color adjustedGridColor = gridColor.withOpacity(contrast.clamp(0.1, 1.0) * darken);

    final paint = Paint()
      ..color = adjustedGridColor
      ..strokeWidth = lineThickness;

    // Calculates the size of each grid box based on the smaller dimension
    final availableWidth = size.width - marginWidth * 2;
    final availableHeight = size.height - marginHeight * 2;
    final gridSize =
        (availableWidth < availableHeight ? availableWidth : availableHeight) / gridLines;

    final adjustedSize = Size(gridSize * gridLines, gridSize * gridLines);

    // Center the grid
    final dx = (size.width - adjustedSize.width) / 2;
    final dy = (size.height - adjustedSize.height) / 2;
    canvas.translate(dx, dy);

    // Center of the grid for distortion calculations
    final Offset center = Offset(adjustedSize.width / 2, adjustedSize.height / 2);

    // Maximum radius from the center to the corner
    final double maxRadius = center.distance;

    // Function to apply 3D-like distortion to a point
    Offset distortPoint(Offset point) {
      final dx = point.dx - center.dx;
      final dy = point.dy - center.dy;
      final double r = sqrt(dx * dx + dy * dy);

      // Compute effective distortion amount from -1 to 1
      double effectiveDistortion = (distortionAmount - 50) / 50.0;

      // Scale the distortion amount
      double distortionStrength = effectiveDistortion * 1.5; // Adjust strength as needed

      // Apply a smooth distortion function
      // Create a 3D-like effect using a paraboloid function
      double z = distortionStrength * (1 - (r / maxRadius) * (r / maxRadius));

      // Perspective projection parameters
      double d = 500.0; // Distance from the viewer to the grid (adjust as needed)

      // Project the 3D point back to 2D
      double scale = d / (d - z * 100); // Adjust z scaling as needed

      double distortedX = center.dx + dx * scale;
      double distortedY = center.dy + dy * scale;

      return Offset(distortedX, distortedY);
    }

    // Draw the distorted vertical lines
    for (int i = 0; i <= gridLines; i++) {
      List<Offset> points = [];
      for (int j = 0; j <= gridLines; j++) {
        final point = Offset(i * gridSize, j * gridSize);
        final distortedPoint = distortPoint(point);
        points.add(distortedPoint);
      }
      canvas.drawPoints(PointMode.polygon, points, paint);
    }

    // Draw the distorted horizontal lines
    for (int j = 0; j <= gridLines; j++) {
      List<Offset> points = [];
      for (int i = 0; i <= gridLines; i++) {
        final point = Offset(i * gridSize, j * gridSize);
        final distortedPoint = distortPoint(point);
        points.add(distortedPoint);
      }
      canvas.drawPoints(PointMode.polygon, points, paint);
    }

    // Draw the center dot
    if (showCenterDot) {
      final centerDotPaint = Paint()
        ..color = adjustedGridColor
        ..style = PaintingStyle.fill;

      // dotRadius = 4.0;

      // Apply distortion to center point if distortion is present
      final distortedCenter = distortionAmount != 50.0 ? distortPoint(center) : center;

      canvas.drawCircle(distortedCenter, dotRadius, centerDotPaint);
    }
  }

  @override
  bool shouldRepaint(covariant BackgroundPaint oldDelegate) {
    return oldDelegate.gridLines != gridLines ||
        oldDelegate.lineThickness != lineThickness ||
        oldDelegate.gridColor != gridColor ||
        oldDelegate.backgroundColor != backgroundColor ||
        oldDelegate.showCenterDot != showCenterDot ||
        oldDelegate.contrast != contrast ||
        oldDelegate.distortionAmount != distortionAmount ||
        oldDelegate.darken != darken;
  }
}//////////////////
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:google_mlkit_face_detection/google_mlkit_face_detection.dart';
import 'dart:math';

class BlinkDetectionScreen extends StatefulWidget {
  final CameraDescription camera;

  const BlinkDetectionScreen({Key? key, required this.camera}) : super(key: key);

  @override
  BlinkDetectionScreenState createState() => BlinkDetectionScreenState();
}

class BlinkDetectionScreenState extends State<BlinkDetectionScreen> {
  late CameraController _controller;
  late Future<void> _initializeControllerFuture;
  late FaceDetector _faceDetector;
  int _blinkCount = 0;
  double _lastEAR = 0;
  final double _blinkThreshold = 0.2;
  bool _isDetecting = false;

  @override
  void initState() {
    super.initState();
    _controller = CameraController(
      widget.camera,
      ResolutionPreset.medium,
    );
    _initializeControllerFuture = _controller.initialize();

    final options = FaceDetectorOptions(
      performanceMode: FaceDetectorMode.accurate,
      enableLandmarks: true,
      enableContours: true,
      enableClassification: true,
    );
    _faceDetector = FaceDetector(options: options);
  }

  @override
  void dispose() {
    _controller.dispose();
    _faceDetector.close();
    super.dispose();
  }

  void _processCameraImage(CameraImage image) async {
    if (_isDetecting) return;
    _isDetecting = true;

    final inputImage = InputImage.fromBytes(
      bytes: image.planes[0].bytes!,
      metadata: InputImageMetadata(
        size: Size(image.width.toDouble(), image.height.toDouble()),
        rotation: InputImageRotation.rotation0deg,
        format: InputImageFormat.nv21,
        bytesPerRow: image.planes[0].bytesPerRow,
      ),
    );

    final faces = await _faceDetector.processImage(inputImage);

    if (faces.isNotEmpty) {
      final face = faces[0];
      if (face.landmarks[FaceLandmarkType.leftEye] != null &&
          face.landmarks[FaceLandmarkType.rightEye] != null) {
        final leftEyeEAR = _calculateEAR([
          face.landmarks[FaceLandmarkType.leftEye]!.position.x.toDouble(),
          face.landmarks[FaceLandmarkType.leftEye]!.position.y.toDouble(),
          face.landmarks[FaceLandmarkType.rightEye]!.position.x.toDouble(),
          face.landmarks[FaceLandmarkType.rightEye]!.position.y.toDouble(),
        ]);
        final rightEyeEAR = _calculateEAR([
          face.landmarks[FaceLandmarkType.rightEye]!.position.x.toDouble(),
          face.landmarks[FaceLandmarkType.rightEye]!.position.y.toDouble(),
          face.landmarks[FaceLandmarkType.leftEye]!.position.x.toDouble(),
          face.landmarks[FaceLandmarkType.leftEye]!.position.y.toDouble(),
        ]);

        final averageEAR = (leftEyeEAR + rightEyeEAR) / 2;

        if (averageEAR < _blinkThreshold && _lastEAR >= _blinkThreshold) {
          setState(() {
            _blinkCount++;
          });
        }
        _lastEAR = averageEAR;
      }
    }

    _isDetecting = false;
  }

  double _calculateEAR(List<double> eyePoints) {
    final p2 = Offset(eyePoints[0], eyePoints[1]);
    final p6 = Offset(eyePoints[2], eyePoints[3]);
    // Approximating other points
    final p3 = Offset(eyePoints[0], eyePoints[1] + (eyePoints[3] - eyePoints[1]) / 3);
    final p5 = Offset(eyePoints[2], eyePoints[1] + (eyePoints[3] - eyePoints[1]) * 2 / 3);
    final p1 = Offset(eyePoints[0] + (eyePoints[2] - eyePoints[0]) / 2, eyePoints[1]);
    final p4 = Offset(eyePoints[0] + (eyePoints[2] - eyePoints[0]) / 2, eyePoints[3]);

    final p2p6 = _distance(p2, p6);
    final p3p5 = _distance(p3, p5);
    final p1p4 = _distance(p1, p4);

    return (p2p6 + p3p5) / (2.0 * p1p4);
  }

  double _distance(Offset p1, Offset p2) {
    return sqrt(pow(p1.dx - p2.dx, 2) + pow(p1.dy - p2.dy, 2));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Blink Detection')),
      body: FutureBuilder<void>(
        future: _initializeControllerFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            return Stack(
              fit: StackFit.expand,
              children: <Widget>[
                CameraPreview(_controller),
                Positioned(
                  top: 20,
                  left: 20,
                  child: Container(
                    padding: EdgeInsets.all(10),
                    decoration: BoxDecoration(
                      color: Colors.black54,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: Text(
                      'Blinks: $_blinkCount',
                      style: TextStyle(
                        fontSize: 20,
                        color: Colors.white,
                      ),
                    ),
                  ),
                ),
              ],
            );
          } else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          try {
            await _initializeControllerFuture;
            _controller.startImageStream(_processCameraImage);
          } catch (e) {
            print(e);
          }
        },
        child: Icon(Icons.play_arrow),
      ),
    );
  }
}
i ahve sent u teh code, now wrtie teh test cases from teh tester prespective, in the below i also shared the sample of teh tester method, do it like this

S No	Subject	Test case ID	Requirement ID	Scenario Name	Test Name	Test Case Description	Step Number	Detailed Steps	Expected Result	Actual Result	Test Status		Test Date	Tester's Name	"TC Criticality
[High / Medium/ Low]"
Test ID	QC Path	Test case ID	Requirement ID	Test folder Name	Test Name	Description	1, 2, 3 etc.	 Design Steps	Expected Result	Actual Result	Pass	Fail			TC Priority
1		TC_1			"INFUSE-FA Drawer-1 
Testing"	"Testing Drawer-1 
with power -0.75 
in Brand INFUSE with Indication FA"	1	Open Application 			Passed				
							2	Select Customer 	[Type in Customer Selected]						
							3	"Select Brand: INFUSE
Select Indication: FA
Select Drawer: -0.75 CYL 10, 80, 90"	"Select Brand: INFUSE-FA
Select Indication: "						
							4	Select uppermost left(non empty)slot in  Drawer							
							5	Select lowest right (non empty) Slot							
							6	Click on cart in upper right hand view							
							7	"Two lenses  should show in cart and be highlighted with yellow color in drawer: with power lens as 

+2.00
+1.50

"	"Two lenses  should show in cart and be highlighted with yellow color in drawer: with power lens as 

+2.00
+1.50

"						
							8	Select Proceed and submit Cart	Receive confirmation that cart is submitted.						
							9	Download FlatFile for customer from AWS bucket							
							10	Open FlatFile							
							11	SKU line 2	196527098191						
							12	SKU line 3	196527097590						
							14	Matching Y/N	Matched with SKUs selected to SKUs inline with CSV files						
															
Random-2							1	Open Application 							
							2	Select Customer 	[Type in Customer Selected]						
		INFUSE-FA -0.75 				INFUSE-FA Drawer-2	3	"Select Brand: INFUSE-FA
Select Indication: 
Select Drawer: "	"Select Brand: INFUSE-FA
Select Indication: "						
							4	Select Down try from Top left(non empty)slot in  Drawer							
							5	Select lowest right (non empty) Slot							
							6	Click on cart in upper right hand view							
							7	"Two lenses should show in cart and be highlighted in drawer:

+2.00
+1.50

"	"Two lenses should show in cart and be highlighted in drawer:

+2.00
+1.50
"						
							8	Select Proceed and submit Cart	Receive confirmation that cart is submitted.						
							9	Download FlatFile for customer from AWS bucket							
							10	Open FlatFile							
							11	SKU line 2	196527098221