From 8fa2f153c16716bc89097383c8ad374a6b370748 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sun, 12 Jul 2026 06:27:36 +0300 Subject: [PATCH] refactor: disable Mawasalati feature, wrap controller initialization in post-frame callbacks, and add documentation plan --- docs/mawasalati_plan.md | 46 +++++++++ .../lib/views/transit/org_admins_page.dart | 4 +- .../lib/views/transit/org_details_page.dart | 4 +- .../Captin/home_captain/drawer_captain.dart | 10 +- .../home/map_widget.dart/map_menu_widget.dart | 10 +- .../views/transit/transit_live_map_page.dart | 98 ++++++++++--------- 6 files changed, 114 insertions(+), 58 deletions(-) create mode 100644 docs/mawasalati_plan.md diff --git a/docs/mawasalati_plan.md b/docs/mawasalati_plan.md new file mode 100644 index 00000000..419c5121 --- /dev/null +++ b/docs/mawasalati_plan.md @@ -0,0 +1,46 @@ +# خطة مواصلاتي (Siro Transit) - ما تم إنجازه وما لم يتم + +تُوثق هذه الوثيقة حالة ميزة "مواصلاتي" (النقل المؤسسي للجامعات والفنادق) في منصة سيرو، وتفصل ما تم بناءه حتى الآن وما يتبقى إكماله قبل الإطلاق النهائي. + +## ✅ أولاً: ما تم إنجازه + +### 1. البنية التحتية وقواعد البيانات (Backend) +- تصميم قواعد البيانات وإضافة الجداول اللازمة (مؤسسات، خطوط، محطات، جداول زمنية، رحلات، واشتراكات الركاب). +- بناء مسارات الـ API بلغة PHP لخدمة الراكب والسائق (جلب المؤسسات، المسارات، المحطات، الرحلات اليومية). + +### 2. تطبيق الراكب (Rider App) +- شاشة **تصفح المؤسسات** (`TransitOrgBrowsePage`) لعرض الجامعات والفنادق المتاحة. +- شاشة **مسارات المؤسسة** (`TransitRoutesPage`) لعرض الخطوط والمحطات على الخريطة. +- شاشة **الصفحة الرئيسية للمواصلاتي** (`TransitHomePage`) لعرض اشتراكات الراكب الحالية. +- شاشة **التتبع الحي** (`TransitLiveMapPage`) المهيأة مبدئياً لتتبع الباص. +- إصلاح مشاكل الـ UI (ParentDataWidget و initState). + +### 3. تطبيق السائق (Driver App) +- شاشة **الرحلات المجدولة** (`TransitDriverHomePage`) لعرض الرحلات المطلوبة من السائق اليوم، مع أزرار "بدء الرحلة" و"إنهاء الرحلة". +- تحسين خريطة السائق الأساسية (`home_captin.dart`) وتفعيل ماركر السيارة الصحيح (`car_icon`) ليكون جاهزاً لبث الموقع الفعلي أثناء الرحلة، وإصلاح مشاكل الـ UI (Overflow). + +--- + +## ⏳ ثانياً: ما لم يتم إنجازه (الخطوات القادمة والأولويات) + +> [!IMPORTANT] +> تم تعليق (إخفاء) أزرار الوصول لخدمة "مواصلاتي" مؤقتاً من تطبيقي الراكب والسائق حتى يتم الانتهاء من هذه الخطوات واختبارها فعلياً على سيرفرات الإنتاج. + +### أولوية 1: الاختبار الميداني الحقيقي +- **بث واستقبال الموقع الحي (WebSockets):** تشغيل واختبار `driver_socket.php` و `passenger_socket.php` على سيرفر الإنتاج الفعلي. +- التأكد من إعدادات الـ Redis (`REDIS_LOCATION_HOST`) في الـ `.env`. +- التأكد من أن "ماركر" الباص يتحرك بسلاسة على خريطة الراكب عندما يبدأ السائق الرحلة. + +### أولوية 2: دورة حياة الرحلة للسائق والتذاكر +- **وضع التوجيه للسائق (Active Trip Navigation):** شاشة تظهر للسائق عند الضغط على "بدء الرحلة" لترشده للمحطات بالترتيب وتتبع تقدمه. +- **الاشتراكات والتذاكر (Ticketing):** شراء الراكب للاشتراك وخصم الرصيد من المحفظة. +- **مسح كود الصعود (QR Boarding):** آلية لكي يثبت الراكب صعوده للباص (إما السائق يمسح كود الراكب، أو يعلّم عليه في قائمة الركاب). + +### أولوية 3: لوحة تحكم المؤسسات والتنبيهات +- **واجهة الويب للمؤسسات (B2B Admin Dashboard):** واجهة ويب تتيح لمدير الحركة في الجامعة إضافة المسارات، الباصات، وتتبع الأسطول. +- **استيراد كشف الركاب:** واجهة لرفع ملفات CSV (`import_roster.php`) لتعريف طلاب الجامعة المسموح لهم بالركوب. +- **التنبيهات الجغرافية (Geofence Push Notifications):** تفعيل إشعارات FCM ("الباص على بُعد 5 دقائق من محطتك"). +- **إدارة العقود:** زر في تطبيق `siro_admin` لتفعيل/تعليق عقود المؤسسات (`contract_status`). + +--- +سيتم الرجوع لهذه الخطة واستئناف العمل عليها في المرحلة القادمة بعد الانتهاء من الأولويات الحالية للنظام. diff --git a/siro_admin/lib/views/transit/org_admins_page.dart b/siro_admin/lib/views/transit/org_admins_page.dart index 77bd08a4..0e6f8d6e 100644 --- a/siro_admin/lib/views/transit/org_admins_page.dart +++ b/siro_admin/lib/views/transit/org_admins_page.dart @@ -28,7 +28,9 @@ class _TransitOrgAdminsPageState extends State { @override void initState() { super.initState(); - Get.find().fetchOrgAdmins(widget.orgId); + WidgetsBinding.instance.addPostFrameCallback((_) { + Get.find().fetchOrgAdmins(widget.orgId); + }); } @override diff --git a/siro_admin/lib/views/transit/org_details_page.dart b/siro_admin/lib/views/transit/org_details_page.dart index da93f2f6..5d9db7e9 100644 --- a/siro_admin/lib/views/transit/org_details_page.dart +++ b/siro_admin/lib/views/transit/org_details_page.dart @@ -19,7 +19,9 @@ class _TransitOrgDetailsPageState extends State { @override void initState() { super.initState(); - Get.find().loadOrgDetails(widget.orgId); + WidgetsBinding.instance.addPostFrameCallback((_) { + Get.find().loadOrgDetails(widget.orgId); + }); } @override diff --git a/siro_driver/lib/views/home/Captin/home_captain/drawer_captain.dart b/siro_driver/lib/views/home/Captin/home_captain/drawer_captain.dart index 29e6d5e8..a706af05 100755 --- a/siro_driver/lib/views/home/Captin/home_captain/drawer_captain.dart +++ b/siro_driver/lib/views/home/Captin/home_captain/drawer_captain.dart @@ -56,11 +56,11 @@ class AppDrawer extends StatelessWidget { // 2. تعريف بيانات القائمة بشكل مركزي ومنظم final List drawerItems = [ - DrawerItem( - title: 'Mawasalati'.tr, - icon: Icons.directions_bus_filled_rounded, - color: Colors.teal, - onTap: () => Get.to(() => const TransitDriverHomePage())), + // DrawerItem( + // title: 'Mawasalati'.tr, + // icon: Icons.directions_bus_filled_rounded, + // color: Colors.teal, + // onTap: () => Get.to(() => const TransitDriverHomePage())), DrawerItem( title: 'Balance'.tr, icon: Icons.account_balance_wallet, diff --git a/siro_rider/lib/views/home/map_widget.dart/map_menu_widget.dart b/siro_rider/lib/views/home/map_widget.dart/map_menu_widget.dart index 114b9248..c35b09ad 100644 --- a/siro_rider/lib/views/home/map_widget.dart/map_menu_widget.dart +++ b/siro_rider/lib/views/home/map_widget.dart/map_menu_widget.dart @@ -149,11 +149,11 @@ class MapMenuWidget extends StatelessWidget { padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 4), children: [ - MenuListItem( - title: 'Mawasalati'.tr, - icon: Icons.directions_bus_filled_rounded, - onTap: () => Get.to(() => const TransitHomePage()), - ), + // MenuListItem( + // title: 'Mawasalati'.tr, + // icon: Icons.directions_bus_filled_rounded, + // onTap: () => Get.to(() => const TransitHomePage()), + // ), MenuListItem( title: 'My Balance'.tr, icon: Icons.account_balance_wallet_outlined, diff --git a/siro_rider/lib/views/transit/transit_live_map_page.dart b/siro_rider/lib/views/transit/transit_live_map_page.dart index 4fb72597..bbd75f26 100644 --- a/siro_rider/lib/views/transit/transit_live_map_page.dart +++ b/siro_rider/lib/views/transit/transit_live_map_page.dart @@ -24,7 +24,9 @@ class _TransitLiveMapPageState extends State { @override void initState() { super.initState(); - Get.find().openLiveRoute(widget.routeId); + WidgetsBinding.instance.addPostFrameCallback((_) { + Get.find().openLiveRoute(widget.routeId); + }); } @override @@ -78,52 +80,56 @@ class _TransitLiveMapPageState extends State { title: widget.routeName, isleading: true, body: [ - Expanded( - child: Stack( - children: [ - IntaleqMap( - apiKey: Env.mapSaasKey, - initialCameraPosition: CameraPosition(target: initialTarget, zoom: 14), - markers: markers, - onMapCreated: (ctrl) => _mapController = ctrl, + Column( + children: [ + Expanded( + child: Stack( + children: [ + IntaleqMap( + apiKey: Env.mapSaasKey, + initialCameraPosition: CameraPosition(target: initialTarget, zoom: 14), + markers: markers, + onMapCreated: (ctrl) => _mapController = ctrl, + ), + if (c.isLoadingLiveTrip) + const Positioned.fill( + child: ColoredBox( + color: Colors.black12, + child: Center(child: CircularProgressIndicator()), + ), + ), + if (!c.isLoadingLiveTrip && c.liveError.isNotEmpty) + Positioned( + top: 16, + left: 16, + right: 16, + child: _statusBanner(c.liveError, AppColor.redColor), + ), + if (!c.isLoadingLiveTrip && + c.liveError.isEmpty && + c.liveBusPosition == null) + Positioned( + top: 16, + left: 16, + right: 16, + child: _statusBanner( + 'No bus running on this route right now'.tr, AppColor.yellowColor), + ), + if (c.liveTripData?['trip']?['delay_minutes'] != null && + (int.tryParse(c.liveTripData!['trip']['delay_minutes'].toString()) ?? 0) > 0) + Positioned( + bottom: 24, + left: 16, + right: 16, + child: _statusBanner( + '${'Bus is delayed'.tr} ${c.liveTripData!['trip']['delay_minutes']} ${'min'.tr}', + AppColor.yellowColor, + ), + ), + ], ), - if (c.isLoadingLiveTrip) - const Positioned.fill( - child: ColoredBox( - color: Colors.black12, - child: Center(child: CircularProgressIndicator()), - ), - ), - if (!c.isLoadingLiveTrip && c.liveError.isNotEmpty) - Positioned( - top: 16, - left: 16, - right: 16, - child: _statusBanner(c.liveError, AppColor.redColor), - ), - if (!c.isLoadingLiveTrip && - c.liveError.isEmpty && - c.liveBusPosition == null) - Positioned( - top: 16, - left: 16, - right: 16, - child: _statusBanner( - 'No bus running on this route right now'.tr, AppColor.yellowColor), - ), - if (c.liveTripData?['trip']?['delay_minutes'] != null && - (int.tryParse(c.liveTripData!['trip']['delay_minutes'].toString()) ?? 0) > 0) - Positioned( - bottom: 24, - left: 16, - right: 16, - child: _statusBanner( - '${'Bus is delayed'.tr} ${c.liveTripData!['trip']['delay_minutes']} ${'min'.tr}', - AppColor.yellowColor, - ), - ), - ], - ), + ), + ], ), ], );