25-10-11/1

This commit is contained in:
Hamza-Ayed
2025-11-06 12:29:17 +03:00
parent 14484fcd8f
commit a69e4c6912
46 changed files with 14145 additions and 13529 deletions

View File

@@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:math' as math;
import 'package:http/http.dart' as http;
import 'package:sefer_driver/controller/home/captin/behavior_controller.dart';
import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
@@ -17,8 +18,10 @@ import 'package:url_launcher/url_launcher.dart';
import '../../../constant/api_key.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/country_polygons.dart';
import '../../../constant/links.dart';
import '../../../constant/table_names.dart';
import '../../../env/env.dart';
import '../../../main.dart';
import '../../../print.dart';
import '../../../views/Rate/rate_passenger.dart';
@@ -196,23 +199,16 @@ class MapDriverController extends GetxController {
cancelTripFromDriverAfterApplied() async {
if (formKeyCancel.currentState!.validate()) {
box.write(BoxName.statusDriverLocation, 'off');
// Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
// "Cancel Trip from driver",
// "Trip Cancelled from driver. We are looking for a new driver. Please wait."
// .tr,
// tokenPassenger,
// [],
// 'cancel.wav',
// );
NotificationService.sendNotification(
target: tokenPassenger.toString(),
title: "Cancel Trip from driver".tr,
title: "Cancel Trip from driver",
body:
"Trip Cancelled from driver. We are looking for a new driver. Please wait."
.tr,
isTopic: false, // Important: this is a token
tone: 'cancel',
driverList: [],
driverList: [], category: "Cancel Trip from driver",
);
await CRUD().post(
link: "${AppLink.seferCairoServer}/ride/rides/update.php",
@@ -343,21 +339,13 @@ class MapDriverController extends GetxController {
'status': 'Applied'
});
// Get.find<HomeCaptainController>().changeToAppliedRide('Applied');
// Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
// 'Driver Is Going To Passenger',
// box.read(BoxName.nameDriver).toString(), //todo name driver
// tokenPassenger,
// [],
// 'start.wav');
NotificationService.sendNotification(
target: tokenPassenger.toString(),
title: 'Driver Is Going To Passenger'.tr,
body: box.read(BoxName.nameDriver).toString(),
isTopic: false, // Important: this is a token
tone: 'start',
driverList: [],
driverList: [], category: 'Driver Is Going To Passenger',
);
}
@@ -449,11 +437,11 @@ class MapDriverController extends GetxController {
NotificationService.sendNotification(
target: tokenPassenger.toString(),
title: 'Trip is Begin',
title: 'Trip is Begin'.tr,
body: box.read(BoxName.nameDriver).toString(),
isTopic: false, // Important: this is a token
tone: 'start',
driverList: [],
driverList: [], category: 'Trip is Begin',
);
rideIsBeginPassengerTimer();
@@ -546,7 +534,7 @@ class MapDriverController extends GetxController {
} else {
double costOfWaiting5Minute = box.read(BoxName.countryCode) == 'Egypt'
? (distanceBetweenDriverAndPassengerWhenConfirm * .08) + (5 * 1)
: (distanceBetweenDriverAndPassengerWhenConfirm * .06) +
: (distanceBetweenDriverAndPassengerWhenConfirm * 1100) +
(5 * .06); //for Eygpt other like jordan .06 per minute
await CRUD().post(link: AppLink.updateRides, payload: {
'id': (rideId),
@@ -771,20 +759,9 @@ class MapDriverController extends GetxController {
Get.put(DriverBehaviorController())
.sendSummaryToServer(driverId, rideId);
// Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
// "Driver Finish Trip",
// '${'you will pay to Driver'.tr} $paymentAmount \$',
// tokenPassenger,
// [
// box.read(BoxName.driverID),
// rideId,
// box.read(BoxName.tokenDriver),
// paymentAmount.toString()
// ],
// 'ding.wav');
NotificationService.sendNotification(
target: tokenPassenger.toString(),
title: "Driver Finish Trip",
title: "Driver Finish Trip".tr,
body: '${'you will pay to Driver'.tr} $paymentAmount \$'.tr,
isTopic: false, // Important: this is a token
tone: 'ding',
@@ -794,6 +771,7 @@ class MapDriverController extends GetxController {
box.read(BoxName.tokenDriver),
paymentAmount.toString()
],
category: 'Driver Finish Trip',
);
Get.to(() => RatePassenger(), arguments: {
@@ -1303,21 +1281,115 @@ class MapDriverController extends GetxController {
var _stepBounds = <LatLngBounds>[];
var _stepEndPoints = <LatLng>[];
var _allPointsForActiveRoute = <LatLng>[];
bool _rayIntersectsSegment(LatLng point, LatLng vertex1, LatLng vertex2) {
double px = point.longitude;
double py = point.latitude;
double v1x = vertex1.longitude;
double v1y = vertex1.latitude;
double v2x = vertex2.longitude;
double v2y = vertex2.latitude;
// Check if the point is outside the vertical bounds of the segment
if ((py < v1y && py < v2y) || (py > v1y && py > v2y)) {
return false;
}
// Calculate the intersection of the ray and the segment
double intersectX = v1x + (py - v1y) * (v2x - v1x) / (v2y - v1y);
// Check if the intersection is to the right of the point
return intersectX > px;
}
// Function to check if the point is inside the polygon
bool isPointInPolygon(LatLng point, List<LatLng> polygon) {
int intersections = 0;
for (int i = 0; i < polygon.length; i++) {
LatLng vertex1 = polygon[i];
LatLng vertex2 =
polygon[(i + 1) % polygon.length]; // Loop back to the start
if (_rayIntersectsSegment(point, vertex1, vertex2)) {
intersections++;
}
}
// If the number of intersections is odd, the point is inside
return intersections % 2 != 0;
}
String getLocationArea(double latitude, double longitude) {
LatLng passengerPoint = LatLng(latitude, longitude);
// 1. فحص الأردن
if (isPointInPolygon(passengerPoint, CountryPolygons.jordanBoundary)) {
box.write(BoxName.countryCode, 'Jordan');
// يمكنك تعيين AppLink.endPoint هنا إذا كان منطقك الداخلي لا يزال يعتمد عليه
// box.write(BoxName.serverChosen,
// AppLink.IntaleqSyriaServer); // مثال: اختر سيرفر سوريا للبيانات
return 'Jordan';
}
// 2. فحص سوريا
if (isPointInPolygon(passengerPoint, CountryPolygons.syriaBoundary)) {
box.write(BoxName.countryCode, 'Syria');
// box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
return 'Syria';
}
// 3. فحص مصر
if (isPointInPolygon(passengerPoint, CountryPolygons.egyptBoundary)) {
box.write(BoxName.countryCode, 'Egypt');
// box.write(BoxName.serverChosen, AppLink.IntaleqAlexandriaServer);
return 'Egypt';
}
// 4. الافتراضي (إذا كان خارج المناطق المخدومة)
box.write(BoxName.countryCode, 'Jordan');
// box.write(BoxName.serverChosen, AppLink.IntaleqSyriaServer);
return 'Unknown Location (Defaulting to Jordan)';
}
// دالة موحّدة وقوية لجلب أي مسار
Future<void> getRoute({
required LatLng origin,
required LatLng destination,
required Color routeColor,
required Color routeColor, // تم الإبقاء عليه كما طلبت
}) async {
// إظهار مؤشر التحميل لو رغبت
// isLoading.value = true;
getLocationArea(origin.latitude, origin.longitude);
String _dynamicApiUrl = 'https://routec.intaleq.xyz/route';
// استخدام مفتاح الـ API الخاص بك (افترضتُ أنه موجود في Env)
final String _routeApiKey = Env.mapKeyOsm;
var url =
('${AppLink.googleMapsLink}directions/json?language=ar&destination=${destination.latitude},${destination.longitude}&origin=${origin.latitude},${origin.longitude}&key=${AK.mapAPIKEY}');
var response = await CRUD().getGoogleApi(link: url, payload: {});
'$_dynamicApiUrl?origin=${origin.latitude},${origin.longitude}&destination=${destination.latitude},${destination.longitude}&steps=true&overview=full';
if (response == null || response['routes'].isEmpty) {
var response;
try {
response = await http.get(
Uri.parse(url),
headers: {'X-API-KEY': _routeApiKey},
);
} catch (e) {
print("Error calling route API: $e");
// isLoading.value = false;
// أظهر رسالة خطأ
return;
}
if (response.statusCode != 200) {
print("Route API returned error: ${response.statusCode}");
// isLoading.value = false;
return;
}
final responseData = jsonDecode(response.body);
if (responseData == null || responseData['status'] != 'ok') {
// isLoading.value = false;
// أظهر رسالة خطأ
return;
@@ -1325,17 +1397,36 @@ class MapDriverController extends GetxController {
_resetRouteState(); // تنظيف الحالة القديمة قبل رسم الجديد
final route = response['routes'][0];
final leg = route['legs'][0];
// --- 2. "ترجمة" الاستجابة الجديدة لتناسب الكود القديم ---
// استخراج النقاط ورسم المسار المبدئي بالكامل
final pointsString = route["overview_polyline"]["points"];
// استخراج النقاط ورسم المسار المبدئي
// الكود القديم كان يتوقع: route["overview_polyline"]["points"]
// الكود الجديد يوفر: responseData["polyline"]
final pointsString = responseData["polyline"];
// افترضتُ أن لديك دالة اسمها decodePolylineToLatLng
// إذا كان اسمها decodePolylineIsolate، قم بتغيير الاسم هنا
_allPointsForActiveRoute = decodePolylineToLatLng(pointsString);
upcomingPathPoints.assignAll(_allPointsForActiveRoute);
// استخراج خطوات الملاحة
activeRouteSteps.assignAll(List<Map<String, dynamic>>.from(leg['steps']));
_prepareStepData(activeRouteSteps);
// الكود القديم كان يتوقع: List<Map<String, dynamic>>.from(leg['steps'])
// الكود الجديد يوفر: List<Map<String, dynamic>>.from(responseData['steps'])
final stepsList = List<Map<String, dynamic>>.from(responseData['steps']);
// [مهم جداً] إضافة الحقول التي يتوقعها الكود القديم
for (var step in stepsList) {
// الكود القديم يتوقع 'html_instructions'
// سنقوم بإنشائها من بيانات 'maneuver'
step['html_instructions'] = _createInstructionFromManeuver(step);
// الكود القديم قد يتوقع 'end_location'
var loc = step['maneuver']['location']; // [lng, lat]
step['end_location'] = {'lat': loc[1], 'lng': loc[0]};
}
activeRouteSteps.assignAll(stepsList);
_prepareStepData(activeRouteSteps); // هذه الدالة ستعمل الآن كما هي
// تحديث التعليمات الأولية
if (activeRouteSteps.isNotEmpty) {
@@ -1347,18 +1438,161 @@ class MapDriverController extends GetxController {
}
// تحديث الكاميرا لتناسب المسار الجديد
final boundsData = route["bounds"];
_fitToBounds(LatLngBounds(
northeast: LatLng(
boundsData['northeast']['lat'], boundsData['northeast']['lng']),
southwest: LatLng(
boundsData['southwest']['lat'], boundsData['southwest']['lng']),
));
// الكود القديم كان يتوقع: route["bounds"]
// الكود الجديد لا يوفرها، لذا سنقوم بحسابها يدوياً
if (_allPointsForActiveRoute.isNotEmpty) {
final bounds = _boundsFromLatLngList(_allPointsForActiveRoute);
_fitToBounds(bounds); // ستعمل هذه الدالة الآن كما هي
}
// isLoading.value = false;
update(); // تحديث الواجهة مرة واحدة بعد كل العمليات
}
String _createInstructionFromManeuver(Map<String, dynamic> step) {
final maneuver = step['maneuver'];
final type = maneuver['type'] ?? 'continue';
final modifier = maneuver['modifier'] ?? 'straight';
final name = step['name'] ?? '';
String instruction = "";
switch (type) {
case 'depart':
instruction = "انطلق";
break;
case 'arrive':
instruction = "لقد وصلت إلى وجهتك";
if (name.isNotEmpty) instruction += "، $name";
return instruction;
case 'turn':
case 'fork':
case 'off ramp':
case 'on ramp':
case 'roundabout':
instruction = _getTurnInstruction(modifier);
break;
case 'continue':
instruction = "استمر";
break;
default:
instruction = "اتجه";
}
if (name.isNotEmpty) {
if (instruction == "استمر") {
instruction += " على $name";
} else {
instruction += " إلى $name";
}
} else if (type == 'continue' && modifier == 'straight') {
instruction = "استمر بشكل مستقيم";
}
return instruction;
}
/**
* دالة مساعدة لترجمة تعليمات الانعطاف
*/
String _getTurnInstruction(String modifier) {
switch (modifier) {
case 'uturn':
return "قم بالاستدارة والعودة";
case 'sharp right':
return "انعطف يمينًا بحدة";
case 'right':
return "انعطف يمينًا";
case 'slight right':
return "انعطف يمينًا قليلاً";
case 'straight':
return "استمر بشكل مستقيم";
case 'slight left':
return "انعطف يسارًا قليلاً";
case 'left':
return "انعطف يسارًا";
case 'sharp left':
return "انعطف يسارًا بحدة";
default:
return "اتجه";
}
}
/**
* دالة لحساب حدود الخريطة (Bounds) من قائمة نقاط
*/
LatLngBounds _boundsFromLatLngList(List<LatLng> list) {
assert(list.isNotEmpty);
double? x0, x1, y0, y1;
for (LatLng latLng in list) {
if (x0 == null) {
x0 = x1 = latLng.latitude;
y0 = y1 = latLng.longitude;
} else {
if (latLng.latitude > x1!) x1 = latLng.latitude;
if (latLng.latitude < x0) x0 = latLng.latitude;
if (latLng.longitude > y1!) y1 = latLng.longitude;
if (latLng.longitude < y0!) y0 = latLng.longitude;
}
}
return LatLngBounds(
northeast: LatLng(x1!, y1!), southwest: LatLng(x0!, y0!));
}
// // دالة موحّدة وقوية لجلب أي مسار
// Future<void> getRoute({
// required LatLng origin,
// required LatLng destination,
// required Color routeColor,
// }) async {
// // إظهار مؤشر التحميل لو رغبت
// // isLoading.value = true;
// var url =
// ('${AppLink.googleMapsLink}directions/json?language=ar&destination=${destination.latitude},${destination.longitude}&origin=${origin.latitude},${origin.longitude}&key=${AK.mapAPIKEY}');
// var response = await CRUD().getGoogleApi(link: url, payload: {});
// if (response == null || response['routes'].isEmpty) {
// // isLoading.value = false;
// // أظهر رسالة خطأ
// return;
// }
// _resetRouteState(); // تنظيف الحالة القديمة قبل رسم الجديد
// final route = response['routes'][0];
// final leg = route['legs'][0];
// // استخراج النقاط ورسم المسار المبدئي بالكامل
// final pointsString = route["overview_polyline"]["points"];
// _allPointsForActiveRoute = decodePolylineToLatLng(pointsString);
// upcomingPathPoints.assignAll(_allPointsForActiveRoute);
// // استخراج خطوات الملاحة
// activeRouteSteps.assignAll(List<Map<String, dynamic>>.from(leg['steps']));
// _prepareStepData(activeRouteSteps);
// // تحديث التعليمات الأولية
// if (activeRouteSteps.isNotEmpty) {
// currentInstruction =
// _parseInstruction(activeRouteSteps[0]['html_instructions']);
// Get.isRegistered<TextToSpeechController>()
// ? Get.find<TextToSpeechController>().speakText(currentInstruction)
// : Get.put(TextToSpeechController()).speakText(currentInstruction);
// }
// // تحديث الكاميرا لتناسب المسار الجديد
// final boundsData = route["bounds"];
// _fitToBounds(LatLngBounds(
// northeast: LatLng(
// boundsData['northeast']['lat'], boundsData['northeast']['lng']),
// southwest: LatLng(
// boundsData['southwest']['lat'], boundsData['southwest']['lng']),
// ));
// // isLoading.value = false;
// update(); // تحديث الواجهة مرة واحدة بعد كل العمليات
// }
// الدالة التي يتم استدعاؤها من خدمة الموقع كل 5 ثوان (أو حسب الفترة المحددة)
void onLocationUpdated(Position newPosition) {
myLocation = LatLng(newPosition.latitude, newPosition.longitude);
@@ -1533,7 +1767,7 @@ class MapDriverController extends GetxController {
('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang)}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');
var response = await CRUD().getGoogleApi(link: url, payload: {});
Log.print('response: ${response}');
Log.print('response: $response');
data = response['routes'][0]['legs'];
distanceBetweenDriverAndPassengerWhenConfirm =
(data[0]['distance']['value']) / 1000;
@@ -1663,7 +1897,7 @@ class MapDriverController extends GetxController {
// );
NotificationService.sendNotification(
target: tokenPassenger.toString(),
title: "You are near the destination",
title: "You are near the destination".tr,
body: "You are near the destination".tr,
isTopic: false, // Important: this is a token
tone: 'ding',
@@ -1673,6 +1907,7 @@ class MapDriverController extends GetxController {
box.read(BoxName.tokenDriver),
paymentAmount.toString()
],
category: "You are near the destination",
);
// يمكن إضافة أي إجراء آخر هنا عند الاقتراب من الوجهة
}