Files
intaleq_driver/lib/views/home/Captin/mapDriverWidgets/passenger_info_window.dart
Hamza-Ayed 3c0ae4cf2f 26-1-20/1
2026-01-20 10:11:10 +03:00

393 lines
16 KiB
Dart
Executable File

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 '../../../../constant/style.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import '../../../../controller/functions/launch.dart';
import '../../../../controller/functions/location_controller.dart';
import '../../../widgets/error_snakbar.dart';
class PassengerInfoWindow extends StatelessWidget {
const PassengerInfoWindow({super.key});
@override
Widget build(BuildContext context) {
// 1. حساب الهوامش الآمنة (SafeArea) من الأسفل
final double safeBottomPadding = MediaQuery.of(context).padding.bottom;
return GetBuilder<MapDriverController>(
// id: 'PassengerInfo',
builder: (controller) {
// --- 1. تجهيز بيانات العرض ---
String displayName = controller.passengerName ?? "Unknown";
String avatarText = "";
// التحقق من اللغة (عربي/إنجليزي) للاسم المختصر
bool isArabic = RegExp(r'[\u0600-\u06FF]').hasMatch(displayName);
if (displayName.isNotEmpty) {
if (isArabic) {
avatarText = displayName.split(' ').first;
if (avatarText.length > 4) {
avatarText = avatarText.substring(0, 4);
}
} else {
avatarText = displayName[0].toUpperCase();
}
}
// --- 2. المنطق الذكي للموقع (Smart Positioning) ---
// نرفع النافذة إذا ظهر شريط التعليمات في الأسفل لتجنب التغطية
bool hasInstructions = controller.currentInstruction.isNotEmpty;
double instructionsHeight = hasInstructions ? 110.0 : 0.0;
// الموقع النهائي: إذا كانت مفعلة تظهر، وإلا تختفي للأسفل
double finalBottomPosition = controller.isPassengerInfoWindow
? (safeBottomPadding + 10 + instructionsHeight)
: -450.0;
return AnimatedPositioned(
duration: const Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
bottom: finalBottomPosition,
left: 12.0,
right: 12.0,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
blurRadius: 25,
offset: const Offset(0, 8),
spreadRadius: 2,
)
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// --- مقبض السحب (Visual Handle) ---
Center(
child: Container(
margin: const EdgeInsets.only(top: 8, bottom: 4),
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey.shade300,
borderRadius: BorderRadius.circular(10),
),
),
),
Padding(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
child: Column(
children: [
// --- الصف العلوي: معلومات الراكب ---
Row(
children: [
// الصورة الرمزية
Container(
width: 52,
height: 52,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.primaryColor.withOpacity(0.1),
border: Border.all(
color:
AppColor.primaryColor.withOpacity(0.2)),
),
child: Center(
child: Text(
avatarText,
style: TextStyle(
color: AppColor.primaryColor,
fontWeight: FontWeight.bold,
fontSize: isArabic ? 14 : 20,
),
),
),
),
const SizedBox(width: 12),
// النصوص (الاسم والمسافة)
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
displayName,
style: AppStyle.title.copyWith(
fontWeight: FontWeight.w800,
fontSize: 16),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
Icon(Icons.location_on,
size: 14, color: Colors.grey[600]),
const SizedBox(width: 4),
Text(
'${controller.distance} km',
style: TextStyle(
color: Colors.grey[700],
fontSize: 13,
fontWeight: FontWeight.w600),
),
const SizedBox(width: 10),
Icon(Icons.access_time_filled,
size: 14, color: Colors.grey[600]),
const SizedBox(width: 4),
Text(
controller.hours > 0
? '${controller.hours}h ${controller.minutes}m'
: '${controller.minutes} min',
style: TextStyle(
color: Colors.grey[700],
fontSize: 13,
fontWeight: FontWeight.w600),
),
],
),
],
),
),
// أزرار جانبية (سرعة + اتصال)
Row(
children: [
_buildSpeedCircle(),
const SizedBox(width: 10),
InkWell(
onTap: () async {
controller.isSocialPressed = true;
// نفحص النتيجة: هل مسموح له يتصل؟
bool canCall =
await controller.driverCallPassenger();
if (canCall) {
makePhoneCall(
controller.passengerPhone.toString());
} else {
// هنا ممكن تظهر رسالة: تم منع الاتصال بسبب كثرة الإلغاءات
mySnackeBarError(
"You cannot call the passenger due to policy violations"
.tr);
}
},
borderRadius: BorderRadius.circular(50),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
shape: BoxShape.circle,
border: Border.all(
color: Colors.green.withOpacity(0.2)),
),
child: const Icon(Icons.phone,
color: Colors.green, size: 22),
),
),
],
),
],
),
// خط فاصل
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Divider(height: 1, color: Colors.grey.shade100),
),
// --- مؤشر الانتظار (يظهر عند الوصول) ---
if (controller.remainingTimeInPassengerLocatioWait <
300 &&
controller.remainingTimeInPassengerLocatioWait != 0 &&
!controller.isRideBegin) ...[
_buildWaitingIndicator(controller),
const SizedBox(height: 12),
],
// --- الأزرار الرئيسية (وصلت / ابدأ) ---
if (!controller.isRideBegin)
_buildActionButtons(controller),
// --- زر الإلغاء المدفوع (بعد انتهاء وقت الانتظار) ---
if (controller.isdriverWaitTimeEnd &&
!controller.isRideBegin)
Padding(
padding: const EdgeInsets.only(top: 10),
child: SizedBox(
width: double.infinity,
height: 48,
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFFF0F0),
foregroundColor: Colors.red,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(
color: Color(0xFFFFCDCD)),
),
),
onPressed: () {
MyDialog().getDialog(
'Confirm Cancellation'.tr,
'Are you sure you want to cancel and collect the fee?'
.tr, () async {
// كود الإلغاء
Get.back();
controller
.addWaitingTimeCostFromPassengerToDriverWallet();
});
},
icon: const Icon(Icons.money_off, size: 20),
label: Text('Cancel & Collect Fee'.tr,
style: const TextStyle(
fontWeight: FontWeight.bold)),
),
),
),
],
),
),
],
),
),
);
},
);
}
// --- Widgets مساعدة ---
Widget _buildSpeedCircle() {
return GetBuilder<LocationController>(builder: (locController) {
int speedKmh = (locController.speed * 3.6).round();
Color color = speedKmh > 100 ? Colors.red : const Color(0xFF0D47A1);
return Container(
width: 42,
height: 42,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(color: color.withOpacity(0.3), width: 2),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('$speedKmh',
style: TextStyle(
color: color,
fontWeight: FontWeight.w900,
fontSize: 13,
height: 1)),
Text('km/h',
style: TextStyle(
color: color.withOpacity(0.7), fontSize: 8, height: 1)),
],
),
);
});
}
Widget _buildWaitingIndicator(MapDriverController controller) {
bool isUrgent = controller.remainingTimeInPassengerLocatioWait < 60;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.grey.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(Icons.timer_outlined,
size: 16, color: isUrgent ? Colors.red : Colors.green),
const SizedBox(width: 8),
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator(
value:
controller.progressInPassengerLocationFromDriver.toDouble(),
backgroundColor: Colors.grey[200],
color: isUrgent ? Colors.red : Colors.green,
minHeight: 6,
),
),
),
const SizedBox(width: 10),
Text(
controller.stringRemainingTimeWaitingPassenger,
style: TextStyle(
fontWeight: FontWeight.w900,
color: isUrgent ? Colors.red : Colors.green,
fontFamily: 'monospace'),
),
],
),
);
}
Widget _buildActionButtons(MapDriverController controller) {
if (controller.isArrivedSend) {
return SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFF1C40F),
foregroundColor: Colors.white,
elevation: 2,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
onPressed: () async {
await controller.markDriverAsArrived();
},
icon: const Icon(Icons.near_me_rounded),
label: Text('I Have Arrived'.tr,
style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
),
);
} else {
return SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF27AE60),
foregroundColor: Colors.white,
elevation: 2,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
onPressed: () {
MyDialog().getDialog(
"Start Trip?".tr,
"Ensure the passenger is in the car.".tr,
() async {
await controller.startRideFromDriver();
Get.back();
},
);
},
icon: const Icon(Icons.play_circle_fill_rounded),
label: Text('Start Ride'.tr,
style:
const TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
),
);
}
}
}