diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000..7ec5719 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000..42c9a9a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000..4403599 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000..0998d4a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000..8de127f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000..80fa488 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/ios/Runner/Resources/InfoPlist.strings b/ios/Runner/Resources/InfoPlist.strings new file mode 100644 index 0000000..8a0f810 --- /dev/null +++ b/ios/Runner/Resources/InfoPlist.strings @@ -0,0 +1 @@ +"CFBundleDisplayName" = "Aquick Supplier"; \ No newline at end of file diff --git a/lib/profile/service_location.dart b/lib/profile/service_location.dart index deb10f8..5dd2703 100644 --- a/lib/profile/service_location.dart +++ b/lib/profile/service_location.dart @@ -1,6 +1,8 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:supplier_new/common/settings.dart'; +import 'package:supplier_new/profile/service_locations_radius.dart'; import '../resources/source_loctaions_model.dart'; void main() => runApp(const MaterialApp(home: ServiceLocation())); @@ -15,13 +17,14 @@ class ServiceLocation extends StatefulWidget { class _ServiceLocationState extends State { final _formKey = GlobalKey(); String _deliveryFrom = 'business'; - final TextEditingController _radiusController = - TextEditingController(text: "10"); + final TextEditingController _radiusController = TextEditingController(text: "10"); bool _customizeEachSource = false; bool isLoading = false; int currentStep = 3; List sourceLocationsList = []; + // 🔹 Notifier for dynamic map radius + late final ValueNotifier _radiusKmNotifier; final List _services = [ "24/7 Emergency services", @@ -32,15 +35,31 @@ class _ServiceLocationState extends State { ]; final Set _selectedServices = {}; - final Map _expandedMap = {}; @override void initState() { super.initState(); + _radiusKmNotifier = ValueNotifier( + double.tryParse(_radiusController.text) ?? 10, + ); + + // 🔹 Listen to radius text changes + _radiusController.addListener(() { + final v = double.tryParse(_radiusController.text); + _radiusKmNotifier.value = (v == null || v.isNaN || v <= 0) ? 10 : v; + }); + _fetchSources(); } + @override + void dispose() { + _radiusController.dispose(); + _radiusKmNotifier.dispose(); + super.dispose(); + } + Future _fetchSources() async { setState(() => isLoading = true); try { @@ -76,290 +95,336 @@ class _ServiceLocationState extends State { child: isLoading ? const Center(child: CircularProgressIndicator()) : Form( - key: _formKey, - child: ListView( - padding: const EdgeInsets.fromLTRB(20, 10, 20, 24), - children: [ - Text("Step $currentStep/5", - style: fontTextStyle(16, Color(0xFFC3C4C4), FontWeight.w500)), - const SizedBox(height: 16), - Row( - children: List.generate(5, (index) { - final isFilled = index < currentStep; - return Expanded( - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 2), - height: 5, - decoration: BoxDecoration( - color: isFilled - ? const Color(0xFF0D3771) - : const Color(0xFFE6E6E6), - borderRadius: BorderRadius.circular(2), - ), - ), - ); - }), + key: _formKey, + child: ListView( + padding: const EdgeInsets.fromLTRB(20, 10, 20, 24), + children: [ + Text("Step $currentStep/5", + style: fontTextStyle( + 16, const Color(0xFFC3C4C4), FontWeight.w500)), + const SizedBox(height: 16), + Row( + children: List.generate(5, (index) { + final isFilled = index < currentStep; + return Expanded( + child: Container( + margin: const EdgeInsets.symmetric(horizontal: 2), + height: 5, + decoration: BoxDecoration( + color: isFilled + ? const Color(0xFF0D3771) + : const Color(0xFFE6E6E6), + borderRadius: BorderRadius.circular(2), + ), ), + ); + }), + ), - const SizedBox(height: 16), + const SizedBox(height: 16), + + Text("SERVICE LOCATIONS", + style: fontTextStyle( + 20, const Color(0xFF515253), FontWeight.w600)), + const SizedBox(height: 16), + Align( + alignment: Alignment.centerLeft, + child: Image.asset('images/marker-pin.png', + width: 24, height: 24), + ), + const SizedBox(height: 16), + Text( + "Define where you want to provide delivery services", + style: fontTextStyle( + 14, const Color(0xFF939495), FontWeight.w500), + ), + const SizedBox(height: 16), - Text("SERVICE LOCATIONS", - style: fontTextStyle(20, Color(0xFF515253), FontWeight.w600)), + RadioListTile( + value: 'business', + groupValue: _deliveryFrom, + onChanged: (value) => + setState(() => _deliveryFrom = value ?? 'business'), + title: Text("From Business Location", + style: fontTextStyle( + 12, const Color(0xFF2D2E30), FontWeight.w400)), + dense: true, + contentPadding: EdgeInsets.zero, + visualDensity: + const VisualDensity(horizontal: 0, vertical: -3), + ), + RadioListTile( + value: 'source', + groupValue: _deliveryFrom, + onChanged: (value) => + setState(() => _deliveryFrom = value ?? 'source'), + title: Text("From Source Locations", + style: fontTextStyle( + 12, const Color(0xFF2D2E30), FontWeight.w400)), + dense: true, + contentPadding: EdgeInsets.zero, + visualDensity: + const VisualDensity(horizontal: 0, vertical: -3), + ), + + const SizedBox(height: 16), + + // 🔹 BUSINESS LOCATION SECTION + Visibility( + visible: _deliveryFrom == 'business', + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Delivery Radius (in Kms) *", + style: fontTextStyle( + 12, const Color(0xFF2F3036), FontWeight.w600)), const SizedBox(height: 16), - Align( - alignment: Alignment.centerLeft, - child: Image.asset('images/marker-pin.png', - width: 24, height: 24), + TextFormField( + controller: _radiusController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: "Enter radius in kms", + hintStyle: fontTextStyle( + 14, const Color(0xFF939495), FontWeight.w400), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 12), + ), ), const SizedBox(height: 16), - Text( - "Define where you want to provide delivery services", - style: fontTextStyle(14, Color(0xFF939495), FontWeight.w500), + Container( + width: double.infinity, + height: 220, // 👈 small map fits neatly + decoration: BoxDecoration( + border: Border.all(color: const Color(0xFFE6E6E6)), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: ServiceLocationsRadiusScreen( + initialPosition: const LatLng(17.381597, 78.481791), + radiusKmListenable: _radiusKmNotifier, + ), + ), ), - const SizedBox(height: 16), + ], + ), + ), - RadioListTile( - value: 'business', - groupValue: _deliveryFrom, - onChanged: (value) => - setState(() => _deliveryFrom = value ?? 'business'), - title: Text("From Business Location", - style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400)), - dense: true, - contentPadding: EdgeInsets.zero, - visualDensity: - const VisualDensity(horizontal: 0, vertical: -3), - ), - RadioListTile( - value: 'source', - groupValue: _deliveryFrom, - onChanged: (value) => - setState(() => _deliveryFrom = value ?? 'source'), - title: Text("From Source Locations", - style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400)), - dense: true, - contentPadding: EdgeInsets.zero, - visualDensity: - const VisualDensity(horizontal: 0, vertical: -3), + // 🔹 SOURCE LOCATIONS SECTION + Visibility( + visible: _deliveryFrom == 'source', + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Delivery Radius (in Kms) *", + style: fontTextStyle( + 12, const Color(0xFF2F3036), FontWeight.w600)), + const SizedBox(height: 16), + TextFormField( + controller: _radiusController, + keyboardType: TextInputType.number, + decoration: InputDecoration( + hintText: "Enter radius in kms", + hintStyle: fontTextStyle( + 14, const Color(0xFF939495), FontWeight.w400), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12, vertical: 12), + ), ), - const SizedBox(height: 16), - - - Visibility( - visible: _deliveryFrom == 'business', - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Delivery Radius (in Kms) *", - style: fontTextStyle(12, Color(0xFF2F3036), FontWeight.w600)), - const SizedBox(height: 16), - TextFormField( - controller: _radiusController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - hintText: "Enter radius in kms", - hintStyle: fontTextStyle(14, Color(0xFF939495), FontWeight.w400), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 12), - ), - ), - const SizedBox(height: 16), - Container( - width: double.infinity, - height: 160, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('images/google_maps.png'), - fit: BoxFit.contain, - ), - ), + Row( + children: [ + Checkbox( + value: _customizeEachSource, + onChanged: (val) => setState( + () => _customizeEachSource = val ?? false), + materialTapTargetSize: + MaterialTapTargetSize.shrinkWrap, + visualDensity: const VisualDensity( + horizontal: -4, vertical: -4), + ), + const SizedBox(width: 6), + Expanded( + child: Text( + "Customize for each source location", + style: fontTextStyle( + 12, const Color(0xFF2D2E30), + FontWeight.w400), ), - ], - ), + ), + ], ), + const SizedBox(height: 12), - // ✅ Source Location Customization Section - Visibility( - visible: _deliveryFrom == 'source', - child: Column( - + // 🔹 Show source list if enabled + if (_customizeEachSource) + Column( crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Delivery Radius (in Kms) *", - style: fontTextStyle(12, Color(0xFF2F3036), FontWeight.w600)), - const SizedBox(height: 16), - TextFormField( - controller: _radiusController, - keyboardType: TextInputType.number, - decoration: InputDecoration( - hintText: "Enter radius in kms", - hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, vertical: 12), - ), - ), - const SizedBox(height: 16), - Row( - children: [ - Checkbox( - value: _customizeEachSource, - onChanged: (val) => setState( - () => _customizeEachSource = val ?? false), - materialTapTargetSize: - MaterialTapTargetSize.shrinkWrap, - visualDensity: const VisualDensity( - horizontal: -4, vertical: -4), - ), - const SizedBox(width: 6), + children: sourceLocationsList.isEmpty + ? [ + const Text( + "No source locations available"), + ] + : List.generate(sourceLocationsList.length, + (index) { + final d = sourceLocationsList[index]; + final isExpanded = + _expandedMap[index] ?? false; - Expanded( - child: Text( - "Customize for each source location", - style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400), + return Container( + margin: + const EdgeInsets.only(bottom: 8), + decoration: BoxDecoration( + color: const Color(0xFFF7F7F7), + border: Border.all( + color: + const Color(0xFFE5E5E5)), + borderRadius: + BorderRadius.circular(12), ), - ), - ], - ), - const SizedBox(height: 12), - - // 🔹 Show all source locations when checkbox checked - if (_customizeEachSource) - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: sourceLocationsList.isEmpty - ? [ - const Text("No source locations available"), - ] - : List.generate(sourceLocationsList.length, (index) { - final d = sourceLocationsList[index]; - return StatefulBuilder( - builder: (context, setInner) { - // ✅ Always read from map dynamically (not fixed final variable) - final isExpanded = _expandedMap[index] ?? false; - - return Container( - margin: const EdgeInsets.only(bottom: 8), - decoration: BoxDecoration( - color: const Color(0xFFF7F7F7), - border: Border.all(color: const Color(0xFFE5E5E5)), - borderRadius: BorderRadius.circular(12), + child: Column( + children: [ + ListTile( + dense: true, + contentPadding: + EdgeInsets.zero, + minVerticalPadding: 0, + visualDensity: + const VisualDensity( + vertical: -4, + horizontal: 0), + title: Text( + d.source_name ?? + 'Unnamed location', + style: fontTextStyle( + 14, + const Color(0xFF2D2E30), + FontWeight.w600), ), - child: Column( - children: [ - ListTile( - dense: true, - contentPadding: EdgeInsets.zero, - minVerticalPadding: 0, - visualDensity: const VisualDensity(vertical: -4, horizontal: 0), - title: Text( - d.source_name ?? 'Unnamed location', - style: fontTextStyle(14, const Color(0xFF2D2E30), FontWeight.w600), - ), - trailing: IconButton( - icon: Image.asset( - isExpanded - ? 'images/arrow-up.png' - : 'images/downarrow.png', - width: 18, - height: 18, - ), - onPressed: () { - setInner(() { - _expandedMap[index] = !isExpanded; - }); - }, - ), - ), - if (isExpanded) - Container( - margin: const EdgeInsets.only(left: 10, right: 10, bottom: 6), - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(8), - border: Border.all(color: const Color(0xFFE5E5E5)), - ), - child: Text( - "Address: ${d.address ?? 'N/A'}", - style: fontTextStyle(12, const Color(0xFF646566), FontWeight.w400), - ), - ), - ], + trailing: IconButton( + icon: Image.asset( + isExpanded + ? 'images/arrow-up.png' + : 'images/downarrow.png', + width: 18, + height: 18, + ), + onPressed: () { + setState(() { + _expandedMap[index] = + !isExpanded; + }); + }, ), - ); - }, - ); - }), - ), - - const SizedBox(height: 16), - Container( - width: double.infinity, - height: 160, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('images/google_maps.png'), - fit: BoxFit.contain, - ), - ), - ), - ], + ), + if (isExpanded) + Container( + margin: + const EdgeInsets.only( + left: 10, + right: 10, + bottom: 6), + padding: + const EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: + BorderRadius.circular( + 8), + border: Border.all( + color: + const Color( + 0xFFE5E5E5)), + ), + child: Text( + "Address: ${d.address ?? 'N/A'}", + style: fontTextStyle( + 12, + const Color( + 0xFF646566), + FontWeight.w400), + ), + ), + ], + ), + ); + }), ), - ), - - const SizedBox(height: 24), - Text("Types of Services", - style: fontTextStyle(16, Color(0xFF2D2E30), FontWeight.w600)), - const SizedBox(height: 12), - Text( - "Define what type of services you would wish to provide", - style: fontTextStyle(14, Color(0xFF939495), FontWeight.w500)), const SizedBox(height: 16), - ..._services - .map((service) => _serviceItem(service)) - .toList(), - const SizedBox(height: 24), - SizedBox( + Container( width: double.infinity, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xFF8270DB), - foregroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(24)), + height: 250, + decoration: BoxDecoration( + border: + Border.all(color: const Color(0xFFE6E6E6)), + borderRadius: BorderRadius.circular(8), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: ServiceLocationsRadiusScreen( + initialPosition: + const LatLng(20.5937, 78.9629), + radiusKmListenable: _radiusKmNotifier, ), - onPressed: () { - final selected = _selectedServices.isEmpty - ? "No services selected" - : _selectedServices.join(", "); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - "Saved successfully for ${_deliveryFrom == 'business' ? 'Business Location' : 'Source Locations'}\nSelected: $selected"), - ), - ); - }, - child: Text("Save & Continue", - style: fontTextStyle(14, Color(0xFFFFFFFF), FontWeight.w400)), ), ), ], ), ), + + const SizedBox(height: 24), + Text("Types of Services", + style: fontTextStyle( + 16, const Color(0xFF2D2E30), FontWeight.w600)), + const SizedBox(height: 12), + Text("Define what type of services you would wish to provide", + style: fontTextStyle( + 14, const Color(0xFF939495), FontWeight.w500)), + + const SizedBox(height: 16), + ..._services.map((service) => _serviceItem(service)).toList(), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8270DB), + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24)), + ), + onPressed: () { + final selected = _selectedServices.isEmpty + ? "No services selected" + : _selectedServices.join(", "); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Saved successfully for ${_deliveryFrom == 'business' ? 'Business Location' : 'Source Locations'}\nSelected: $selected"), + ), + ); + }, + child: Text("Save & Continue", + style: fontTextStyle( + 14, Colors.white, FontWeight.w400)), + ), + ), + ], + ), + ), ), ); } - // ✅ Service item + // ✅ Service item checkbox list Widget _serviceItem(String label) { final bool selected = _selectedServices.contains(label); return GestureDetector( @@ -378,13 +443,14 @@ class _ServiceLocationState extends State { children: [ Icon( selected ? Icons.check_box : Icons.check_box_outline_blank, - color: selected ? Color(0xFF8270DB) : Color(0xFF939495), + color: selected ? const Color(0xFF8270DB) : const Color(0xFF939495), size: 20, ), const SizedBox(width: 8), Expanded( - child: Text(label, style: fontTextStyle(12, Color(0xFF2D2E30), FontWeight.w400), - ), + child: Text(label, + style: fontTextStyle( + 12, const Color(0xFF2D2E30), FontWeight.w400)), ), ], ), diff --git a/lib/profile/service_locations_radius.dart b/lib/profile/service_locations_radius.dart new file mode 100644 index 0000000..222382b --- /dev/null +++ b/lib/profile/service_locations_radius.dart @@ -0,0 +1,147 @@ +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); + }, + ); + } +}