You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<double>? radiusKmListenable;
const ServiceLocationsRadiusScreen({
Key? key,
this.initialPosition,
this.radiusKmListenable,
}) : super(key: key);
@override
State<ServiceLocationsRadiusScreen> createState() =>
_ServiceLocationsRadiusScreenState();
}
class _ServiceLocationsRadiusScreenState
extends State<ServiceLocationsRadiusScreen> {
GoogleMapController? _controller;
LatLng? _currentPosition;
LatLng? _circleCenter;
bool _isMapReady = false;
Set<Circle> _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<void> _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 (200300 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);
},
);
}
}