import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:sefer_driver/constant/box_name.dart'; import 'package:sefer_driver/constant/style.dart'; import 'package:sefer_driver/views/widgets/elevated_btn.dart'; import 'package:sefer_driver/controller/home/captin/map_driver_controller.dart'; import '../../../constant/colors.dart'; import '../../../controller/functions/location_controller.dart'; import '../../../main.dart'; import '../../Rate/rate_passenger.dart'; import '../../widgets/my_textField.dart'; import 'mapDriverWidgets/driver_end_ride_bar.dart'; import 'mapDriverWidgets/google_driver_map_page.dart'; import 'mapDriverWidgets/google_map_app.dart'; import 'mapDriverWidgets/passenger_info_window.dart'; import 'mapDriverWidgets/sos_connect.dart'; import 'mapDriverWidgets/sped_circle.dart'; class PassengerLocationMapPage extends StatelessWidget { PassengerLocationMapPage({super.key}); final LocationController locationController = Get.put(LocationController()); final MapDriverController mapDriverController = Get.put(MapDriverController()); // دالة ديالوج الخروج Future showExitDialog() async { bool? result = await Get.defaultDialog( title: "Warning".tr, titleStyle: AppStyle.title.copyWith(color: AppColor.redColor), middleText: "Active ride in progress. Leaving might stop tracking. Exit?".tr, barrierDismissible: false, radius: 15, confirm: MyElevatedButton( title: 'Stay'.tr, kolor: AppColor.greenColor, onPressed: () => Get.back(result: false)), cancel: MyElevatedButton( title: 'Exit'.tr, kolor: AppColor.redColor, onPressed: () => Get.back(result: true)), ); return result ?? false; } @override Widget build(BuildContext context) { WidgetsBinding.instance.addPostFrameCallback((_) { if (Get.arguments != null && Get.arguments is Map) { mapDriverController.argumentLoading(); mapDriverController.startTimerToShowPassengerInfoWindowFromDriver(); // 2. فرض التحديث لكل المعرفات (IDs) لضمان ظهورها // لأن argumentLoading قد تستدعي update() العادية التي لا تؤثر على هؤلاء mapDriverController .update(['PassengerInfo', 'DriverEndBar', 'SosConnect']); } }); return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) async { if (didPop) return; final shouldExit = await showExitDialog(); if (shouldExit) Get.back(); }, child: Scaffold( resizeToAvoidBottomInset: false, body: Stack( children: [ // 1. الخريطة (الخلفية) Positioned.fill( child: GoogleDriverMap(locationController: locationController)), // 2. واجهة المستخدم (فوق الخريطة) SafeArea( child: Stack( children: [ // أ) زر الإلغاء (أعلى اليسار) CancelWidget(mapDriverController: mapDriverController), // ب) شريط إنهاء الرحلة (أعلى الوسط) Positioned( top: 0, left: 0, right: 0, child: SafeArea(child: driverEndRideBar())), // ج) شريط التعليمات الملاحية (الأسفل) const InstructionsOfRoads(), // د) نافذة معلومات الراكب (تعلو التعليمات ديناميكياً) const PassengerInfoWindow(), // SpeedCircle(), Positioned( right: 16, bottom: 20, // أو أي مسافة تناسبك child: GetBuilder( // id: 'SosConnect', // لتحديث الزر عند بدء الرحلة builder: (controller) { // حساب الهوامش ديناميكياً لرفع الأزرار فوق النوافذ السفلية double bottomPadding = 0; if (controller.currentInstruction.isNotEmpty) bottomPadding += 120; if (controller.isPassengerInfoWindow) bottomPadding += 220; return AnimatedContainer( duration: const Duration(milliseconds: 300), margin: EdgeInsets.only(bottom: bottomPadding), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, children: [ SosConnect(), // ويدجت نظيفة const SizedBox(height: 12), const GoogleMapApp(), // ويدجت نظيفة ], ), ); }, ), ), ], ), ), // 3. النوافذ المنبثقة (Overlay) const PricesWindow(), ], ), ), ); } } // --------------------------------------------------------------------------- // 1. ويدجت شريط التعليمات (InstructionsOfRoads) // --------------------------------------------------------------------------- class InstructionsOfRoads extends StatelessWidget { const InstructionsOfRoads({super.key}); @override Widget build(BuildContext context) { return Positioned( bottom: 20, left: 15, right: 15, child: GetBuilder( builder: (controller) { // إخفاء الشريط إذا لم يكن هناك تعليمات if (controller.currentInstruction.isEmpty) return const SizedBox(); return TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: const Duration(milliseconds: 500), builder: (context, value, child) { return Transform.translate( offset: Offset(0, 50 * (1 - value)), // حركة انزلاق child: Opacity( opacity: value, child: Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12), decoration: BoxDecoration( color: const Color(0xFF1F1F1F) .withOpacity(0.95), // خلفية داكنة borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.4), blurRadius: 15, offset: const Offset(0, 5)), ], border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Row( children: [ // أيقونة الاتجاه Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppColor.primaryColor, shape: BoxShape.circle, ), child: const Icon(Icons.turn_right_rounded, color: Colors.white, size: 24), ), const SizedBox(width: 14), // نص التعليمات Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "NEXT STEP".tr, style: TextStyle( color: Colors.grey.shade500, fontSize: 10, fontWeight: FontWeight.bold, letterSpacing: 1.2), ), const SizedBox(height: 2), Text( controller.currentInstruction, style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, height: 1.2), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), // فاصل عمودي Container( width: 1, height: 30, color: Colors.white12, margin: const EdgeInsets.symmetric(horizontal: 10)), // زر التحكم بالصوت Material( color: Colors.transparent, child: InkWell( onTap: () => controller.toggleTts(), borderRadius: BorderRadius.circular(20), child: Padding( padding: const EdgeInsets.all(8.0), child: Icon( controller.isTtsEnabled ? Icons.volume_up_rounded : Icons.volume_off_rounded, color: controller.isTtsEnabled ? AppColor.greenColor : Colors.grey, size: 24, ), ), ), ), ], ), ), ), ); }, ); }, ), ); } } // --------------------------------------------------------------------------- // 2. ويدجت زر الإلغاء (CancelWidget) - كامل // --------------------------------------------------------------------------- class CancelWidget extends StatelessWidget { const CancelWidget({super.key, required this.mapDriverController}); final MapDriverController mapDriverController; @override Widget build(BuildContext context) { return Positioned( top: 10, left: 15, child: GetBuilder(builder: (controller) { // نخفي الزر إذا انتهت الرحلة if (controller.isRideFinished) return const SizedBox(); return ClipRRect( borderRadius: BorderRadius.circular(30), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.9), borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 8) ], ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(30), onTap: () => _showCancelDialog(context, controller), child: const Padding( padding: EdgeInsets.all(10.0), child: Icon(Icons.close_rounded, color: AppColor.redColor, size: 26), ), ), ), ), ), ); }), ); } void _showCancelDialog(BuildContext context, MapDriverController controller) { Get.defaultDialog( title: "Cancel Trip?".tr, titleStyle: AppStyle.title.copyWith(fontWeight: FontWeight.bold), radius: 16, content: Column( children: [ const Icon(Icons.warning_amber_rounded, size: 50, color: Colors.orangeAccent), const SizedBox(height: 10), Text( "Please tell us why you want to cancel.".tr, textAlign: TextAlign.center, style: TextStyle(color: Colors.grey[600]), ), const SizedBox(height: 15), Form( key: controller.formKeyCancel, child: MyTextForm( controller: controller.cancelTripCotroller, label: "Reason".tr, hint: "Write your reason...".tr, type: TextInputType.text, ), ), ], ), confirm: SizedBox( width: 100, child: MyElevatedButton( title: 'Confirm'.tr, kolor: AppColor.redColor, onPressed: () async { // استدعاء دالة الإلغاء من الكنترولر await controller.cancelTripFromDriverAfterApplied(); // Get.back(); // عادة موجودة داخل الدالة في الكنترولر }, ), ), cancel: SizedBox( width: 100, child: TextButton( onPressed: () => Get.back(), child: Text('Back'.tr, style: const TextStyle(color: Colors.grey)), ), ), ); } } // --------------------------------------------------------------------------- // 3. ويدجت نافذة الأسعار (PricesWindow) - كامل // --------------------------------------------------------------------------- class PricesWindow extends StatelessWidget { const PricesWindow({super.key}); @override Widget build(BuildContext context) { return GetBuilder(builder: (controller) { // إخفاء إذا لم تكن مفعلة if (!controller.isPriceWindow) return const SizedBox(); return Container( color: Colors.black.withOpacity(0.6), // خلفية معتمة child: Center( child: TweenAnimationBuilder( tween: Tween(begin: 0.8, end: 1.0), duration: const Duration(milliseconds: 300), curve: Curves.elasticOut, builder: (context, scale, child) { return Transform.scale( scale: scale, child: Container( width: Get.width * 0.85, padding: const EdgeInsets.all(30), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 20, spreadRadius: 5, ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: AppColor.primaryColor.withOpacity(0.1), shape: BoxShape.circle, ), child: Icon(Icons.check_circle_rounded, color: AppColor.primaryColor, size: 50), ), const SizedBox(height: 20), Text( 'Total Price'.tr, style: AppStyle.headTitle2 .copyWith(fontSize: 18, color: Colors.grey[600]), ), const SizedBox(height: 10), Text( '${controller.totalCost} ${'\$'.tr}', style: AppStyle.headTitle2.copyWith( color: Colors.black87, fontSize: 42, fontWeight: FontWeight.w900, ), ), const SizedBox(height: 30), SizedBox( width: double.infinity, height: 55, child: MyElevatedButton( title: 'Collect Payment'.tr, kolor: AppColor.primaryColor, onPressed: () { // الذهاب لصفحة التقييم Get.to(() => RatePassenger(), arguments: { 'rideId': controller.rideId, 'passengerId': controller.passengerId, 'driverId': controller.driverId, 'price': controller.paymentAmount, 'walletChecked': controller.walletChecked }); }, ), ), ], ), ), ); }, ), ), ); }); } }