the grid should be stable without moving anywhere at zooming, and if the the device is phone then its ok , if teh device is tab then place the scroll rightside and grid left side

import 'package:flutter/material.dart';
import 'dart:math'; // Import for mathematical functions

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;

  // Variables for distortion effect
  double _distortionAmount = 0.0; // Range: 0.0 (no distortion) to 1.0 (maximum 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;
    // 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 View',
          ),
          IconButton(
            icon: Icon(_showCenterDot ? Icons.visibility : Icons.visibility_off),
            onPressed: () {
              setState(() {
                _showCenterDot = !_showCenterDot;
              });
            },
            tooltip: 'Toggle Center Dot',
          ),
        ],
      ),
      body: Column(
        children: [
          // Expanded widget for the grid to take maximum space at the top
          Expanded(
            child: 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,
                  child: CustomPaint(
                    painter: BackgroundPaint(
                      marginWidth: marginWidth,
                      marginHeight: marginHeight,
                      gridLines: _gridLines,
                      lineThickness: _lineThickness,
                      gridColor: _gridColor,
                      backgroundColor: _backgroundColor,
                      showCenterDot: _showCenterDot,
                      contrast: _contrast,
                      distortionAmount: _distortionAmount,
                      darken: _darken,
                    ),
                    size: Size.infinite,
                  ),
                ),
              ),
            ),
          ),
          // Controls at the bottom in a scrollable view
          Container(
            color: Colors.grey[200],
            height: 370, // Adjusted height to accommodate additional sliders
            child: SingleChildScrollView(
              child: Column(
                children: [
                  // Zoom level slider
                  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;
                          _transformationController.value = Matrix4.identity()..scale(_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;
                        });
                      },
                    ),
                  ),
                  // 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 * 100).toInt()}%'),
                    subtitle: Slider(
                      value: _distortionAmount,
                      min: 0.0,
                      max: 1.0,
                      divisions: 20,
                      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: [
                            DropdownMenuItem(
                              value: Colors.black,
                              child: const Text('Black'),
                            ),
                            DropdownMenuItem(
                              value: Colors.white,
                              child: const Text('White'),
                            ),
                          ],
                          onChanged: (value) {
                            setState(() {
                              _gridColor = value!;
                            });
                          },
                        ),
                        const SizedBox(width: 20),
                        const Text('Background Color:'),
                        const SizedBox(width: 10),
                        DropdownButton<Color>(
                          value: _backgroundColor,
                          items: [
                            DropdownMenuItem(
                              value: Colors.white,
                              child: const Text('White'),
                            ),
                            DropdownMenuItem(
                              value: Colors.black,
                              child: const Text('Black'),
                            ),
                          ],
                          onChanged: (value) {
                            setState(() {
                              _backgroundColor = value!;
                            });
                          },
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(height: 10),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

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

  void _handleDoubleTap() {
    if (_doubleTapDetails != null) {
      final position = _doubleTapDetails!.localPosition;
      // Zoom in or out on double tap
      if (_scale == 1.0) {
        _scale = 2.0;
      } else {
        _scale = 1.0;
      }
      _transformationController.value = Matrix4.identity()
        ..translate(-position.dx * (_scale - 1), -position.dy * (_scale - 1))
        ..scale(_scale);
      setState(() {});
    }
  }
}

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;

  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,
  });

  @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);

    // Function to apply distortion to a point
    Offset distortPoint(Offset point) {
      final dx = point.dx - center.dx;
      final dy = point.dy - center.dy;
      final distance = sqrt(dx * dx + dy * dy);
      final angle = atan2(dy, dx);
      // Distortion amount based on the distance from the center
      final distortion = distortionAmount * 50 * sin(distance / 50);
      final distortedDistance = distance + distortion;
      final distortedX = center.dx + distortedDistance * cos(angle);
      final distortedY = center.dy + distortedDistance * sin(angle);
      return Offset(distortedX, distortedY);
    }

    // Draw the distorted vertical lines
    for (int i = 0; i <= gridLines; i++) {
      final start = Offset(i * gridSize, 0);
      final end = Offset(i * gridSize, adjustedSize.height);

      final distortedStart = distortPoint(start);
      final distortedEnd = distortPoint(end);

      canvas.drawLine(
        distortedStart,
        distortedEnd,
        paint,
      );
    }

    // Draw the distorted horizontal lines
    for (int i = 0; i <= gridLines; i++) {
      final start = Offset(0, i * gridSize);
      final end = Offset(adjustedSize.width, i * gridSize);

      final distortedStart = distortPoint(start);
      final distortedEnd = distortPoint(end);

      canvas.drawLine(
        distortedStart,
        distortedEnd,
        paint,
      );
    }

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

      final dotRadius = 4.0;

      // Apply distortion to center point if distortion is present
      final distortedCenter = distortionAmount > 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;
  }
}