import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:supplier_new/common/settings.dart'; import 'package:supplier_new/profile/service_location.dart'; import '../common/keys.dart'; import '../google_maps_place_picker_mb/src/models/pick_result.dart'; import '../google_maps_place_picker_mb/src/place_picker.dart'; import 'package:supplier_new/google_maps_place_picker_mb/google_maps_place_picker.dart'; import 'package:google_maps_flutter_android/google_maps_flutter_android.dart'; import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; import 'package:location/location.dart' as locationmap; import '../resources/resources_drivers.dart'; import '../resources/source_loctaions_model.dart'; class SourceLocation extends StatefulWidget { const SourceLocation({super.key}); @override State createState() => _SourceLocationState(); } PickResult? selectedPlace; bool _mapsInitialized = false; final String _mapsRenderer = "latest"; var kInitialPosition = const LatLng(15.462477, 78.717401); locationmap.Location location = locationmap.Location(); final GoogleMapsFlutterPlatform mapsImplementation = GoogleMapsFlutterPlatform.instance; void initRenderer() { if (_mapsInitialized) return; if (mapsImplementation is GoogleMapsFlutterAndroid) { switch (_mapsRenderer) { case "legacy": (mapsImplementation as GoogleMapsFlutterAndroid) .initializeWithRenderer(AndroidMapRenderer.legacy); break; case "latest": (mapsImplementation as GoogleMapsFlutterAndroid) .initializeWithRenderer(AndroidMapRenderer.latest); break; } } // setState(() { // _mapsInitialized = true; // }); } class _SourceLocationState extends State { bool isLoading = false; int currentStep = 2; List sourceLocationsList = []; bool addBusinessAsSource = false; final List waterTypes = [ "Drinking Water", "Bore Water", "Industrial", "Construction", "Non-potable", ]; // For map bool _mapsInitialized = false; final GoogleMapsFlutterPlatform mapsImplementation = GoogleMapsFlutterPlatform.instance; final locationmap.Location location = locationmap.Location(); var kInitialPosition = const LatLng(15.462477, 78.717401); void initRenderer() { if (_mapsInitialized) return; if (mapsImplementation is GoogleMapsFlutterAndroid) { (mapsImplementation as GoogleMapsFlutterAndroid) .initializeWithRenderer(AndroidMapRenderer.latest); } setState(() => _mapsInitialized = true); } @override void initState() { super.initState(); _fetchSources(); } Future _fetchSources() async { setState(() => isLoading = true); try { final response = await AppSettings.getSourceLoctaions(); final data = (jsonDecode(response)['data'] as List) .map((e) => SourceLocationsModel.fromJson(e)) .toList(); if (!mounted) return; setState(() { sourceLocationsList = data; isLoading = false; }); } catch (e) { debugPrint("⚠️ Error fetching source locations: $e"); setState(() => isLoading = false); } } String? _required(String? v, {String field = "This field"}) { if (v == null || v.trim().isEmpty) return "$field is required"; return null; } String? _validatePhone(String? v, {String label = "Phone"}) { if (v == null || v.trim().isEmpty) return "$label is required"; if (v.trim().length != 10) return "$label must be 10 digits"; return null; } void _showAddLocationSheet() { final _formKey = GlobalKey(); final TextEditingController _nameCtrl = TextEditingController(); final TextEditingController _mobileCtrl = TextEditingController(); String? selectedWaterType; String address = ''; double lat = 0; double lng = 0; showModalBottomSheet( isScrollControlled: true, context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20))), backgroundColor: Colors.white, builder: (context) { return Padding( padding: EdgeInsets.only( left: 20, right: 20, top: 20, bottom: MediaQuery.of(context).viewInsets.bottom + 20, ), child: SingleChildScrollView( child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Center( child: Container( width: 40, height: 4, margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(2), ), ), ), Center( child: Text( "Add Source Location", style: fontTextStyle(16, Color(0xFF2D2E30), FontWeight.w600), ), ), const SizedBox(height: 20), _LabeledField( label: "Location Name *", child: TextFormField( controller: _nameCtrl, validator: (v) => _required(v, field: "Location Name"), textCapitalization: TextCapitalization.none, inputFormatters: const [ FirstCharUppercaseFormatter(), // << live first-letter caps ], decoration: InputDecoration( hintText: "Location Name", hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), textInputAction: TextInputAction.next, ), ), _LabeledField( label: "Mobile Number *", child: TextFormField( controller: _mobileCtrl, validator: (v) => _validatePhone(v, label: "Mobile Number"), keyboardType: TextInputType.phone, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], decoration: InputDecoration( hintText: "Mobile Number", hintStyle: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), border: const OutlineInputBorder(), isDense: true, ), textInputAction: TextInputAction.next, ), ), Visibility( visible: !addBusinessAsSource, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox( width: double.infinity, child: OutlinedButton.icon( onPressed: () { // Your PlacePicker flow goes here (kept commented for reference) location.serviceEnabled().then((value) { if (value) { initRenderer(); Navigator.push( context, MaterialPageRoute( builder: (context) { return PlacePicker( resizeToAvoidBottomInset: false, hintText: "Find a place ...", searchingText: "Please wait ...", selectText: "Select place", outsideOfPickAreaText: "Place not in area", initialPosition: kInitialPosition, useCurrentLocation: true, selectInitialPosition: true, usePinPointingSearch: true, usePlaceDetailSearch: true, zoomGesturesEnabled: true, zoomControlsEnabled: true, onMapCreated: (GoogleMapController controller) {}, onPlacePicked: (PickResult result) { setState(() { selectedPlace = result; lat = selectedPlace!.geometry!.location.lat; lng = selectedPlace!.geometry!.location.lng; if (selectedPlace!.types!.length == 1) { address = selectedPlace!.formattedAddress!; } else { address = '${selectedPlace!.name!}, ${selectedPlace!.formattedAddress!}'; } Navigator.of(context).pop(); }); }, onMapTypeChanged: (MapType mapType) {}, apiKey: Platform.isAndroid ? APIKeys.androidApiKey : APIKeys.iosApiKey, forceAndroidLocationManager: true, ); }, ), ); } else { showGeneralDialog( context: context, pageBuilder: (context, x, y) { return Scaffold( backgroundColor: Colors.grey.withOpacity(.5), body: Center( child: Container( width: double.infinity, height: 150, padding: const EdgeInsets.symmetric(horizontal: 20), child: Card( child: Padding( padding: const EdgeInsets.all(10.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( "Please enable the location", style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500), ), const SizedBox(height: 20), ElevatedButton( onPressed: () { Navigator.pop(context); }, child: const Text("Cancel"), ), ], ), ), ), ), ), ); }, ); } }); }, icon: Image.asset('images/Add_icon.png', width: 16, height: 16), label: Text( "Add Location on map", style: fontTextStyle(14, const Color(0xFF646566), FontWeight.w600), ), ), ), const SizedBox(height: 16), ], ), ), _LabeledField( label: "Water Type *", child: DropdownButtonFormField( value: selectedWaterType, items: waterTypes .map((w) => DropdownMenuItem(value: w, child: Text(w))) .toList(), onChanged: (v) => setState(() => selectedWaterType = v), validator: (v) => v == null || v.isEmpty ? "Water Type is required" : null, isExpanded: true, alignment: Alignment.centerLeft, hint: Text( "Select Water Type", style: fontTextStyle(14, const Color(0xFF939495), FontWeight.w400), ), icon: Image.asset('images/downarrow.png', width: 16, height: 16), decoration: const InputDecoration( border: OutlineInputBorder(), isDense: false, contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14), ), ), ), const SizedBox(height: 20), const SizedBox(height: 20), SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8270DB), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24)), padding: const EdgeInsets.symmetric(vertical: 14), ), onPressed: () async { if (_formKey.currentState?.validate() ?? false) { var payload = { "location_name": _nameCtrl.text, "phone": _mobileCtrl.text, "water_type": selectedWaterType, "address": address, "latitude": lat, "longitude": lng, "status": "active", }; bool ok = await AppSettings.addSourceLocations(payload); if (ok) { AppSettings.longSuccessToast( "Source added successfully"); Navigator.pop(context); _fetchSources(); } else { AppSettings.longFailedToast( "Failed to add location"); } } }, child: const Text("Save Location", style: TextStyle( fontSize: 14, color: Colors.white)), ), ), ], ), ), ), ); }, ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( backgroundColor: Colors.white, surfaceTintColor: Colors.transparent, elevation: 0, title: const Text("Complete Profile"), ), body: SafeArea( child: isLoading ? const Center(child: CircularProgressIndicator()) : 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), ), ), ); }), ), const SizedBox(height: 16), Text("SOURCE LOCATIONS", style: fontTextStyle(20, Color(0xFF515253), FontWeight.w600)), const SizedBox(height: 6), Align( alignment: Alignment.centerLeft, child: Image.asset('images/truck.png', width: 24, height: 24), ), const SizedBox(height: 16), Text("Add your source location", style: fontTextStyle(14, Color(0xFF939495), FontWeight.w500)), const SizedBox(height: 16), // List of saved locations if (sourceLocationsList.isEmpty) const Padding( padding: EdgeInsets.symmetric(vertical: 40), child: Center( child: Text("No source locations added yet."), ), ) else ...List.generate(sourceLocationsList.length, (idx) { final d = sourceLocationsList[idx]; bool expanded = false; return StatefulBuilder(builder: (context, setInner) { return Container( margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 0), decoration: BoxDecoration( color: Color(0xFFF1F1F1), // background color border: Border.all(color: Color(0xFFE5E5E5)), borderRadius: BorderRadius.circular(29), ), child: Column( children: [ ListTile( dense: true, // makes tile shorter contentPadding: EdgeInsets.zero, // removes default horizontal padding 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( expanded ? 'images/arrow-up.png' : 'images/downarrow.png', width: 18, height: 18, ), onPressed: () => setInner(() => expanded = !expanded), ), ), if (expanded) 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, Color(0xFF646566), FontWeight.w400), ), ), ], ), ); }); }), const SizedBox(height: 24), OutlinedButton.icon( onPressed: _showAddLocationSheet, icon: const Icon(Icons.add, size: 18, color: Color(0xFF646566)), label: Text( "Add New Location", style: fontTextStyle( 14, const Color(0xFF646566), FontWeight.w600), ), ), const SizedBox(height: 16), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF8270DB), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24)), ), onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (_) => const ServiceLocation())); }, child: Text("Continue", style: fontTextStyle( 14, Color(0xFFFFFFFF), FontWeight.w600)), ), ], ), ), ); } } // ======= Helper widget ======= class _LabeledField extends StatelessWidget { final String label; final Widget child; const _LabeledField({required this.label, required this.child}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(bottom: 14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: fontTextStyle( 12, const Color(0xFF515253), FontWeight.w600)), const SizedBox(height: 6), child, ], ), ); } }