Update: 2026-07-12 18:53:59

This commit is contained in:
Hamza-Ayed
2026-07-12 18:53:59 +03:00
parent 8cd4a4b57e
commit 653d73422f
54 changed files with 2078 additions and 436 deletions
@@ -74,11 +74,17 @@ class FirebaseMessagesController extends GetxController {
// Log.print('fcmToken: ${token}');
box.write(BoxName.tokenFCM, (token.toString()));
});
// 🔹 الاشتراك في topic
await fcmToken
.subscribeToTopic("passengers"); // أو "users" حسب نوع المستخدم
// 🔹 الاشتراك في topic العام
await fcmToken.subscribeToTopic("passengers");
Log.print("Subscribed to 'passengers' topic ✅");
// اشتراك شخصي بـ passenger_{id} لاستقبال إشعارات العضوية في مواصلاتي
final passengerId = box.read(BoxName.passengerID);
if (passengerId != null && passengerId.toString().isNotEmpty) {
await fcmToken.subscribeToTopic('passenger_${passengerId}');
Log.print("Subscribed to 'passenger_${passengerId}' topic ✅");
}
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
// If the app is in the background or terminated, show a system tray message
RemoteNotification? notification = message.notification;
@@ -297,30 +297,19 @@ class LocationSearchController extends GetxController {
newMyLocation = passengerLocation;
if (!CountryPolygons.isServiceSupported(passengerLocation)) {
Get.bottomSheet(
Container(
padding: const EdgeInsets.all(20),
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.location_off, size: 60, color: Colors.redAccent),
const SizedBox(height: 15),
Text(
'service_unavailable_area'.tr,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
],
),
),
isDismissible: false,
enableDrag: false,
);
if (!Get.isSnackbarOpen) {
Get.snackbar(
'Alert'.tr,
'service_unavailable_area'.tr,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: Colors.redAccent,
colorText: Colors.white,
icon: const Icon(Icons.location_off, color: Colors.white),
margin: const EdgeInsets.all(15),
duration: const Duration(seconds: 5),
isDismissible: true,
);
}
}
if (Get.isRegistered<RideLifecycleController>()) {
@@ -24,6 +24,7 @@ class MapSocketController extends GetxController {
// 🚌 مواصلاتي — الخط الحالي المشترَك فيه + مستمع تحديث موقع الباص
int? _subscribedTransitRouteId;
void Function(Map<String, dynamic> data)? onBusLocationUpdate;
void Function(String errorCode)? onTransitError;
DateTime? get lastDriverLocationTime => _lastSocketLocationTime;
int get socketLocationUpdatesCount => _socketLocationUpdatesCount;
@@ -154,6 +155,18 @@ class MapSocketController extends GetxController {
Log.print('Error parsing bus_location_update: $e');
}
});
socket.on('transit_error', (data) {
if (data == null) return;
try {
final map = Map<String, dynamic>.from(data as Map);
final code = map['code']?.toString() ?? '';
Log.print('⚠️ transit_error: $code');
onTransitError?.call(code);
} catch (e) {
Log.print('Error parsing transit_error: $e');
}
});
}
// ── مواصلاتي: اشتراك/إلغاء اشتراك ببثّ موقع خط ─────────────
@@ -21,6 +21,7 @@ final Map<String, String> ar_eg = {
"Stops": "محطات",
"No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن",
"Bus is delayed": "الباص متأخر",
"Missed the bus? Book a ride now": "فاتك الأتوبيس؟ احجز سيارة دلوقتي",
" ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using",
" I am currently located at ": " أنا حالياً في ",
" I am using": " أنا استخدم",
@@ -21,6 +21,7 @@ final Map<String, String> ar_jo = {
"Stops": "محطات",
"No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن",
"Bus is delayed": "الباص متأخر",
"Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة الآن",
" ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using",
" I am currently located at ": " أنا حالياً في ",
" I am using": " أنا استخدم",
@@ -21,6 +21,7 @@ final Map<String, String> ar_sy = {
"Stops": "محطات",
"No bus running on this route right now": "لا يوجد باص يعمل على هذا الخط الآن",
"Bus is delayed": "الباص متأخر",
"Missed the bus? Book a ride now": "فاتك الباص؟ اطلب سيارة هلق",
" ')[0]).toString()}.\\n\${' I am using": " ')[0]).toString()}.\\n\${' I am using",
" I am currently located at ": " أنا حالياً في ",
" I am using": " أنا استخدم",
@@ -1,4 +1,5 @@
// transit_controller.dart — تحكم شاشات مواصلاتي (جهة الراكب)
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:get/get.dart';
import '../home/map/map_socket_controller.dart';
import '../../print.dart';
@@ -55,12 +56,31 @@ class TransitController extends GetxController {
);
if (res.success) {
await fetchMyEnrollments();
// اشترك في topic المؤسسة لاستقبال إشعارات الانطلاق والتأخير
try {
await FirebaseMessaging.instance.subscribeToTopic('transit_org_$orgId');
Log.print('Subscribed to transit_org_$orgId ✅');
} catch (_) {}
return true;
}
Get.snackbar('مواصلاتي', res.message);
return false;
}
// اشتراك/إلغاء اشتراك في topic الخط المحدد
Future<void> subscribeToRouteTopic(int routeId) async {
try {
await FirebaseMessaging.instance.subscribeToTopic('transit_route_$routeId');
Log.print('Subscribed to transit_route_$routeId ✅');
} catch (_) {}
}
Future<void> unsubscribeFromRouteTopic(int routeId) async {
try {
await FirebaseMessaging.instance.unsubscribeFromTopic('transit_route_$routeId');
} catch (_) {}
}
Future<void> openOrgRoutes(int orgId) async {
currentOrgId = orgId;
isLoadingRoutes = true;
@@ -101,6 +121,7 @@ class TransitController extends GetxController {
if (Get.isRegistered<MapSocketController>()) {
final ms = Get.find<MapSocketController>();
ms.onBusLocationUpdate = _handleLiveBusUpdate;
ms.onTransitError = _handleTransitError;
ms.subscribeToTransitRoute(routeId);
}
}
@@ -122,11 +143,23 @@ class TransitController extends GetxController {
update();
}
void _handleTransitError(String errorCode) {
if (errorCode == 'NOT_ENROLLED') {
liveError = 'غير مشترك في هذا الخط. فعّل عضويتك أولاً.';
} else if (errorCode == 'ROUTE_NOT_FOUND') {
liveError = 'الخط غير متاح حالياً.';
} else {
liveError = 'خطأ في الاتصال بالخط: $errorCode';
}
update();
}
void closeLiveRoute() {
if (liveRouteId != null && Get.isRegistered<MapSocketController>()) {
final ms = Get.find<MapSocketController>();
ms.unsubscribeFromTransitRoute(liveRouteId!);
ms.onBusLocationUpdate = null;
ms.onTransitError = null;
}
liveRouteId = null;
liveTripId = null;