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 _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, ), ), ), ], ); } }