second commit

This commit is contained in:
Anbarasu
2026-05-27 10:35:09 +05:30
parent c53794c04c
commit 1435ac47b0
501 changed files with 52818 additions and 0 deletions

View File

@@ -0,0 +1,951 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../Controller/map_controller.dart';
import '../../../Globalwidgets/textwidget.dart';
import '../../../Helper/Constants/Colorconstants.dart';
import '../../../Helper/utility.dart';
import '../../../Model/Response/Summary/Getsummarysresponse.dart';
class MapWithBottomSheetPage extends StatelessWidget {
final DeliveriesDetails data;
MapWithBottomSheetPage({super.key, required this.data});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
MapWithPolylines(
endLatLng: LatLng(
double.tryParse(data.deliverylat ?? '') ?? 0.0,
double.tryParse(data.deliverylong ?? '') ?? 0.0,
),
startLatLng: LatLng(
double.tryParse(data.pickuplat ?? '') ?? 0.0,
double.tryParse(data.pickuplon ?? '') ?? 0.0,
),
),
DraggableScrollableSheet(
initialChildSize: 0.22,
minChildSize: 0.12,
maxChildSize: 0.65,
builder: (context, scrollController) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(18)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
spreadRadius: 2,
),
],
),
child: SingleChildScrollView(
controller: scrollController,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 40,
height: 5,
decoration: BoxDecoration(
color: Colors.grey[300],
borderRadius: BorderRadius.circular(12),
),
),
SizedBox(height: 12),
Row(
children: [
CircleAvatar(
backgroundColor: ColorConstants.primaryColor,
radius: 30,
child: TextWidget(
text: data.ridername?[0] ?? '',
fontWeight: FontWeight.w700,
fontSize: 20,
color: ColorConstants.secondaryColor,
),
),
SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.ridername ?? '',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
Text("Order ID: ${data.orderid}"),
Text("Status: ${data.orderstatus}", style: TextStyle(color: Colors.green)),
],
),
),
IconButton(
icon: Icon(Icons.phone, color: ColorConstants.primaryColor),
onPressed: () {},
),
],
),
SizedBox(height: 20),
Divider(),
ListTile(
title: Text("Pickup Location"),
subtitle: Text(data.pickupaddress ?? ''),
leading: Icon(Icons.location_on, color: Colors.red),
),
SizedBox(height: 10,),
ListTile(
title: Text("Drop-off Location"),
subtitle: Text(data.deliveryaddress ?? ''),
leading: Icon(Icons.flag, color: Colors.green),
),
SizedBox(height: 18),
Divider(
height: 1,
color: Colors.grey,
),
SizedBox(height: 18),
TextWidget(
text: 'Order Details',
fontWeight: FontWeight.w500,
fontSize: 14,
),
SizedBox(height: 10,),
Row(
children: [
TextWidget(
text: 'Delivery Charges',
fontWeight: FontWeight.w700,
),
Spacer(),
TextWidget(
text: data.deliverycharges.toString(),
fontWeight: FontWeight.w700,
)
],
),
SizedBox(height: 10,),
Row(
children: [
TextWidget(
text: 'Total Amount',
fontWeight: FontWeight.w700,
),
Spacer(),
TextWidget(
text: data.deliveryamt.toString(),
fontWeight: FontWeight.w700,
)
],
),
SizedBox(height: 18),
Divider(
height: 1,
color: Colors.grey,
),
SizedBox(height: 18),
TextWidget(
text: 'Payment Details',
fontWeight: FontWeight.w500,
fontSize: 14,
),
SizedBox(height: 10,),
Row(
children: [
TextWidget(
text: data.deliverycustomer ?? '',
fontWeight: FontWeight.w700,
),
Spacer(),
TextWidget(
text: data.deliverycontactno.toString(),
fontWeight: FontWeight.w700,
)
],
),
SizedBox(height: 18),
Divider(
height: 1,
color: Colors.grey,
),
SizedBox(height: 18),
TextWidget(
text: 'Payment method',
fontWeight: FontWeight.w500,
fontSize: 14,
),
SizedBox(height: 10,),
TextWidget(
text: 'Cash on delivery',
fontWeight: FontWeight.w700,
),
],
),
),
),
);
},
),
],
),
);
}
}
// class SummaryDetailsView extends StatelessWidget {
// final DeliveriesDetails data;
//
// const SummaryDetailsView({super.key, required this.data});
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// appBar: _buildAppBar(),
// backgroundColor: Colors.grey[100],
// body: _buildBody(context),
// );
// }
//
// /// Builds the app bar with a back button and title.
// AppBar _buildAppBar() {
// return AppBar(
// leading: InkWell(
// onTap: Get.back,
// child: Icon(
// Icons.arrow_back,
// color: ColorConstants.blackColor,
// size: 28,
// ),
// ),
// title: TextWidget(
// text: 'Delivery Details',
// fontSize: 20,
// fontWeight: FontWeight.w700,
// ),
// backgroundColor: ColorConstants.secondaryColor,
// );
// }
//
// /// Builds the scrollable body with delivery details and map.
// Widget _buildBody(BuildContext context) {
// return SingleChildScrollView(
// padding: const EdgeInsets.all(0.0),
// child: Column(
// children: [
// Padding(
// padding: const EdgeInsets.only(left: 0,right: 0),
// child: SizedBox(
// height: Get.height * 0.60,
// child: MapWithPolylines(
// endLatLng: LatLng(
// double.tryParse(data.deliverylat ?? '') ?? 0.0,
// double.tryParse(data.deliverylong ?? '') ?? 0.0,
// ),
// startLatLng: LatLng(
// double.tryParse(data.pickuplat ?? '') ?? 0.0,
// double.tryParse(data.pickuplon ?? '') ?? 0.0,
// ),
// )
// ),
// ),
// const SizedBox(height: 10),
// DeliveryCard(data: data, isFromSummary: true,),
// const SizedBox(height: 20,)
// ],
// ),
// );
// }
// }
/// A reusable card widget displaying delivery header information (date, tenant, order).
class DeliveryHeaderCard extends StatelessWidget {
final DeliveriesDetails data;
const DeliveryHeaderCard({super.key, required this.data});
@override
Widget build(BuildContext context) {
return Container(
color: ColorConstants.secondaryColor,
margin: const EdgeInsets.symmetric(horizontal: 5),
height: 95,
child: Row(
children: [
_buildDateSection(),
const SizedBox(width: 12),
Expanded(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconTextRow(
icon: Icons.person,
text: data.tenantname ?? '',
textStyle: _textStyle(15, Colors.grey[500]),
),
IconTextRow(
icon: Icons.receipt,
text: data.orderid ?? '',
textStyle: _textStyle(13, Colors.black54),
),
IconTextRow(
icon: Icons.phone,
text: data.tenantcontactno ?? '',
textStyle: _textStyle(13, Colors.black54),
onTap: () => _launchPhone(data.tenantcontactno),
),
],
),
),
],
),
);
}
/// Builds the date section with day, month, and time.
Widget _buildDateSection() {
final date = DateFormat("yyyy-MM-dd", "en_US").parse(data.deliverydate ?? DateTime.now().toString());
return Container(
width: 75,
decoration: BoxDecoration(
color: ColorConstants.primaryColor1,
shape: BoxShape.rectangle,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
decoration: BoxDecoration(
color: Colors.white70,
borderRadius: BorderRadius.circular(5),
),
child: Column(
children: [
Text(
DateFormat("dd").format(date),
style: _textStyle(14, Colors.grey[700]),
),
const SizedBox(height: 4),
Text(
DateFormat("MMM").format(date),
style: _textStyle(14, Colors.grey[700], height: 1),
),
],
),
),
const SizedBox(height: 6),
Text(
DateFormat("hh.mm a").format(date),
style: _textStyle(11, Colors.grey[700]),
),
],
),
);
}
/// Helper method to create consistent text styles.
TextStyle _textStyle(double fontSize, Color? color, {double? height}) {
return TextStyle(
fontSize: fontSize,
color: color,
fontWeight: FontWeight.w600,
height: height,
);
}
/// Launches phone dialer with the provided number.
void _launchPhone(String? number) {
if (number != null && number.isNotEmpty) {
launch('tel://$number');
}
}
}
/// A reusable card widget for displaying pickup or delivery location details.
class DeliveryLocationCard extends StatelessWidget {
final String title;
final String address;
final String contact;
final double lat;
final double lon;
final Color iconColor;
final bool isPickup;
const DeliveryLocationCard({
super.key,
required this.title,
required this.address,
required this.contact,
required this.lat,
required this.lon,
required this.iconColor,
required this.isPickup,
});
@override
Widget build(BuildContext context) {
return Card(
color: Colors.red[100]!.withAlpha(100),
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(13)),
child: SizedBox(
height: 150,
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Expanded(
flex: 2,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const SizedBox(height: 15),
_buildMarkerIcon(),
const Spacer(),
_buildNavigationIcon(),
const SizedBox(height: 10),
],
),
),
Expanded(
flex: 14,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Card(
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.only(left: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 15),
IconTextRow(
icon: isPickup ? Icons.business : Icons.person,
text: title,
textStyle: const TextStyle(color: Colors.black87, fontSize: 15),
),
const SizedBox(height: 10),
IconTextRow(
icon: Icons.location_on_rounded,
text: address,
textStyle: const TextStyle(
color: Colors.black87,
fontSize: 13,
overflow: TextOverflow.ellipsis,
),
maxLines: 2,
),
const SizedBox(height: 15),
IconTextRow(
icon: Icons.phone,
text: contact,
textStyle: const TextStyle(color: Colors.black87, fontSize: 13),
onTap: () => Utility.openPhoneCallApp(contact),
),
],
),
),
),
),
),
],
),
),
);
}
/// Builds the marker icon for the location.
Widget _buildMarkerIcon() {
return Container(
height: 40,
width: 40,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: FaIcon(
FontAwesomeIcons.mapMarkerAlt,
size: 22,
color: iconColor,
),
);
}
/// Builds the navigation icon with a tap action to open the map.
Widget _buildNavigationIcon() {
return InkWell(
onTap: () => Utility.openMap(lat, lon),
child: Container(
height: 40,
width: 40,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: const Icon(
Icons.assistant_direction_rounded,
size: 30,
color: ColorConstants.primaryColor,
),
),
);
}
}
/// A reusable widget for displaying an icon and text with an optional tap action.
class IconTextRow extends StatelessWidget {
final IconData icon;
final String text;
final TextStyle textStyle;
final int? maxLines;
final VoidCallback? onTap;
const IconTextRow({
super.key,
required this.icon,
required this.text,
required this.textStyle,
this.maxLines,
this.onTap,
});
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Row(
children: [
Icon(icon, size: 14, color: Colors.black38),
const SizedBox(width: 4),
Flexible(
child: Text(
text,
style: textStyle,
maxLines: maxLines,
overflow: maxLines != null ? TextOverflow.ellipsis : null,
),
),
if (maxLines != null) const SizedBox(width: 5),
],
),
);
}
}
/// Map with polyLines
class MapWithPolylines extends StatelessWidget {
final LatLng startLatLng;
final LatLng endLatLng;
MapWithPolylines({
required this.startLatLng,
required this.endLatLng,
Key? key,
}) : super(key: key);
final mapController = Get.put(MapController());
Set<Polyline> _createPolylines() {
return {
Polyline(
polylineId: const PolylineId('route1'),
visible: true,
points: [startLatLng, endLatLng],
color: Colors.blue,
width: 5,
),
};
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
Obx(() => GoogleMap(
initialCameraPosition: CameraPosition(
target: startLatLng,
zoom: mapController.zoom.value,
),
polylines: _createPolylines(),
markers: {
Marker(markerId: const MarkerId("start"), position: startLatLng),
Marker(markerId: const MarkerId("end"), position: endLatLng),
},
onMapCreated: (controller) {
mapController.setController(controller);
},
)),
Positioned(
top: 20,
right: 10,
child: Column(
children: [
FloatingActionButton(
mini: true,
backgroundColor: Colors.white,
onPressed: mapController.zoomIn,
child: const Icon(Icons.add, color: Colors.black),
),
const SizedBox(height: 8),
FloatingActionButton(
mini: true,
backgroundColor: Colors.white,
onPressed: mapController.zoomOut,
child: const Icon(Icons.remove, color: Colors.black),
),
],
),
),
Positioned(
top: 20,
left: 10,
child: FloatingActionButton(
mini: true,
backgroundColor: Colors.white,
child: Icon(Icons.arrow_back, color: Colors.black),
onPressed: () {
Get.back();
}
)
),
],
);
}
}
class DeliveryInfoCard extends StatelessWidget {
final String deliveryDate;
final String tenantName;
final String orderId;
final String contactNumber;
final VoidCallback onPhoneTap;
final Color primaryColor;
const DeliveryInfoCard({
super.key,
required this.deliveryDate,
required this.tenantName,
required this.orderId,
required this.contactNumber,
required this.onPhoneTap,
required this.primaryColor,
});
@override
Widget build(BuildContext context) {
final date = DateFormat("yyyy-MM-dd").parse(deliveryDate);
final dateTime = DateFormat("yyyy-MM-ddTHH:mm:ss").parse(deliveryDate);
return Container(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: const [
BoxShadow(
color: Colors.black12,
blurRadius: 6,
offset: Offset(0, 2),
),
],
),
child: SizedBox(
height: 100,
child: Row(
children: [
/// LEFT SIDE: DATE
Container(
width: 80,
decoration: BoxDecoration(
color: primaryColor,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(12),
bottomLeft: Radius.circular(12),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Text(
DateFormat("dd").format(date),
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const SizedBox(height: 2),
Text(
DateFormat("MMM").format(date),
style: TextStyle(
fontSize: 14,
color: Colors.grey[600],
fontWeight: FontWeight.w600,
),
),
],
),
),
const SizedBox(height: 6),
Text(
DateFormat("hh:mm a").format(dateTime),
style: const TextStyle(
fontSize: 12,
color: Colors.white,
fontWeight: FontWeight.w500,
),
),
],
),
),
const SizedBox(width: 12),
/// RIGHT SIDE: DETAILS
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildIconText(Icons.person, tenantName, 15),
_buildIconText(Icons.receipt, orderId, 13),
InkWell(
onTap: onPhoneTap,
child: _buildIconText(Icons.phone, contactNumber, 13, isLink: true),
),
],
),
),
),
],
),
),
);
}
Widget _buildIconText(IconData icon, String text, double fontSize, {bool isLink = false}) {
return Row(
children: [
Icon(icon, color: Colors.black45, size: 18),
const SizedBox(width: 6),
Expanded(
child: Text(
text,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: fontSize,
color: isLink ? Colors.blue : Colors.black87,
fontWeight: FontWeight.w500,
decoration: isLink ? TextDecoration.underline : TextDecoration.none,
),
),
),
],
);
}
}
class DeliveryCard extends StatelessWidget {
final dynamic data;
final bool isFromSummary;
const DeliveryCard({super.key, required this.data, this.isFromSummary = false});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(12),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
elevation: 0,
child: Padding(
padding: const EdgeInsets.all(12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Timeline: Pickup icon, dotted line, Drop icon
SizedBox(
height: 190, // <-- match the combined height of your content
child: Column(
children: [
_circleIcon(FontAwesomeIcons.mapMarkerAlt as IconData, isFromSummary ? Colors.red : Colors.green),
Expanded(child: _verticalDottedLine()),
_circleIcon((isFromSummary ? FontAwesomeIcons.checkCircle : FontAwesomeIcons.mapMarkerAlt) as IconData, isFromSummary ? Colors.green : Colors.red),
],
),
),
const SizedBox(width: 12),
/// Content Block
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoBlock(
label: "Pickup",
name: data?.pickupcustomer ?? '',
address: data?.pickupaddress ?? '',
contact: data?.pickupcontactno ?? '',
lat: data?.pickuplat,
lon: data?.pickuplon,
isPickup: true,
),
const SizedBox(height: 20),
_buildInfoBlock(
label: isFromSummary ? "Delivered" : "Drop",
name: data?.deliverycustomer ?? '',
address: data?.deliveryaddress ?? '',
contact: data?.deliverycontactno ?? '',
lat: data?.droplat,
lon: data?.droplon,
isPickup: false,
),
],
),
),
],
),
),
);
}
Widget _circleIcon(IconData icon, Color color) {
return Container(
height: 38,
width: 38,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 3)],
),
child: FaIcon(icon as FaIconData?, color: color, size: 20),
);
}
Widget _verticalDottedLine({double height = 60}) {
return SizedBox(
height: height,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(
(height ~/ 6),
(index) => Container(
width: 1,
height: 4,
color: Colors.grey[400],
),
),
),
);
}
Widget _buildInfoBlock({
required String label,
required String name,
required String address,
required String contact,
required String? lat,
required String? lon,
required bool isPickup,
}) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
const SizedBox(height: 6),
_infoRow(Icons.person, name),
const SizedBox(height: 4),
_infoRow(Icons.location_on, address, maxLines: 2),
const SizedBox(height: 4),
InkWell(
onTap: () => Utility.openPhoneCallApp(contact),
child: _infoRow(Icons.phone, contact),
),
const SizedBox(height: 6),
InkWell(
onTap: () {
Utility.openMap(
double.tryParse(lat ?? '0') ?? 0,
double.tryParse(lon ?? '0') ?? 0,
);
},
child: const Row(
children: [
Icon(Icons.assistant_direction_rounded,
color: ColorConstants.primaryColor, size: 20),
SizedBox(width: 6),
Text(
"Navigate",
style: TextStyle(
color: ColorConstants.primaryColor,
fontWeight: FontWeight.w500,
),
)
],
),
),
],
);
}
Widget _infoRow(IconData icon, String text, {int maxLines = 1}) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(icon, size: 16, color: Colors.black45),
const SizedBox(width: 6),
Expanded(
child: Text(
text,
maxLines: maxLines,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.black87,
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
],
);
}
}