import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'dart:math'; import '../../constant/box_name.dart'; import '../../constant/colors.dart'; import '../../constant/links.dart'; import '../../constant/style.dart'; import '../../controller/firebase/firbase_messge.dart'; import '../../controller/firebase/notification_service.dart'; import '../../controller/functions/crud.dart'; import '../../controller/home/captin/home_captain_controller.dart'; import '../../controller/notification/ride_available_controller.dart'; import '../../main.dart'; import '../home/Captin/driver_map_page.dart'; import '../widgets/my_scafold.dart'; import '../widgets/mycircular.dart'; import '../widgets/mydialoug.dart'; // --- Placeholder Classes and Variables (for demonstration) --- // These are dummy implementations to make the code runnable. // You should use your actual project files. // --- End of Placeholder Classes --- class AvailableRidesPage extends StatelessWidget { const AvailableRidesPage({super.key}); @override Widget build(BuildContext context) { // Use findOrPut to avoid re-creating the controller on rebuilds Get.lazyPut(() => RideAvailableController()); Get.lazyPut(() => HomeCaptainController()); return GetBuilder( builder: (rideAvailableController) { // rideAvailableController.sortRidesByDistance(); // Original logic return MyScafolld( title: 'Available for rides'.tr, body: [ rideAvailableController.isLoading ? const MyCircularProgressIndicator() : Builder( builder: (context) { // Filtering logic remains the same final filteredRides = rideAvailableController .rideAvailableMap['message'] .where((rideInfo) { var driverType = box.read(BoxName.carTypeOfDriver).toString(); switch (driverType) { case 'Comfort': return ['Speed', 'Comfort'] .contains(rideInfo['carType']); case 'Speed': case 'Scooter': case 'Awfar Car': return rideInfo['carType'] == driverType; case 'Lady': return ['Comfort', 'Speed', 'Lady'] .contains(rideInfo['carType']); default: return false; } }).toList(); if (filteredRides.isEmpty) { return Center( child: Text( "No rides available for your vehicle type.".tr, style: AppStyle.subtitle, ), ); } return ListView.builder( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 16), itemCount: filteredRides.length, itemBuilder: (context, index) { return RideAvailableCard( rideInfo: filteredRides[index], ); }, ); }, ) ], isleading: true); }); } } class RideAvailableCard extends StatelessWidget { final Map rideInfo; const RideAvailableCard({Key? key, required this.rideInfo}) : super(key: key); @override Widget build(BuildContext context) { // The main card with improved styling return Card( margin: const EdgeInsets.only(bottom: 16.0), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), elevation: 5, shadowColor: Colors.black.withOpacity(0.1), child: InkWell( borderRadius: BorderRadius.circular(16), onTap: () { // You can add an action here, e.g., show ride details on a map }, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHeader(), const SizedBox(height: 16), _buildRouteInfo(), const Divider(height: 32), _buildRideDetails(), const SizedBox(height: 20), _buildAcceptButton(), ], ), ), ), ); } // Header section with Price and Car Type Widget _buildHeader() { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Fare'.tr, style: AppStyle.subtitle.copyWith(fontSize: 12)), const SizedBox(height: 4), Text('${rideInfo['price']} \$', style: AppStyle.title .copyWith(fontSize: 24, color: AppColor.primaryColor)), ], ), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: AppColor.greenColor.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Text( rideInfo['carType'], style: AppStyle.title .copyWith(color: AppColor.greenColor, fontSize: 12), ), ), ], ); } // Visual representation of the pickup and dropoff route Widget _buildRouteInfo() { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Dotted line and icons column Column( children: [ const Icon(CupertinoIcons.circle_fill, color: AppColor.greenColor, size: 20), ...List.generate( 4, (index) => Container( height: 4, width: 2, color: AppColor.writeColor, margin: const EdgeInsets.symmetric(vertical: 2), )), const Icon(CupertinoIcons.location_solid, color: Colors.red, size: 20), ], ), const SizedBox(width: 16), // Location text column Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildLocationText(rideInfo['startName'], 'Pickup'.tr), const SizedBox(height: 20), _buildLocationText(rideInfo['endName'], 'Dropoff'.tr), ], ), ) ], ); } // Helper for location text Widget _buildLocationText(String location, String label) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text(label, style: AppStyle.subtitle.copyWith(fontSize: 12)), const SizedBox(height: 2), Text( location, style: AppStyle.title.copyWith(fontWeight: FontWeight.normal), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ); } // Ride details section with Distance and Passenger Rating Widget _buildRideDetails() { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _buildInfoChip( icon: CupertinoIcons.map_pin_ellipse, value: '${rideInfo['distance']} ${'KM'.tr}', label: 'Distance'.tr, color: AppColor.primaryColor, ), _buildInfoChip( icon: CupertinoIcons.star_fill, value: '${rideInfo['passengerRate']}', label: 'Rating'.tr, color: Colors.amber, ), ], ); } // A reusable chip for displaying info with an icon Widget _buildInfoChip( {required IconData icon, required String value, required String label, required Color color}) { return Column( children: [ Row( children: [ Icon(icon, color: color, size: 16), const SizedBox(width: 8), Text(value, style: AppStyle.title), ], ), const SizedBox(height: 4), Text(label, style: AppStyle.subtitle.copyWith(fontSize: 12)), ], ); } // The accept button with improved styling Widget _buildAcceptButton() { return SizedBox( width: double.infinity, child: ElevatedButton.icon( icon: const Icon(Icons.check_circle_outline, color: Colors.white), label: Text('Accept'.tr, style: const TextStyle( color: Colors.white, fontWeight: FontWeight.bold)), onPressed: _acceptRide, style: ElevatedButton.styleFrom( backgroundColor: AppColor.greenColor, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 2, ), ), ); } // --- Ride Acceptance Logic --- // This logic is copied exactly from your original code. void _acceptRide() async { var res = await CRUD().post(link: AppLink.updateStausFromSpeed, payload: { 'id': rideInfo['id'], 'rideTimeStart': DateTime.now().toString(), 'status': 'Apply', 'driver_id': box.read(BoxName.driverID), }); if (AppLink.endPoint.toString() != AppLink.seferCairoServer) { CRUD().post( link: '${AppLink.endPoint}rides/updateStausFromSpeed.php', payload: { 'id': rideInfo['id'], 'rideTimeStart': DateTime.now().toString(), 'status': 'Apply', 'driver_id': box.read(BoxName.driverID), }); } if (res != "failure") { List bodyToPassenger = [ box.read(BoxName.driverID).toString(), box.read(BoxName.nameDriver).toString(), box.read(BoxName.tokenDriver).toString(), ]; box.write(BoxName.statusDriverLocation, 'on'); await CRUD().postFromDialogue(link: AppLink.addDriverOrder, payload: { 'driver_id': box.read(BoxName.driverID), 'order_id': rideInfo['id'], 'status': 'Apply' }); await CRUD().post(link: AppLink.updateRides, payload: { 'id': rideInfo['id'], 'DriverIsGoingToPassenger': DateTime.now().toString(), 'status': 'Applied' }); await CRUD().post( link: AppLink.updateWaitingRide, payload: {'id': rideInfo['id'], 'status': 'Applied'}); if (AppLink.endPoint.toString() != AppLink.seferCairoServer) { CRUD().postFromDialogue( link: '${AppLink.endPoint}/driver_order/add.php', payload: { 'driver_id': box.read(BoxName.driverID), 'order_id': rideInfo['id'], 'status': 'Apply' }); CRUD().post(link: '${AppLink.endPoint}/rides/update.php', payload: { 'id': rideInfo['id'], 'DriverIsGoingToPassenger': DateTime.now().toString(), 'status': 'Applied' }); CRUD().post( link: "${AppLink.endPoint}/ride/notificationCaptain/updateWaitingTrip.php", payload: {'id': rideInfo['id'], 'status': 'Applied'}); } // FirebaseMessagesController().sendNotificationToPassengerToken( // "Accepted Ride".tr, // 'your ride is Accepted'.tr, // rideInfo['passengerToken'].toString(), // bodyToPassenger, // 'start.wav'); NotificationService.sendNotification( target: rideInfo['passengerToken'].toString(), title: 'Accepted Ride'.tr, body: 'your ride is Accepted'.tr, isTopic: false, // Important: this is a token tone: 'start', driverList: [], category: 'Accepted Ride', ); Get.back(); Get.to(() => PassengerLocationMapPage(), arguments: { 'passengerLocation': rideInfo['start_location'].toString(), 'passengerDestination': rideInfo['end_location'].toString(), 'Duration': rideInfo['duration'].toString(), 'totalCost': rideInfo['price'].toString(), 'Distance': rideInfo['distance'].toString(), 'name': rideInfo['first_name'].toString(), 'phone': rideInfo['phone'].toString(), 'email': rideInfo['email'].toString(), 'WalletChecked': rideInfo['payment_method'].toString(), 'tokenPassenger': rideInfo['passengerToken'].toString(), 'direction': 'https://www.google.com/maps/dir/${rideInfo['start_location']}/${rideInfo['end_location']}/', 'DurationToPassenger': rideInfo['duration'].toString(), 'rideId': rideInfo['id'].toString(), 'passengerId': rideInfo['passenger_id'].toString(), 'driverId': box.read(BoxName.driverID).toString(), 'durationOfRideValue': rideInfo['duration'].toString(), 'paymentAmount': rideInfo['price'].toString(), 'paymentMethod': 'cash'.toString() == 'true' ? 'visa' : 'cash', 'isHaveSteps': 'startEnd'.toString(), 'step0': ''.toString(), 'step1': ''.toString(), 'step2': ''.toString(), 'step3': ''.toString(), 'step4': ''.toString(), 'passengerWalletBurc': rideInfo['bruc'].toString(), 'timeOfOrder': DateTime.now().toString(), 'totalPassenger': rideInfo['price'].toString(), 'carType': rideInfo['carType'].toString(), 'kazan': Get.find().kazan.toString(), }); } else { MyDialog().getDialog( "This ride is already taken by another driver.".tr, '', () { CRUD().post( link: AppLink.deleteAvailableRide, payload: {'id': rideInfo['id']}); if (AppLink.endPoint.toString() != AppLink.seferCairoServer) { CRUD().post( link: '${AppLink.endPoint}/ride/notificationCaptain/deleteAvailableRide.php', payload: {'id': rideInfo['id']}); } Get.back(); }); } } }