import 'dart:io'; import 'dart:ui'; import 'package:bubble_head/bubble.dart'; // import 'package:google_maps_flutter/google_maps_flutter.dart'; // import 'package:flutter_map/flutter_map.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; // import 'package:latlong2/latlong.dart' as latlng; // لإحداثيات العرض import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_font_icons/flutter_font_icons.dart'; import 'package:sefer_driver/views/home/Captin/home_captain/drawer_captain.dart'; import 'package:sefer_driver/views/widgets/mycircular.dart'; import '../../../../constant/box_name.dart'; import '../../../../constant/colors.dart'; import '../../../../constant/info.dart'; import '../../../../constant/style.dart'; import '../../../../controller/functions/location_background_controller.dart'; import '../../../../controller/functions/location_controller.dart'; import '../../../../controller/functions/overlay_permisssion.dart'; import '../../../../controller/functions/package_info.dart'; import '../../../../controller/home/captin/home_captain_controller.dart'; import '../../../../controller/home/captin/map_driver_controller.dart'; import '../../../../main.dart'; import '../../../notification/available_rides_page.dart'; import '../../../widgets/circle_container.dart'; import '../driver_map_page.dart'; import 'widget/connect.dart'; import 'widget/left_menu_map_captain.dart'; // ================================================================== // Redesigned Main Widget (V3) // ================================================================== class HomeCaptain extends StatelessWidget { HomeCaptain({super.key}); final LocationController locationController = Get.put(LocationController(), permanent: true); final HomeCaptainController homeCaptainController = Get.put(HomeCaptainController()); @override Widget build(BuildContext context) { // Initial calls remain the same. // Get.put(HomeCaptainController()); WidgetsBinding.instance.addPostFrameCallback((_) async { print("🔥 HomeCaptain postFrameCallback started"); // Debug await closeOverlayIfFound(); await checkForUpdate(context); await getPermissionOverlay(); await showDriverGiftClaim(context); await checkForAppliedRide(context); print("✅ postFrameCallback completed"); }); // The stack is now even simpler. return Scaffold( appBar: const _HomeAppBar(), drawer: AppDrawer(), body: SafeArea( child: Stack( children: [ // 1. The Map View is the base layer. const _MapView(), // 2. The new floating "Status Pod" at the bottom. const _StatusPodOverlay(), FloatingActionButtons(), // This widget from the original code remains. leftMainMenuCaptainIcons(), ], ), ), ); } } // ================================================================== // Redesigned Helper Widgets (V3) // ================================================================== /// 1. The AppBar now contains the map actions in a PopupMenuButton. class _HomeAppBar extends StatelessWidget implements PreferredSizeWidget { const _HomeAppBar(); @override Widget build(BuildContext context) { final homeCaptainController = Get.find(); return AppBar( backgroundColor: Colors.white, elevation: 1, shadowColor: Colors.black.withOpacity(0.1), title: Row( children: [ Image.asset( 'assets/images/logo.gif', height: 35, ), const SizedBox(width: 10), Text( AppInformation.appName.split(' ')[0].toString().tr, style: AppStyle.title.copyWith( fontSize: 24, fontWeight: FontWeight.bold, color: AppColor.blueColor, ), ), ], ), actions: [ // Refuse count indicator Padding( padding: const EdgeInsets.only(right: 8.0), child: Center( child: MyCircleContainer( child: Text( homeCaptainController.countRefuse.toString(), style: AppStyle.title.copyWith(fontWeight: FontWeight.bold), ), ), ), ), // The new PopupMenuButton for all map and ride actions. Container( margin: const EdgeInsets.symmetric(horizontal: 4), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.1), spreadRadius: 1, blurRadius: 4, ), ], ), child: Row( children: [ _MapControlButton( iconColor: Colors.blue, icon: Icons.satellite_alt, tooltip: 'Change Map Type'.tr, onPressed: homeCaptainController.changeMapType, ), // _MapControlButton( // iconColor: Colors.blue, // icon: Icons.streetview_sharp, // tooltip: 'Toggle Traffic'.tr, // onPressed: homeCaptainController.changeMapTraffic, // ), GetBuilder( builder: (controller) { return _MapControlButton( // تغيير الأيقونة واللون بناءً على الحالة icon: Icons.local_fire_department, iconColor: controller.isHeatmapVisible ? Colors.orange : Colors.grey, tooltip: 'Show Heatmap'.tr, onPressed: controller.toggleHeatmap, ); }, ), _MapControlButton( iconColor: Colors.blue, icon: Icons.my_location, // Changed for clarity tooltip: 'Center on Me'.tr, onPressed: () { if (homeCaptainController.mapHomeCaptainController != null) { homeCaptainController.mapHomeCaptainController! .animateCamera(CameraUpdate.newLatLngZoom( Get.find().myLocation, 17.5, )); } }, ), ], ), ), ], ); } PopupMenuItem _buildPopupMenuItem({ required String value, IconData? icon, Widget? iconWidget, required String text, Color? iconColor, }) { return PopupMenuItem( value: value, child: Row( children: [ iconWidget ?? Icon(icon, color: iconColor ?? Colors.grey.shade600), const SizedBox(width: 16), Text(text), ], ), ); } @override Size get preferredSize => const Size.fromHeight(kToolbarHeight); } /// 2. The Map View is unchanged functionally. class _MapView extends StatelessWidget { const _MapView(); @override Widget build(BuildContext context) { // جلب الكونترولر الرئيسي final homeController = Get.find(); return GetBuilder( builder: (controller) { if (controller.isLoading) { return const MyCircularProgressIndicator(); } // --- هذا هو التعديل --- // هذا الـ Builder يستمع إلى تحديثات الموقع return GetBuilder( builder: (locationController) { // if (homeController.mapHomeCaptainController != null && // homeController.isActive) { // homeController.mapHomeCaptainController!.animateCamera( // CameraUpdate.newCameraPosition( // CameraPosition( // target: locationController.myLocation, // الموقع الجديد // zoom: 17.5, // تقريب لمتابعة السائق // tilt: 50.0, // زاوية رؤية 3D // bearing: locationController.heading, // اتجاه السيارة // ), // ), // ); // } // --- نهاية الكود الجديد --- // إرجاع الخريطة return GoogleMap( padding: const EdgeInsets.only(bottom: 110, top: 300), fortyFiveDegreeImageryEnabled: true, onMapCreated: controller.onMapCreated, // onCameraMove: controller.onCameraMove, minMaxZoomPreference: const MinMaxZoomPreference(6, 18), initialCameraPosition: CameraPosition( target: locationController.myLocation, zoom: 15, ), // --- تم حذف onCameraMove الخاطئ --- // === إضافة الطبقة الحرارية هنا === polygons: controller.heatmapPolygons, // = markers: { Marker( markerId: MarkerId('MyLocation'.tr), position: locationController.myLocation, // يتم تحديثه من هنا rotation: locationController.heading, // يتم تحديثه من هنا flat: true, anchor: const Offset(0.5, 0.5), icon: controller.carIcon, ) }, mapType: controller.mapType ? MapType.satellite : MapType.terrain, myLocationButtonEnabled: false, myLocationEnabled: false, trafficEnabled: controller.mapTrafficON, buildingsEnabled: false, mapToolbarEnabled: false, compassEnabled: false, zoomControlsEnabled: false, ); // --- الكود الجديد --- // // تحويل الإحداثيات من جوجل (إذا كنت لا تزال تستخدمها) إلى latlong2 // final latlng.LatLng currentCarPosition = latlng.LatLng( // locationController.myLocation.latitude, // locationController.myLocation.longitude); // return FlutterMap( // // 1. تمرير الـ Controller الذي أنشأناه في الخطوة 2 // mapController: homeController.mapController, // options: MapOptions( // // 2. هذا بديل initialCameraPosition // initialCenter: currentCarPosition, // initialZoom: 15, // // هذا بديل padding // // (ملاحظة: flutter_map لا يدعم padding مباشرة، قد تحتاج لتعديل الواجهة // // أو استخدام خاصية nonRotatedChildren لبدائل أخرى) // // هذا بديل minMaxZoomPreference // minZoom: 12, // maxZoom: 16, onMapReady: homeController.onMapReady, // ), // // 3. الخرائط في flutter_map عبارة عن "طبقات" (Layers) // children: [ // // --- الطبقة الأولى: الخريطة الأساسية (OSM) --- // TileLayer( // urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', // userAgentPackageName: // 'com.your.app.name', // هام: ضع اسم تطبيقك هنا // ), // // --- (اختياري) طبقة القمر الصناعي بناءً على MapType --- // if (controller.mapType) // إذا كنت لا تزال تستخدم mapType // // TileLayer( // // // ملاحظة: هذا الرابط يحتاج مفتاح API من MapTiler أو مزود آخر // // urlTemplate: // // 'https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=YOUR_API_KEY', // // userAgentPackageName: 'com.your.app.name', // // ), // // --- الطبقة الثانية: أيقونة السيارة (Marker) --- // MarkerLayer( // markers: [ // Marker( // point: currentCarPosition, // الإحداثيات // width: 80, // height: 80, // child: Transform.rotate( // // 4. هذا بديل rotation // angle: locationController.heading * // (3.1415926535 / 180), // تحويل من درجات إلى راديان // // 5. هذا بديل carIcon (أصبح أسهل!) // child: Image.asset( // 'assets/images/car.png', // نفس المسار الذي استخدمته من قبل // width: 30, // الحجم الذي حددته في addCustomCarIcon // height: 35, // ), // ), // ), // ], // ), // ], // ); }, ); }, ); } } /// 3. The floating "Status Pod" at the bottom of the screen. class _StatusPodOverlay extends StatelessWidget { const _StatusPodOverlay(); void _showDetailsDialog( BuildContext context, HomeCaptainController controller) { Get.dialog( _DriverDetailsDialog(controller), // تمرير الكنترولر هنا barrierColor: Colors.black.withOpacity(0.3), ); } @override Widget build(BuildContext context) { final homeCaptainController = Get.find(); return Positioned( bottom: 16, left: 16, right: 16, child: GestureDetector( onTap: () => _showDetailsDialog(context, homeCaptainController), child: ClipRRect( borderRadius: BorderRadius.circular(24), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.85), borderRadius: BorderRadius.circular(24), border: Border.all(color: Colors.white.withOpacity(0.5)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, spreadRadius: -5, ) ], ), child: Row( children: [ const ConnectWidget(), const Spacer(), _buildQuickStat( icon: Icons.directions_car_rounded, value: homeCaptainController.countRideToday, label: 'Rides'.tr, color: AppColor.blueColor, ), const SizedBox(width: 16), _buildQuickStat( icon: Entypo.wallet, value: homeCaptainController.totalMoneyToday.toString(), label: 'Today'.tr, color: AppColor.greenColor, ), const SizedBox(width: 8), ], ), ), ), ), ), ); } Widget _buildQuickStat( {required IconData icon, required String value, required String label, required Color color}) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( children: [ Icon(icon, color: color, size: 20), const SizedBox(width: 4), Text(value, style: AppStyle.title .copyWith(fontSize: 16, fontWeight: FontWeight.bold)), ], ), Text(label, style: AppStyle.title .copyWith(fontSize: 12, color: Colors.grey.shade700)), ], ); } } /// 4. The Dialog that shows detailed driver stats. class _DriverDetailsDialog extends StatelessWidget { // 1. إضافة متغير للكنترولر final HomeCaptainController controller; // 2. تحديث البناء لاستقباله const _DriverDetailsDialog(this.controller); @override Widget build(BuildContext context) { // 3. حذف السطر الذي يسبب الخطأ: final homeCaptainController = Get.find... return BackdropFilter( filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), child: AlertDialog( backgroundColor: Colors.white.withOpacity(0.95), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), titlePadding: const EdgeInsets.only(top: 20), title: Center( child: Text( 'Your Activity'.tr, style: AppStyle.title .copyWith(fontSize: 20, fontWeight: FontWeight.bold), ), ), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Divider(height: 20), _buildStatRow( icon: Entypo.wallet, color: AppColor.greenColor, label: 'Today'.tr, // استخدام المتغير controller الذي تم تمريره value: controller.totalMoneyToday.toString(), ), const SizedBox(height: 12), _buildStatRow( icon: Entypo.wallet, color: AppColor.yellowColor, label: AppInformation.appName, value: controller.totalMoneyInSEFER.toString(), ), const Divider(height: 24), _buildDurationRow( icon: Icons.timer_outlined, label: 'Active Duration:'.tr, value: controller.stringActiveDuration, color: AppColor.greenColor, ), const SizedBox(height: 12), _buildDurationRow( icon: Icons.access_time, label: 'Total Connection Duration:'.tr, value: controller.totalDurationToday, color: AppColor.accentColor, ), const Divider(height: 24), _buildStatRow( icon: Icons.star_border_rounded, color: AppColor.blueColor, label: 'Total Points'.tr, value: controller.totalPoints.toString(), ), ], ), ), actions: [ TextButton( onPressed: () => Get.back(), child: Text('Close'.tr, style: AppStyle.title.copyWith( color: AppColor.blueColor, fontWeight: FontWeight.bold)), ) ], ), ); } // ... بقية الدوال المساعدة (_buildStatRow, _buildDurationRow) تبقى كما هي ... Widget _buildStatRow( {required IconData icon, required Color color, required String label, required String value}) { return Row( children: [ Icon(icon, color: color, size: 22), const SizedBox(width: 12), Text('$label:', style: AppStyle.title), const Spacer(), Text( value, style: AppStyle.title.copyWith( color: color, fontWeight: FontWeight.bold, fontSize: 18), ), ], ); } Widget _buildDurationRow( {required IconData icon, required String label, required String value, required Color color}) { return Row( children: [ Icon(icon, color: color, size: 20), const SizedBox(width: 12), Text(label, style: AppStyle.title), const Spacer(), Text( value, style: AppStyle.title.copyWith( fontWeight: FontWeight.bold, color: color, fontSize: 16), ), ], ); } } class _MapControlButton extends StatelessWidget { final IconData icon; final VoidCallback onPressed; final String tooltip; const _MapControlButton({ required this.icon, required this.onPressed, required this.tooltip, required MaterialColor iconColor, }); @override Widget build(BuildContext context) { return Tooltip( message: tooltip, child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(12), onTap: onPressed, child: Container( padding: const EdgeInsets.all(8), child: Icon( icon, size: 24, color: AppColor.blueColor, ), ), ), ), ); } } class FloatingActionButtons extends StatelessWidget { const FloatingActionButtons(); @override Widget build(BuildContext context) { // نفس الكود الأصلي للأزرار return Positioned( bottom: Get.height * .2, right: 6, child: GetBuilder(builder: (homeCaptainController) { return Column( children: [ Platform.isAndroid ? AnimatedContainer( duration: const Duration(microseconds: 200), width: homeCaptainController.widthMapTypeAndTraffic, decoration: BoxDecoration( border: Border.all(color: AppColor.blueColor), color: AppColor.secondaryColor, borderRadius: BorderRadius.circular(15)), child: IconButton( onPressed: () async { Bubble().startBubbleHead(sendAppToBackground: true); }, icon: Image.asset( 'assets/images/logo1.png', fit: BoxFit.cover, width: 35, height: 35, ), ), ) : const SizedBox(), const SizedBox( height: 5, ), AnimatedContainer( duration: const Duration(microseconds: 200), width: homeCaptainController.widthMapTypeAndTraffic, decoration: BoxDecoration( border: Border.all(color: AppColor.blueColor), color: AppColor.secondaryColor, borderRadius: BorderRadius.circular(15)), child: IconButton( onPressed: () { Get.to(() => const AvailableRidesPage()); }, icon: const Icon( Icons.train_sharp, size: 29, color: AppColor.blueColor, ), ), ), const SizedBox( height: 5, ), // هذا الكود يوضع داخل الـ Stack في ملف الواجهة (HomeCaptain View) box.read(BoxName.rideStatus) == 'Applied' || box.read(BoxName.rideStatus) == 'Begin' ? Positioned( bottom: Get.height * .2, // جعلنا الزر يظهر في المنتصف أو يمتد ليكون واضحاً جداً right: 20, left: 20, child: Center( child: AnimatedContainer( duration: const Duration( milliseconds: 200), // تم تصحيح microseconds إلى milliseconds لحركة أنعم // أزلنا العرض الثابت homeCaptainController.widthMapTypeAndTraffic لكي يتسع للنص // width: homeCaptainController.widthMapTypeAndTraffic, decoration: BoxDecoration( border: Border.all( color: AppColor.blueColor, width: 2), // تعريض الإطار قليلاً color: AppColor.secondaryColor, // لون الخلفية borderRadius: BorderRadius.circular( 30), // تدوير الحواف ليشبه الأزرار الحديثة boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.2), blurRadius: 8, offset: const Offset(0, 4), ) ]), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(30), onLongPress: () { // وظيفة الحذف عند الضغط الطويل (للطوارئ) box.write(BoxName.rideStatus, 'delete'); homeCaptainController.update(); }, onTap: () { // نفس منطقك الأصلي للانتقال if (box.read(BoxName.rideStatus) == 'Applied') { Get.to(() => PassengerLocationMapPage(), arguments: box.read(BoxName.rideArguments)); Get.put(MapDriverController()) .changeRideToBeginToPassenger(); } else { Get.to(() => PassengerLocationMapPage(), arguments: box.read(BoxName.rideArguments)); Get.put(MapDriverController()) .startRideFromStartApp(); } }, child: Padding( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 12), child: Row( mainAxisSize: MainAxisSize.min, // حجم الزر على قد المحتوى mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon( Icons .directions_car_filled_rounded, // تغيير الأيقونة لسيارة أو اتجاهات لتكون معبرة أكثر size: 24, color: AppColor.blueColor, ), const SizedBox( width: 10), // مسافة بين الأيقونة والنص Text( "متابعة الرحلة", // النص الواضح للسائق style: const TextStyle( color: AppColor.blueColor, fontSize: 16, fontWeight: FontWeight.bold, fontFamily: 'Cairo', // تأكد من نوع الخط المستخدم عندك ), ), if (box.read(BoxName.rideStatus) == 'Begin') ...[ const SizedBox(width: 5), // إضافة مؤشر صغير (نقطة حمراء) إذا كانت الرحلة قد بدأت بالفعل (اختياري) const Icon(Icons.circle, size: 8, color: Colors.green) ] ], ), ), ), ), ), ), ) : const SizedBox() ], ); }), ); } } Future checkForAppliedRide(BuildContext context) async { checkForPendingOrderFromServer(); }