import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:permission_handler/permission_handler.dart'; class ServiceLocationsRadiusScreen extends StatefulWidget { final LatLng? initialPosition; final ValueListenable? radiusKmListenable; const ServiceLocationsRadiusScreen({ Key? key, this.initialPosition, this.radiusKmListenable, }) : super(key: key); @override State createState() => _ServiceLocationsRadiusScreenState(); } class _ServiceLocationsRadiusScreenState extends State { GoogleMapController? _controller; LatLng? _currentPosition; LatLng? _circleCenter; bool _isMapReady = false; Set _circles = {}; final double _fallbackRadiusMeters = 10000; // 10 km final LatLng _indiaCenter = const LatLng(20.5937, 78.9629); @override void initState() { super.initState(); if (widget.initialPosition == null) { _checkLocationPermissionAndGetCurrentPosition(); } else { _circleCenter = widget.initialPosition; } widget.radiusKmListenable?.addListener(_onRadiusChangedFromParent); } @override void dispose() { widget.radiusKmListenable?.removeListener(_onRadiusChangedFromParent); super.dispose(); } // 🔹 When radius changes in parent void _onRadiusChangedFromParent() { final km = widget.radiusKmListenable?.value ?? (_fallbackRadiusMeters / 1000.0); final meters = km * 1000.0; final center = _circleCenter ?? _currentPosition ?? _indiaCenter; _addRadiusCircle(center, radiusInMeters: meters); } // 🔹 Get current location Future _checkLocationPermissionAndGetCurrentPosition() async { var status = await Permission.location.status; if (!status.isGranted) { status = await Permission.location.request(); if (!status.isGranted) return; } bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); if (!serviceEnabled) return; final position = await Geolocator.getCurrentPosition(); setState(() { _currentPosition = LatLng(position.latitude, position.longitude); }); } // 🔹 Add / update the circle void _addRadiusCircle(LatLng center, {double? radiusInMeters}) async { final meters = radiusInMeters ?? (widget.radiusKmListenable?.value ?? (_fallbackRadiusMeters / 1000.0)) * 1000.0; setState(() { _circleCenter = center; _circles = { Circle( circleId: const CircleId("radius_circle"), center: center, radius: meters, fillColor: Colors.blue.withOpacity(0.2), strokeColor: Colors.blueAccent, strokeWidth: 2, ), }; }); // 👇 adjust zoom so full circle is visible even in small container if (_controller != null) { final zoom = _getZoomLevelForSmallMap(meters); await _controller!.animateCamera( CameraUpdate.newCameraPosition( CameraPosition(target: center, zoom: zoom), ), ); } } // 🔹 Calculate zoom for small map container (200–300 px) double _getZoomLevelForSmallMap(double radiusMeters) { // Adjust constant here if map size differs final scale = radiusMeters / 200; // Smaller scale for small map double zoomLevel = 16 - log(scale) / log(2); if (zoomLevel > 18) zoomLevel = 18; if (zoomLevel < 4) zoomLevel = 4; return zoomLevel; } @override Widget build(BuildContext context) { final LatLng target = widget.initialPosition ?? _currentPosition ?? _indiaCenter; final initialCameraPosition = CameraPosition( target: target, zoom: 12, ); return GoogleMap( initialCameraPosition: initialCameraPosition, mapType: MapType.normal, circles: _circles, zoomControlsEnabled: false, myLocationEnabled: false, myLocationButtonEnabled: false, onMapCreated: (controller) async { _controller = controller; _isMapReady = true; await Future.delayed(const Duration(milliseconds: 500)); final center = widget.initialPosition ?? _currentPosition ?? _indiaCenter; final km = widget.radiusKmListenable?.value ?? 10; _addRadiusCircle(center, radiusInMeters: km * 1000.0); }, ); } }