25-12-1/1

This commit is contained in:
Hamza-Ayed
2025-12-01 07:52:54 +03:00
parent b1b8efdd7d
commit 9b1008a0bf
40 changed files with 2471 additions and 2039 deletions

View File

@@ -1,37 +1,43 @@
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/constant/colors.dart';
import 'package:sefer_driver/constant/info.dart';
import 'package:sefer_driver/controller/firebase/firbase_messge.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 '../../../../print.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
// Changed: إعادة تصميم كاملة لتصبح شريط معلومات علوي مدمج
class PassengerInfoWindow extends StatelessWidget {
PassengerInfoWindow({super.key});
final fcm = Get.isRegistered<FirebaseMessagesController>()
? Get.find<FirebaseMessagesController>()
: Get.put(FirebaseMessagesController());
// 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<MapDriverController>(
builder: (controller) => AnimatedPositioned(
duration: const Duration(milliseconds: 400),
curve: Curves.easeInOut,
// Changed: تم تغيير الموضع من الأسفل إلى الأعلى
top: controller.isPassengerInfoWindow ? 15.0 : -200.0,
// 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(
elevation: 8,
shadowColor: Colors.black.withOpacity(0.3),
// 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),
),
@@ -41,14 +47,12 @@ class PassengerInfoWindow extends StatelessWidget {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// New: صف علوي للمعلومات الأساسية
_buildTopInfoRow(controller),
const Divider(height: 16),
// Changed: الأزرار الآن في صف أفقي ومدمج
if (!controller.isRideBegin) _buildActionButtons(controller),
// New: مؤشر انتظار الراكب المدمج
// Optimization: Only render linear indicator if needed
if (controller.remainingTimeInPassengerLocatioWait < 300 &&
controller.remainingTimeInPassengerLocatioWait != 0 &&
!controller.isRideBegin) ...[
@@ -56,7 +60,6 @@ class PassengerInfoWindow extends StatelessWidget {
_buildWaitingIndicator(controller),
],
// زر الإلغاء بعد انتهاء وقت الانتظار
if (controller.isdriverWaitTimeEnd &&
!controller.isRideBegin) ...[
const SizedBox(height: 10),
@@ -70,35 +73,33 @@ class PassengerInfoWindow extends StatelessWidget {
);
}
// New: ودجت لعرض المعلومات العلوية بشكل مدمج
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(
'Go to passenger:'.tr,
style: AppStyle.title
.copyWith(color: Colors.grey[600], fontSize: 13),
),
Text(
controller.passengerName,
style: AppStyle.title
.copyWith(fontWeight: FontWeight.bold, fontSize: 18),
controller.passengerName ?? 'loading...',
style: _valueStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
// معلومات المسافة والزمن
Row(
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(width: 8),
const SizedBox(height: 6), // Vertical spacing
_buildInfoChip(
Icons.timer_outlined,
controller.hours > 1
@@ -111,10 +112,9 @@ class PassengerInfoWindow extends StatelessWidget {
);
}
// New: ودجت مخصص لعرض المعلومات بشكل أنيق
Widget _buildInfoChip(IconData icon, String text) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: AppColor.primaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
@@ -122,144 +122,164 @@ class PassengerInfoWindow extends StatelessWidget {
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: AppColor.primaryColor, size: 16),
const SizedBox(width: 4),
Text(text,
style: TextStyle(
color: AppColor.primaryColor, fontWeight: FontWeight.bold)),
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
),
),
],
),
);
}
// Changed: إعادة تصميم أزرار الإجراءات لتكون أكثر دمجًا
Widget _buildActionButtons(MapDriverController controller) {
return Row(
children: [
if (controller.isArrivedSend)
Expanded(
child: ElevatedButton.icon(
icon: const Icon(Icons.location_on, size: 18),
label: Text('I Arrive'.tr),
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.yellowColor,
foregroundColor: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
),
onPressed: () async {
controller.getRoute(
origin: controller.latLngPassengerLocation,
destination: controller.latLngPassengerDestination,
routeColor: Colors.blue // أو أي لون
);
if (await controller
.calculateDistanceBetweenDriverAndPassengerLocation() <
140) {
// fcm.sendNotificationToDriverMAP(
// 'Hi ,I Arrive your site',
// 'I Arrive at your site'.tr,
// controller.tokenPassenger,
// [],
// 'ding.wav',
// );
Log.print(
'controller.tokenPassenger: ${controller.tokenPassenger}');
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();
NotificationService.sendNotification(
target: controller.tokenPassenger.toString(),
title: 'Hi ,I Arrive your site'.tr,
body: 'I Arrive at your site'.tr,
isTopic: false, // Important: this is a token
tone: 'ding',
driverList: [], category: 'Hi ,I Arrive your site',
);
controller.startTimerToShowDriverWaitPassengerDuration();
controller.isArrivedSend = false;
} else {
MyDialog().getDialog(
'You are not near the passenger location'.tr,
'Please go to the pickup location exactly'.tr,
() => Get.back());
}
},
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,
child: ElevatedButton.icon(
icon: const Icon(Icons.play_arrow_rounded, size: 20),
label: Text('Start the Ride'.tr,
style: const TextStyle(fontWeight: FontWeight.bold)),
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.greenColor,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
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))),
],
),
),
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();
},
);
},
),
),
],
);
}
// Changed: مؤشر الانتظار الآن أكثر دمجًا
Widget _buildWaitingIndicator(MapDriverController controller) {
return ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Stack(
alignment: Alignment.center,
children: [
LinearProgressIndicator(
backgroundColor: AppColor.greyColor.withOpacity(0.3),
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: 25,
minHeight: 8, // Thinner looks more modern
value: controller.progressInPassengerLocationFromDriver.toDouble(),
),
Text(
controller.stringRemainingTimeWaitingPassenger,
style: AppStyle.title.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 13,
shadows: [
Shadow(color: Colors.black.withOpacity(0.5), blurRadius: 2)
]),
),
const SizedBox(height: 4),
Text(
"${'Waiting'.tr}: ${controller.stringRemainingTimeWaitingPassenger}",
style: AppStyle.title.copyWith(
color: Colors.grey[700],
fontWeight: FontWeight.bold,
fontSize: 12,
),
],
),
),
],
);
}
// New: زر الإلغاء بعد انتهاء الانتظار
Widget _buildCancelAfterWaitButton(MapDriverController controller) {
return MyElevatedButton(
title: 'You Can Cancel the Trip and get Cost From '.tr +
AppInformation.appName.tr,
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 to the driver, or it will be deducted from your next trip',
isTopic: false, // Important: this is a token
body: 'You will need to pay the cost...',
isTopic: false,
tone: 'cancel',
driverList: [], category: 'Driver Cancelled Your Trip',
driverList: [],
category: 'Driver Cancelled Your Trip',
);
box.write(BoxName.rideStatus, 'Cancel');
await controller.addWaitingTimeCostFromPassengerToDriverWallet();