874 lines
26 KiB
Dart
874 lines
26 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||
import 'package:google_places_flutter/google_places_flutter.dart';
|
||
import 'package:google_places_flutter/model/prediction.dart';
|
||
import 'package:nearledaily/constants/color_constants.dart';
|
||
import 'package:nearledaily/view/cart/cart_view.dart';
|
||
import 'package:shared_preferences/shared_preferences.dart';
|
||
import 'package:geolocator/geolocator.dart';
|
||
import 'package:geocoding/geocoding.dart';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
import '../../../modules/authentication/auth.dart';
|
||
import '../../constants/font_constants.dart';
|
||
import '../../domain/provider/authentication/location.dart';
|
||
import '../../main.dart';
|
||
import '../../widgets/text_widget.dart';
|
||
|
||
class LocationPage extends StatefulWidget {
|
||
const LocationPage({super.key});
|
||
|
||
@override
|
||
State<LocationPage> createState() => _LocationPageState();
|
||
}
|
||
|
||
class _LocationPageState extends State<LocationPage> with RouteAware {
|
||
final CustomerLocationProvider locationProvider = CustomerLocationProvider();
|
||
|
||
List<Authentication> fetchedLocations = [];
|
||
bool isLoading = true;
|
||
|
||
String? newAddress;
|
||
String? newLat;
|
||
String? newLong;
|
||
|
||
int? selectedLocationId;
|
||
Authentication? selectedLocation;
|
||
|
||
String searchQuery = "";
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_fetchLocations();
|
||
}
|
||
|
||
@override
|
||
void didPopNext() {
|
||
_fetchLocations();
|
||
super.didPopNext();
|
||
}
|
||
|
||
@override
|
||
void didChangeDependencies() {
|
||
super.didChangeDependencies();
|
||
routeObserver.subscribe(this, ModalRoute.of(context)!);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
routeObserver.unsubscribe(this);
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _fetchLocations() async {
|
||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
final id = prefs.getInt('customerId');
|
||
setState(() => isLoading = true);
|
||
try {
|
||
final locations = await locationProvider.fetchCustomerLocations(id!);
|
||
setState(() {
|
||
fetchedLocations = locations;
|
||
});
|
||
} catch (e) {
|
||
print('Error fetching locations: $e');
|
||
} finally {
|
||
setState(() => isLoading = false);
|
||
}
|
||
}
|
||
|
||
Future<void> _addNewAddress() async {
|
||
await Get.to(() => const MapPickerPage())?.then((result) async {
|
||
if (result == true) {
|
||
print("Refreshing locations now ✅");
|
||
await _fetchLocations();
|
||
}
|
||
});
|
||
}
|
||
|
||
Widget _badge({
|
||
required IconData icon,
|
||
required String label,
|
||
required bool isSelected,
|
||
}) {
|
||
const primaryColor = Color(0xFF662582);
|
||
return ConstrainedBox(
|
||
constraints: const BoxConstraints(maxWidth: 220), // ✅ prevents overflow
|
||
child: Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||
decoration: BoxDecoration(
|
||
color: isSelected ? const Color(0xFFF3E8FA) : Colors.grey.shade100,
|
||
borderRadius: BorderRadius.circular(20),
|
||
),
|
||
child: Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
Icon(
|
||
icon,
|
||
size: 10,
|
||
color: isSelected ? primaryColor : Colors.grey.shade500,
|
||
),
|
||
const SizedBox(width: 4),
|
||
Flexible( // ✅ allows text to shrink and ellipsis
|
||
child: Text(
|
||
label,
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
style: TextStyle(
|
||
fontSize: 11,
|
||
fontFamily: FontConstants.fontFamily,
|
||
color: isSelected ? primaryColor : Colors.grey.shade500,
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _addressCard({
|
||
required String address,
|
||
required String doorNo,
|
||
required String landmark,
|
||
required VoidCallback onTap,
|
||
required bool isSelected,
|
||
bool isAddNew = false,
|
||
}) {
|
||
const primaryColor = Color(0xFF662582);
|
||
|
||
if (isAddNew) {
|
||
return GestureDetector(
|
||
onTap: onTap,
|
||
behavior: HitTestBehavior.opaque,
|
||
child: Container(
|
||
margin: const EdgeInsets.symmetric(vertical: 5),
|
||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(14),
|
||
border: Border.all(
|
||
color: primaryColor.withOpacity(0.35),
|
||
width: 1,
|
||
),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Container(
|
||
width: 34,
|
||
height: 34,
|
||
decoration: const BoxDecoration(
|
||
color: Color(0xFFF3E8FA),
|
||
shape: BoxShape.circle,
|
||
),
|
||
child: const Icon(
|
||
Icons.add_location_alt_rounded,
|
||
size: 17,
|
||
color: primaryColor,
|
||
),
|
||
),
|
||
const SizedBox(width: 12),
|
||
ReusableTextWidget(
|
||
text: "Add new address",
|
||
fontSize: 13,
|
||
fontWeight: FontWeight.w500,
|
||
fontFamily: FontConstants.fontFamily,
|
||
color: primaryColor,
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
return GestureDetector(
|
||
onTap: onTap,
|
||
behavior: HitTestBehavior.opaque,
|
||
child: AnimatedContainer(
|
||
duration: const Duration(milliseconds: 200),
|
||
curve: Curves.easeInOut,
|
||
margin: const EdgeInsets.symmetric(vertical: 5),
|
||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
borderRadius: BorderRadius.circular(14),
|
||
border: Border.all(
|
||
color: isSelected ? primaryColor : Colors.grey.withOpacity(0.25),
|
||
width: isSelected ? 1.5 : 0.5,
|
||
),
|
||
),
|
||
child: Row(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// Icon circle
|
||
AnimatedContainer(
|
||
duration: const Duration(milliseconds: 200),
|
||
width: 34,
|
||
height: 34,
|
||
decoration: BoxDecoration(
|
||
color: isSelected
|
||
? const Color(0xFFF3E8FA)
|
||
: Colors.grey.shade100,
|
||
shape: BoxShape.circle,
|
||
),
|
||
child: Icon(
|
||
Icons.location_on_rounded,
|
||
size: 17,
|
||
color: isSelected ? primaryColor : Colors.grey.shade500,
|
||
),
|
||
),
|
||
|
||
const SizedBox(width: 12),
|
||
|
||
// Address + badges — Expanded so it never overflows
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// Main address bold (first 2 parts)
|
||
ReusableTextWidget(
|
||
text: address.split(',').take(2).join(',').trim(),
|
||
fontSize: 13,
|
||
fontWeight: FontWeight.w500,
|
||
fontFamily: FontConstants.fontFamily,
|
||
color: Colors.black.withOpacity(0.87),
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
const SizedBox(height: 2),
|
||
// Rest of address muted
|
||
ReusableTextWidget(
|
||
text: address.split(',').skip(2).join(',').trim(),
|
||
fontSize: 12,
|
||
fontWeight: FontWeight.w400,
|
||
fontFamily: FontConstants.fontFamily,
|
||
color: Colors.grey.shade500,
|
||
maxLines: 1,
|
||
overflow: TextOverflow.ellipsis,
|
||
),
|
||
const SizedBox(height: 8),
|
||
// Badges — each individually constrained
|
||
if (doorNo.isNotEmpty || landmark.isNotEmpty)
|
||
Wrap(
|
||
spacing: 6,
|
||
runSpacing: 4,
|
||
children: [
|
||
if (doorNo.isNotEmpty)
|
||
_badge(
|
||
icon: Icons.door_front_door_outlined,
|
||
label: "Door: $doorNo",
|
||
isSelected: isSelected,
|
||
),
|
||
if (landmark.isNotEmpty)
|
||
_badge(
|
||
icon: Icons.near_me_outlined,
|
||
label: "Near: $landmark",
|
||
isSelected: false,
|
||
),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
|
||
const SizedBox(width: 10),
|
||
|
||
// Radio indicator
|
||
AnimatedContainer(
|
||
duration: const Duration(milliseconds: 200),
|
||
width: 18,
|
||
height: 18,
|
||
margin: const EdgeInsets.only(top: 2),
|
||
decoration: BoxDecoration(
|
||
shape: BoxShape.circle,
|
||
border: Border.all(
|
||
color: isSelected
|
||
? primaryColor
|
||
: Colors.grey.withOpacity(0.4),
|
||
width: 1.5,
|
||
),
|
||
),
|
||
child: AnimatedScale(
|
||
duration: const Duration(milliseconds: 200),
|
||
scale: isSelected ? 1 : 0,
|
||
child: Center(
|
||
child: Container(
|
||
width: 8,
|
||
height: 8,
|
||
decoration: const BoxDecoration(
|
||
color: primaryColor,
|
||
shape: BoxShape.circle,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
List<Widget> _buildAddressList() {
|
||
List<Widget> list = [];
|
||
|
||
// 1️⃣ Add API fetched addresses
|
||
for (var loc in fetchedLocations) {
|
||
final addressText = loc.address ?? '';
|
||
if (addressText.toLowerCase().contains(searchQuery.toLowerCase())) {
|
||
list.add(_addressCard(
|
||
address: addressText,
|
||
doorNo: loc.doorno ?? '',
|
||
landmark: loc.landmark ?? '',
|
||
isSelected: selectedLocationId == loc.locationid,
|
||
onTap: () {
|
||
setState(() {
|
||
selectedLocationId = loc.locationid;
|
||
selectedLocation = loc;
|
||
});
|
||
},
|
||
));
|
||
}
|
||
}
|
||
|
||
// 2️⃣ Add new address (default, unchanged)
|
||
if (newAddress != null &&
|
||
newAddress!.toLowerCase().contains(searchQuery.toLowerCase())) {
|
||
list.add(_addressCard(
|
||
address: newAddress!,
|
||
doorNo: '',
|
||
landmark: '',
|
||
isSelected: selectedLocationId == -1,
|
||
onTap: () {
|
||
setState(() {
|
||
selectedLocationId = -1;
|
||
selectedLocation = Authentication(
|
||
locationid: 0,
|
||
customerid: "0",
|
||
address: newAddress ?? "",
|
||
suburb: "",
|
||
city: "",
|
||
state: "",
|
||
landmark: "",
|
||
doorno: "",
|
||
postcode: "",
|
||
latitude: newLat ?? "",
|
||
longitude: newLong ?? "",
|
||
);
|
||
});
|
||
},
|
||
));
|
||
}
|
||
|
||
// 3️⃣ Always show "Add New Address" option
|
||
list.add(_addressCard(
|
||
address: "Add new address",
|
||
doorNo: '',
|
||
landmark: '',
|
||
isSelected: false,
|
||
isAddNew: true,
|
||
onTap: _addNewAddress,
|
||
));
|
||
|
||
return list;
|
||
}
|
||
|
||
void _showPaymentBottomSheet() {
|
||
if (selectedLocation != null) {
|
||
print("Selected Location Details:");
|
||
print("locationid: ${selectedLocation!.locationid}");
|
||
print("customerid: ${selectedLocation!.customerid}");
|
||
print("address: ${selectedLocation!.address}");
|
||
print("suburb: ${selectedLocation!.suburb}");
|
||
print("city: ${selectedLocation!.city}");
|
||
print("state: ${selectedLocation!.state}");
|
||
print("landmark: ${selectedLocation!.landmark}");
|
||
print("doorno: ${selectedLocation!.doorno}");
|
||
print("postcode: ${selectedLocation!.postcode}");
|
||
print("latitude: ${selectedLocation!.latitude}");
|
||
print("longitude: ${selectedLocation!.longitude}");
|
||
|
||
Navigator.pop(context, selectedLocation);
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return SafeArea(
|
||
top: false,
|
||
bottom: true,
|
||
child: Scaffold(
|
||
backgroundColor: Colors.white,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.white,
|
||
elevation: 1,
|
||
leadingWidth: double.infinity,
|
||
centerTitle: false,
|
||
leading: Row(
|
||
children: [
|
||
IconButton(
|
||
icon: const Icon(Icons.arrow_back, color: Colors.black),
|
||
onPressed: () => Navigator.of(context).pop(),
|
||
),
|
||
ReusableTextWidget(
|
||
text: "Select Location",
|
||
color: Colors.black,
|
||
fontFamily: FontConstants.fontFamily,
|
||
fontSize: 20,
|
||
fontWeight: FontWeight.bold,
|
||
overflow: TextOverflow.ellipsis,
|
||
maxLines: 1,
|
||
),
|
||
],
|
||
),
|
||
actions: [
|
||
IconButton(
|
||
icon: const Icon(Icons.add_location_alt, color: Color(0xFF662582)),
|
||
tooltip: "Add New Location",
|
||
onPressed: _addNewAddress,
|
||
),
|
||
],
|
||
),
|
||
body: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: Column(
|
||
children: [
|
||
TextField(
|
||
onChanged: (val) {
|
||
setState(() => searchQuery = val);
|
||
},
|
||
decoration: InputDecoration(
|
||
hintText: "Search Address",
|
||
prefixIcon: const Icon(Icons.search),
|
||
filled: true,
|
||
fillColor: Colors.grey.shade100,
|
||
border: OutlineInputBorder(
|
||
borderRadius: BorderRadius.circular(12),
|
||
borderSide: BorderSide.none,
|
||
),
|
||
),
|
||
),
|
||
|
||
const SizedBox(height: 16),
|
||
Expanded(
|
||
child: isLoading
|
||
? const Center(child: CircularProgressIndicator())
|
||
: ListView(
|
||
children: _buildAddressList(),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
bottomNavigationBar: Padding(
|
||
padding: const EdgeInsets.all(16.0),
|
||
child: ElevatedButton(
|
||
onPressed: selectedLocationId == null ? null : _showPaymentBottomSheet,
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: const Color(0xFF662582),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(8),
|
||
),
|
||
padding: const EdgeInsets.symmetric(vertical: 16),
|
||
),
|
||
child: ReusableTextWidget(
|
||
text: "Confirm Address",
|
||
color: Colors.white,
|
||
fontFamily: FontConstants.fontFamily,
|
||
fontSize: 16,
|
||
overflow: TextOverflow.ellipsis,
|
||
maxLines: 1,
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
class MapPickerPage extends StatefulWidget {
|
||
const MapPickerPage({super.key});
|
||
|
||
@override
|
||
State<MapPickerPage> createState() => _MapPickerPageState();
|
||
}
|
||
|
||
class _MapPickerPageState extends State<MapPickerPage> {
|
||
LatLng? selectedLatLng;
|
||
String? selectedAddress;
|
||
GoogleMapController? mapController;
|
||
|
||
LatLng currentLatLng = const LatLng(11.0168, 76.9558); // default Coimbatore
|
||
static const String googleApiKey = "AIzaSyBhkGfnq27sN0wV5y_S-M2KojpFTk_by-Q";
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_checkPermissionAndGetLocation();
|
||
}
|
||
|
||
|
||
// Search function
|
||
|
||
|
||
Future<void> _checkPermissionAndGetLocation() async {
|
||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||
if (!serviceEnabled) {
|
||
Get.snackbar("Location Disabled", "Please enable location services");
|
||
return;
|
||
}
|
||
|
||
LocationPermission permission = await Geolocator.checkPermission();
|
||
if (permission == LocationPermission.denied) {
|
||
permission = await Geolocator.requestPermission();
|
||
}
|
||
if (permission == LocationPermission.deniedForever) {
|
||
Get.snackbar("Permission Denied",
|
||
"Location permission is permanently denied, please enable it in settings");
|
||
return;
|
||
}
|
||
|
||
if (permission == LocationPermission.whileInUse ||
|
||
permission == LocationPermission.always) {
|
||
await _goToCurrentLocation();
|
||
}
|
||
}
|
||
|
||
Future<void> _getAddressFromLatLng(LatLng latLng) async {
|
||
setState(() {
|
||
selectedAddress = "Loading address...";
|
||
});
|
||
try {
|
||
List<Placemark> placemarks =
|
||
await placemarkFromCoordinates(latLng.latitude, latLng.longitude);
|
||
|
||
if (placemarks.isNotEmpty) {
|
||
final place = placemarks.first;
|
||
setState(() {
|
||
selectedAddress =
|
||
"${place.name}, ${place.locality}, ${place.administrativeArea}, ${place.postalCode}";
|
||
});
|
||
} else {
|
||
setState(() {
|
||
selectedAddress = "Unknown location";
|
||
});
|
||
}
|
||
} catch (e) {
|
||
setState(() {
|
||
selectedAddress = "Failed to get address";
|
||
});
|
||
}
|
||
}
|
||
|
||
Future<void> _goToCurrentLocation() async {
|
||
try {
|
||
Position position = await Geolocator.getCurrentPosition(
|
||
desiredAccuracy: LocationAccuracy.high);
|
||
LatLng latLng = LatLng(position.latitude, position.longitude);
|
||
|
||
setState(() {
|
||
selectedLatLng = latLng;
|
||
});
|
||
|
||
mapController?.animateCamera(CameraUpdate.newLatLngZoom(latLng, 16));
|
||
await _getAddressFromLatLng(latLng);
|
||
} catch (e) {
|
||
// Get.snackbar();
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return SafeArea(
|
||
top: false,
|
||
child: Scaffold(
|
||
backgroundColor: Colors.white,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.white,
|
||
title: const Text("Pick Location"),
|
||
actions: [
|
||
IconButton(
|
||
onPressed: _goToCurrentLocation,
|
||
icon: Container(
|
||
decoration: BoxDecoration(
|
||
color: Colors.white,
|
||
shape: BoxShape.circle,
|
||
boxShadow: [
|
||
BoxShadow(
|
||
color: Colors.black26,
|
||
blurRadius: 4,
|
||
offset: Offset(0, 2),
|
||
),
|
||
],
|
||
),
|
||
child: const Padding(
|
||
padding: EdgeInsets.all(8.0),
|
||
child: Icon(Icons.my_location, color: Colors.black),
|
||
),
|
||
),
|
||
),
|
||
|
||
],
|
||
),
|
||
body: Stack(
|
||
children: [
|
||
GoogleMap(
|
||
initialCameraPosition:
|
||
CameraPosition(target: currentLatLng, zoom: 14),
|
||
onMapCreated: (controller) => mapController = controller,
|
||
onTap: (latLng) async {
|
||
setState(() {
|
||
selectedLatLng = latLng;
|
||
});
|
||
await _getAddressFromLatLng(latLng);
|
||
},
|
||
markers: selectedLatLng != null
|
||
? {
|
||
Marker(
|
||
markerId: const MarkerId("picked"),
|
||
position: selectedLatLng!)
|
||
}
|
||
: {},
|
||
myLocationEnabled: true,
|
||
myLocationButtonEnabled: false,
|
||
),
|
||
// Floating button for current location
|
||
|
||
// Address card
|
||
if (selectedAddress != null)
|
||
Positioned(
|
||
bottom: 80,
|
||
left: 16,
|
||
right: 16,
|
||
child: Card(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(12),
|
||
child: Text(
|
||
selectedAddress!,
|
||
style: const TextStyle(fontSize: 14),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
|
||
|
||
],
|
||
),
|
||
bottomNavigationBar: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: ElevatedButton(
|
||
onPressed: selectedLatLng == null
|
||
? null
|
||
: () async {
|
||
String address = selectedAddress ?? "";
|
||
String suburb = "";
|
||
String city = "";
|
||
String state = "";
|
||
String postcode = "";
|
||
|
||
try {
|
||
List<Placemark> placemarks =
|
||
await placemarkFromCoordinates(
|
||
selectedLatLng!.latitude,
|
||
selectedLatLng!.longitude);
|
||
if (placemarks.isNotEmpty) {
|
||
final place = placemarks.first;
|
||
suburb = place.subLocality ?? "";
|
||
city = place.locality ?? "";
|
||
state = place.administrativeArea ?? "";
|
||
postcode = place.postalCode ?? "";
|
||
|
||
final result = await Get.to(() => AddressDetailsPage(
|
||
address: address,
|
||
suburb: suburb,
|
||
city: city,
|
||
state: state,
|
||
postcode: postcode,
|
||
latitude: selectedLatLng!.latitude.toString(),
|
||
longitude: selectedLatLng!.longitude.toString(),
|
||
));
|
||
|
||
if (result == true) {
|
||
Get.back(result: true);
|
||
}
|
||
}
|
||
} catch (e) {
|
||
print("Error parsing placemark: $e");
|
||
}
|
||
},
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: ColorConstants.primaryColor,
|
||
padding: const EdgeInsets.symmetric(vertical: 16)),
|
||
child: const Text(
|
||
"Confirm Location",
|
||
style: TextStyle(color: Colors.white),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
class AddressDetailsPage extends StatefulWidget {
|
||
final String address;
|
||
final String? suburb;
|
||
final String? city;
|
||
final String? state;
|
||
final String? postcode;
|
||
final String? latitude;
|
||
final String? longitude;
|
||
|
||
const AddressDetailsPage({
|
||
super.key,
|
||
required this.address,
|
||
this.suburb,
|
||
this.city,
|
||
this.state,
|
||
this.postcode,
|
||
this.latitude,
|
||
this.longitude,
|
||
});
|
||
|
||
@override
|
||
State<AddressDetailsPage> createState() => _AddressDetailsPageState();
|
||
}
|
||
|
||
class _AddressDetailsPageState extends State<AddressDetailsPage> {
|
||
final _formKey = GlobalKey<FormState>();
|
||
|
||
late TextEditingController addressController;
|
||
late TextEditingController doorController;
|
||
late TextEditingController landmarkController;
|
||
|
||
bool isLoading = false;
|
||
|
||
final CustomerLocationProvider provider = CustomerLocationProvider();
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
addressController = TextEditingController(text: widget.address);
|
||
doorController = TextEditingController();
|
||
landmarkController = TextEditingController();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
addressController.dispose();
|
||
doorController.dispose();
|
||
landmarkController.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
void submitAddress() async {
|
||
if (!_formKey.currentState!.validate()) return;
|
||
|
||
setState(() => isLoading = true);
|
||
|
||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||
final id = prefs.getInt('customerId');
|
||
|
||
final success = await provider.createCustomerLocation(
|
||
|
||
|
||
customerId: id!, // Replace with your dynamic customer ID
|
||
address: addressController.text,
|
||
doorNo: doorController.text,
|
||
landmark: landmarkController.text,
|
||
suburb: widget.suburb ?? "",
|
||
city: widget.city ?? "",
|
||
state: widget.state ?? "",
|
||
postcode: widget.postcode ?? "",
|
||
latitude: widget.latitude ?? "",
|
||
longitude: widget.longitude ?? "",
|
||
defaultAddress: "Yes",
|
||
primaryAddress: 1,
|
||
status: 1,
|
||
);
|
||
|
||
|
||
|
||
setState(() => isLoading = false);
|
||
Get.until((route) => route.settings.name == '/LocationPage');
|
||
|
||
if (success == true) {
|
||
print("API Success ✅");
|
||
Get.snackbar("Success", "Address submitted successfully");
|
||
|
||
await Future.delayed(const Duration(milliseconds: 800));
|
||
Get.back(result: true);
|
||
} else {
|
||
print("API failed ❌");
|
||
Get.snackbar("Error", "Failed to submit address");
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return SafeArea(
|
||
child: Scaffold(
|
||
backgroundColor: Colors.grey[200],
|
||
appBar: AppBar(title: const Text("Edit Address"),backgroundColor: Colors.grey[200],),
|
||
body: Padding(
|
||
padding: const EdgeInsets.all(16),
|
||
child: Form(
|
||
key: _formKey,
|
||
child: ListView(
|
||
children: [
|
||
_buildTextField("Address", addressController),
|
||
const SizedBox(height: 12),
|
||
_buildTextField("Door Number", doorController),
|
||
const SizedBox(height: 12),
|
||
_buildTextField("Landmark", landmarkController),
|
||
const SizedBox(height: 20),
|
||
ElevatedButton(
|
||
style: ElevatedButton.styleFrom(
|
||
backgroundColor: const Color(0xFF662582), // Purple color
|
||
padding: const EdgeInsets.symmetric(vertical: 14),
|
||
shape: RoundedRectangleBorder(
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
minimumSize: const Size(double.infinity, 50), // full width
|
||
),
|
||
onPressed: isLoading ? null : submitAddress,
|
||
child: isLoading
|
||
? const CircularProgressIndicator(color: Colors.white)
|
||
: const Text(
|
||
"Submit Address",
|
||
style: TextStyle(color: Colors.white, fontSize: 16),
|
||
),
|
||
)
|
||
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _buildTextField(String label, TextEditingController controller) {
|
||
return TextFormField(
|
||
controller: controller,
|
||
decoration: InputDecoration(
|
||
labelText: label,
|
||
border: const OutlineInputBorder(),
|
||
),
|
||
validator: (value) => value == null || value.isEmpty ? "Enter $label" : null,
|
||
);
|
||
}
|
||
}
|
||
|
||
|