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.

731 lines
28 KiB

2 months ago
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:supplier_new/common/settings.dart';
import 'package:supplier_new/orders/edit_order_requests.dart';
import '../resources/drivers_model.dart';
class ChangeDriverScreen extends StatefulWidget {
var order;
var status;
ChangeDriverScreen({this.order, this.status});
@override
State<ChangeDriverScreen> createState() => _ChangeDriverScreenState();
}
class _ChangeDriverScreenState extends State<ChangeDriverScreen> {
int advancePayable = 0;
int advance = 0;
double amountToPayAfterDelivery = 0.0;
double totalFare = 0.0;
bool isLoading = false;
List<DriversModel> driversList = [];
@override
void initState() {
// TODO: implement initState
super.initState();
_fetchDrivers();
advance = 150;
advancePayable = advance;
totalFare = advance + double.parse(widget.order.quoted_amount);
amountToPayAfterDelivery = totalFare - advancePayable;
}
Future<void> _fetchDrivers() async {
setState(() => isLoading = true);
try {
final response = await AppSettings.getDrivers();
final data = (jsonDecode(response)['data'] as List)
.map((e) => DriversModel.fromJson(e))
.toList();
if (!mounted) return;
setState(() {
driversList = data;
isLoading = false;
});
} catch (e) {
debugPrint("⚠️ Error fetching drivers: $e");
setState(() => isLoading = false);
}
}
void _showAssignDriverBottomSheet() {
int? selectedDriverIndex; // ✅ Track selected driver
showModalBottomSheet(
context: context,
isScrollControlled: true,
isDismissible: false,
enableDrag: false,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
builder: (context) {
return WillPopScope( // ✅ block Android back button
onWillPop: () async => false,
child: StatefulBuilder(
builder: (context, setModalState) {
return DraggableScrollableSheet(
expand: false,
initialChildSize: 0.7,
minChildSize: 0.5,
maxChildSize: 0.9,
builder: (context, scrollController) {
return Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
width: 60,
height: 4,
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: const Color(0xFFE0E0E0),
borderRadius: BorderRadius.circular(2),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Assign Driver",
style: fontTextStyle(16, const Color(0XFF2A2A2A), FontWeight.w600),
),
GestureDetector(
onTap: (){
Navigator.pop(context);
},
child: Image.asset('images/cross.png', height: 24, width: 24,color: Color(0XFF2A2A2A),),
)
],
),
const SizedBox(height: 16),
// 🏢 Order Info
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
border: Border.all(color: const Color(0XFFC9C2F0), width: 0.5),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.order.building_name,
style: fontTextStyle(20, const Color(0XFF2D2E30), FontWeight.w600),
),
Text(
widget.order.displayAddress,
style: fontTextStyle(12, const Color(0XFF939495), FontWeight.w400),
),
],
),
const Spacer(),
Text(
'${widget.order.distanceInKm} Km',
style: fontTextStyle(12, const Color(0XFF939495), FontWeight.w400),
),
],
),
),
const SizedBox(height: 16),
Text(
"SELECT DRIVER",
style: fontTextStyle(10, const Color(0XFF2D2E30), FontWeight.w600),
),
const SizedBox(height: 12),
// 🧍 Driver List
Expanded(
child: isLoading
? const Center(child: CircularProgressIndicator())
: ListView.separated(
controller: scrollController,
itemCount: driversList.length,
separatorBuilder: (_, __) => const SizedBox(height: 12),
itemBuilder: (context, idx) {
final d = driversList[idx];
final bool isSelected = selectedDriverIndex == idx;
final bool isAvailable = d.status == "available";
final statusColor = isAvailable
? const Color(0XFF0A9E04)
: (d.status == "on delivery"
? const Color(0XFFD0AE3C)
: (d.status == "offline"
? const Color(0XFF939495)
: Colors.grey));
return GestureDetector(
onTap: () {
if (isAvailable) { // ✅ only selectable if available
setModalState(() {
selectedDriverIndex = idx;
});
} else {
AppSettings.longFailedToast(
'Only available drivers can be selected',
);
}
},
child: Opacity(
opacity: isAvailable ? 1 : 1, // 👈 grey out non-available
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(
color: isSelected
? const Color(0XFF8270DB)
: const Color(0XFFC3C4C4),
width: 1,
),
),
color: isSelected
? const Color(0XFFEDEBFF)
: Colors.white,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
Image.asset(
'images/avatar.png',
fit: BoxFit.cover,
width: 20,
height: 20,
),
SizedBox(
width: MediaQuery.of(context).size.width * .016),
Expanded(
child: Text(
d.driver_name,
style: fontTextStyle(
14,
const Color(0XFF2D2E30),
FontWeight.w500,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * .016),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(color: statusColor),
),
child: Text(
d.status,
style: fontTextStyle(
10,
statusColor,
FontWeight.w400,
),
),
),
],
),
),
),
),
);
},
),
),
const SizedBox(height: 16),
// 🟣 Assign Button
SizedBox(
width: double.infinity,
child: GestureDetector(
onTap: () async {
if (selectedDriverIndex == null) {
AppSettings.longFailedToast('Please select driver');
return;
}
final selectedDriver = driversList[selectedDriverIndex!];
// ✅ Call your API here
// await _assignDriverApi(selectedDriver.driver_id);
if (context.mounted) Navigator.pop(context);
},
child: Container(
decoration: BoxDecoration(
color: const Color(0XFF8270DB),
borderRadius: BorderRadius.circular(24),
),
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(vertical: 12),
child: Text(
'Assign',
style: fontTextStyle(
14, const Color(0XFFFFFFFF), FontWeight.w500),
),
),
),
),
],
),
);
},
);
},
),);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
extendBodyBehindAppBar: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0,
title: Text(
'',
style: fontTextStyle(16, Color(0XFF2A2A2A), FontWeight.w600),
),
iconTheme: IconThemeData(color: Color(0XFF2A2A2A)),
actions: [
Row(
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 10, 10, 10),
child: IconButton(
icon: Image.asset(
'images/help_appbar.png',
height: 20,
width: 20,
color: Color(0XFFFFFFFF),
),
onPressed: () {},
),
)
],
)
],
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Padding(
padding:
const EdgeInsets.fromLTRB(8, 8, 8, 8), // Add padding if needed
child: Image.asset(
'images/backbutton_appbar.png', // Replace with your image path
fit: BoxFit.contain,
color: Color(0XFFFFFFFF),
height: 24,
width: 24,
),
),
),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// 🔹 Top Card with Image
Stack(
clipBehavior: Clip.none,
children: [
/// 🔹 Background Image
ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(0),
bottomRight: Radius.circular(0),
),
child: Image.asset(
"images/building.png",
height: 220,
width: double.infinity,
fit: BoxFit.cover,
),
),
/// 🔹 Floating Info Card (half on image, half below)
Positioned(
bottom: -40, // pulls the card out by 40px
left: 12,
right: 12,
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 3),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/*Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Color(0XFFFFFFFF),
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: widget.status.statusColor,
width: 0.5,
),
),
child: Text(widget.status.status,
style: fontTextStyle(
12,
widget.status.statusColor,
FontWeight.w500)),
),*/
Text(
widget.order.building_name,
style: fontTextStyle(
20, const Color(0XFF2D2E30), FontWeight.w600),
),
SizedBox(height: 4),
Text(
widget.order.displayAddress,
style: fontTextStyle(
12, const Color(0XFF939495), FontWeight.w400),
),
],
),
const Spacer(),
Text(
widget.order.distanceInKm.toString() + 'Km',
style: fontTextStyle(
12, const Color(0XFF939495), FontWeight.w400),
),
],
),
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height * .08,
),
/// 🔹 Order Details
Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"ORDER DETAILS",
style: fontTextStyle(
10, const Color(0XFF2D2E30), FontWeight.w600),
),
SizedBox(
height: MediaQuery.of(context).size.height * .011,
),
_detailTwoRow(
"Tanker Price",
"${AppSettings.formDouble(widget.order.quoted_amount) ?? ''}",
"images/financialsBottomIcon.png",
"",
"",
""),
SizedBox(
height: MediaQuery.of(context).size.height * .02,
),
_detailTwoRow(
"Water Type",
"${widget.order.type_of_water}",
"images/water.png",
"Date of Delivery",
"${widget.order.date}",
"images/calendar_appbar.png",
),
SizedBox(
height: MediaQuery.of(context).size.height * .02,
),
_detailTwoRow(
"Capacity",
"${widget.order.capacity}",
"images/capacity.png",
"Time of Delivery",
"${widget.order.time}",
"images/time.png",
),
SizedBox(
height: MediaQuery.of(context).size.height * .02,
),
_detailTwoRow(
"Quantity",
"${widget.order.quantity}",
"images/quantity.png",
"Booking Charges",
advance.toString(),
"images/advance.png",
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * .008,
),
/// 🔹 Additional Details
Padding(
padding: EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"ADDITIONAL DETAILS",
style: fontTextStyle(
10, const Color(0XFF2D2E30), FontWeight.w600),
),
SizedBox(
height: MediaQuery.of(context).size.height * .011,
),
Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, "
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
"Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
"aliquip ex ea commodo consequat.",
style: fontTextStyle(
12, const Color(0XFF646566), FontWeight.w400),
),
Image.asset(
'images/avatar.png',
fit: BoxFit.cover,
width: 20,
height: 20,
),
SizedBox(
width: MediaQuery.of(context).size.width * .016),
Expanded(
child: Text(
'd.driver_name',
style: fontTextStyle(
14,
const Color(0XFF2D2E30),
FontWeight.w500,
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * .016),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(color: Colors.green),
),
child: Text(
'd.status',
style: fontTextStyle(
10,
Colors.green,
FontWeight.w400,
),
),
),
],
)),
],
),
),
/// 🔹 Bottom Action Buttons
bottomNavigationBar: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Color(0XFFFFFFFF),
border: Border(top: BorderSide(color: Color(0XFFF5F6F6))),
),
child: Row(
children: [
Expanded(
child: OutlinedButton(
style: OutlinedButton.styleFrom(
foregroundColor: Color(0XFFFFFFFF),
backgroundColor: Colors.white,
side: BorderSide(color: Color(0XFFFFFFFF)),
padding: EdgeInsets.symmetric(vertical: 10),
),
onPressed: () async {
AppSettings.preLoaderDialog(context);
bool isOnline = await AppSettings.internetConnectivity();
if (isOnline) {
var payload = new Map<String, dynamic>();
payload["supplierId"] = AppSettings.supplierId;
payload["amount"] = int.parse(widget.order.quoted_amount);
payload["delivery_charges"] = advance;
payload["action"] = 'reject';
bool status = await AppSettings.acceptOrderRequests(
payload, widget.order.dbId);
try {
if (status) {
Navigator.of(context, rootNavigator: true).pop();
AppSettings.longSuccessToast(
"Order request rejected Successfully");
Navigator.pop(context, true);
} else {
Navigator.of(context, rootNavigator: true).pop();
AppSettings.longFailedToast(
"reject of order request Failed");
}
} catch (e) {
Navigator.of(context, rootNavigator: true).pop();
print(e);
}
} else {
Navigator.of(context, rootNavigator: true).pop();
AppSettings.longFailedToast("Please Check internet");
}
},
child: Text(
"CANCEL",
style: fontTextStyle(
14, const Color(0XFFE2483D), FontWeight.w400),
),
),
),
SizedBox(width: 8),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Color(0XFF8270DB),
foregroundColor: Color(0XFFFFFFFF),
padding: EdgeInsets.symmetric(vertical: 10),
),
onPressed: () async {
_showAssignDriverBottomSheet();
},
child: Text(
"Change Order",
style: fontTextStyle(
14, const Color(0XFFFFFFFF), FontWeight.w400),
),
),
),
],
)),
);
}
/// 🔹 Helper widget for rows
Widget _detailRow(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
title,
style: fontTextStyle(12, const Color(0XFF646566), FontWeight.w400),
),
Text(
value,
style: fontTextStyle(12, const Color(0XFF2D2E30), FontWeight.w500),
),
],
),
);
}
Widget _detailTwoRow(
String title1,
String value1,
String path1,
String title2,
String value2,
String path2, {
EdgeInsetsGeometry padding = const EdgeInsets.symmetric(vertical: 6),
}) {
final titleStyle = fontTextStyle(12, Color(0XFF646566), FontWeight.w400);
final valueStyle = fontTextStyle(12, Color(0XFF343637), FontWeight.w500);
Widget _col(String t, String v, String path) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (path.isNotEmpty)
Image.asset(
path,
fit: BoxFit.contain,
height: 20,
width: 20,
color: const Color(0XFFC3C4C4),
),
if (path.isNotEmpty) const SizedBox(width: 6),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t,
style: titleStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis),
Text(v,
style: valueStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis),
],
),
)
],
),
),
);
}
return Padding(
padding: padding,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_col(title1, value1, path1),
_col(title2, value2, path2),
],
),
);
}
}