import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:sefer_driver/constant/colors.dart'; import 'package:sefer_driver/controller/home/captin/map_driver_controller.dart'; import 'package:sefer_driver/views/widgets/elevated_btn.dart'; import '../../../../constant/box_name.dart'; import '../../../../constant/style.dart'; import '../../../../controller/firebase/notification_service.dart'; import '../../../../main.dart'; import 'package:sefer_driver/views/widgets/mydialoug.dart'; class PassengerInfoWindow extends StatelessWidget { PassengerInfoWindow({super.key}); // Optimization: defining static styles here avoids rebuilding them every frame final TextStyle _labelStyle = AppStyle.title.copyWith(color: Colors.grey[600], fontSize: 13); final TextStyle _valueStyle = AppStyle.title.copyWith(fontWeight: FontWeight.bold, fontSize: 18); @override Widget build(BuildContext context) { // Get safe area top padding (for Notches/Status bars) final double topPadding = MediaQuery.of(context).padding.top; final double topMargin = topPadding + 10; // Safe area + 10px spacing return GetBuilder( builder: (controller) => AnimatedPositioned( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, // FIX: Use calculated top margin to avoid hiding behind status bar top: controller.isPassengerInfoWindow ? topMargin : -250.0, left: 15.0, right: 15.0, child: Card( // Optimization: Lower elevation slightly for smoother animation on cheap phones elevation: 4, shadowColor: Colors.black.withOpacity(0.2), color: Colors.white, surfaceTintColor: Colors.white, // Fix for Material 3 tinting shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildTopInfoRow(controller), const Divider(height: 16), if (!controller.isRideBegin) _buildActionButtons(controller), // Optimization: Only render linear indicator if needed if (controller.remainingTimeInPassengerLocatioWait < 300 && controller.remainingTimeInPassengerLocatioWait != 0 && !controller.isRideBegin) ...[ const SizedBox(height: 10), _buildWaitingIndicator(controller), ], if (controller.isdriverWaitTimeEnd && !controller.isRideBegin) ...[ const SizedBox(height: 10), _buildCancelAfterWaitButton(controller), ] ], ), ), ), ), ); } Widget _buildTopInfoRow(MapDriverController controller) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, // Align top children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Go to passenger:'.tr, style: _labelStyle), const SizedBox(height: 2), Text( controller.passengerName ?? 'loading...', style: _valueStyle, maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), const SizedBox(width: 10), // Spacing between name and chips Column( // Changed to Column for better layout on small screens crossAxisAlignment: CrossAxisAlignment.end, children: [ _buildInfoChip(Icons.map_outlined, '${controller.distance} km'), const SizedBox(height: 6), // Vertical spacing _buildInfoChip( Icons.timer_outlined, controller.hours > 1 ? '${controller.hours}h ${controller.minutes}m' : '${controller.minutes}m', ), ], ), ], ); } Widget _buildInfoChip(IconData icon, String text) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.1), borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, color: AppColor.primaryColor, size: 14), // Smaller icon const SizedBox(width: 6), Text( text, style: TextStyle( color: AppColor.primaryColor, fontWeight: FontWeight.bold, fontSize: 12 // Slightly smaller font for chips ), ), ], ), ); } Widget _buildActionButtons(MapDriverController controller) { return Row( children: [ if (controller.isArrivedSend) Expanded( flex: 1, child: SizedBox( height: 45, // Fixed height for consistency child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppColor.yellowColor, foregroundColor: Colors.black, padding: EdgeInsets.zero, // Reduce padding to fit text shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), onPressed: () async { // LOGIC FIX: Check distance FIRST double distance = await controller .calculateDistanceBetweenDriverAndPassengerLocation(); if (distance < 140) { // Only draw route and send notif if close enough controller.getRoute( origin: controller.latLngPassengerLocation, destination: controller.latLngPassengerDestination, routeColor: Colors.blue); NotificationService.sendNotification( target: controller.tokenPassenger.toString(), title: 'Hi ,I Arrive your site'.tr, body: 'I Arrive at your site'.tr, isTopic: false, tone: 'ding', driverList: [], category: 'Hi ,I Arrive your site', ); controller.startTimerToShowDriverWaitPassengerDuration(); controller.isArrivedSend = false; } else { MyDialog().getDialog( 'You are not near'.tr, // Shortened title 'Please go to the pickup location exactly'.tr, () => Get.back()); } }, // Using Row instead of .icon constructor for better control child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.location_on, size: 16), const SizedBox(width: 4), Flexible( child: Text('I Arrive'.tr, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12))), ], ), ), ), ), if (controller.isArrivedSend) const SizedBox(width: 8), Expanded( flex: 2, // Give "Start" button more space child: SizedBox( height: 45, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppColor.greenColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), ), onPressed: () { MyDialog().getDialog( "Is the Passenger in your Car?".tr, "Don't start trip if passenger not in your car".tr, () async { await controller.startRideFromDriver(); Get.back(); }, ); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.play_arrow_rounded, size: 22), const SizedBox(width: 6), Flexible( child: Text('Start the Ride'.tr, overflow: TextOverflow.ellipsis, style: const TextStyle(fontWeight: FontWeight.bold))), ], ), ), ), ), ], ); } Widget _buildWaitingIndicator(MapDriverController controller) { return Column( children: [ ClipRRect( borderRadius: BorderRadius.circular(10), child: LinearProgressIndicator( backgroundColor: AppColor.greyColor.withOpacity(0.2), // Ternary for color is fine color: controller.remainingTimeInPassengerLocatioWait < 60 ? AppColor.redColor : AppColor.greenColor, minHeight: 8, // Thinner looks more modern value: controller.progressInPassengerLocationFromDriver.toDouble(), ), ), const SizedBox(height: 4), Text( "${'Waiting'.tr}: ${controller.stringRemainingTimeWaitingPassenger}", style: AppStyle.title.copyWith( color: Colors.grey[700], fontWeight: FontWeight.bold, fontSize: 12, ), ), ], ); } Widget _buildCancelAfterWaitButton(MapDriverController controller) { return MyElevatedButton( title: 'Cancel Trip & Get Cost'.tr, // Shortened text kolor: AppColor.gold, onPressed: () { MyDialog().getDialog('Are you sure to cancel?'.tr, '', () async { NotificationService.sendNotification( target: controller.tokenPassenger.toString(), title: 'Driver Cancelled Your Trip'.tr, body: 'You will need to pay the cost...', isTopic: false, tone: 'cancel', driverList: [], category: 'Driver Cancelled Your Trip', ); box.write(BoxName.rideStatus, 'Cancel'); await controller.addWaitingTimeCostFromPassengerToDriverWallet(); controller.isdriverWaitTimeEnd = false; Get.back(); }); }, ); } }