feat: refactor financial wallet UI components and add offline map service support
This commit is contained in:
@@ -5,28 +5,21 @@ import 'dart:math';
|
||||
import 'dart:math' as math;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:sefer_driver/controller/firebase/local_notification.dart';
|
||||
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/controller/home/navigation/decode_polyline_isolate.dart';
|
||||
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
|
||||
import 'package:sefer_driver/views/widgets/mydialoug.dart';
|
||||
import 'package:bubble_head/bubble.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:google_polyline_algorithm/google_polyline_algorithm.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
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';
|
||||
@@ -36,6 +29,7 @@ import '../../firebase/notification_service.dart';
|
||||
import '../../functions/crud.dart';
|
||||
import '../../functions/location_controller.dart';
|
||||
import '../../functions/tts.dart';
|
||||
import 'behavior_controller.dart';
|
||||
|
||||
class MapDriverController extends GetxController {
|
||||
bool isLoading = true;
|
||||
@@ -48,10 +42,10 @@ class MapDriverController extends GetxController {
|
||||
List data = [];
|
||||
List dataDestination = [];
|
||||
LatLngBounds? boundsData;
|
||||
BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker;
|
||||
BitmapDescriptor passengerIcon = BitmapDescriptor.defaultMarker;
|
||||
BitmapDescriptor startIcon = BitmapDescriptor.defaultMarker;
|
||||
BitmapDescriptor endIcon = BitmapDescriptor.defaultMarker;
|
||||
InlqBitmap carIcon = InlqBitmap.defaultMarker;
|
||||
InlqBitmap passengerIcon = InlqBitmap.defaultMarker;
|
||||
InlqBitmap startIcon = InlqBitmap.defaultMarker;
|
||||
InlqBitmap endIcon = InlqBitmap.defaultMarker;
|
||||
final List<LatLng> polylineCoordinates = [];
|
||||
final List<LatLng> polylineCoordinatesDestination = [];
|
||||
List<Polyline> polyLines = [];
|
||||
@@ -104,7 +98,7 @@ class MapDriverController extends GetxController {
|
||||
int remainingTimeToPassenger = 60;
|
||||
int remainingTimeInPassengerLocatioWait = 60;
|
||||
bool isDriverNearPassengerStart = false;
|
||||
GoogleMapController? mapController;
|
||||
IntaleqMapController? mapController;
|
||||
late LatLng myLocation;
|
||||
int remainingTimeTimerRideBegin = 60;
|
||||
String stringRemainingTimeRideBegin = '';
|
||||
@@ -158,16 +152,32 @@ class MapDriverController extends GetxController {
|
||||
_posSub?.cancel();
|
||||
_posSub = null;
|
||||
|
||||
mapController?.dispose();
|
||||
// mapController?.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void onMapCreated(GoogleMapController controller) {
|
||||
void onMapCreated(IntaleqMapController controller) {
|
||||
mapController = controller;
|
||||
if (Get.isRegistered<LocationController>()) {
|
||||
myLocation = Get.find<LocationController>().myLocation;
|
||||
controller.animateCamera(CameraUpdate.newLatLngZoom(myLocation, 16));
|
||||
}
|
||||
|
||||
// 🔥 رسم المسار فور جاهزية الخريطة
|
||||
if (isRideStarted) {
|
||||
// إذا كانت الرحلة بدأت، ارسم للمكان النهائي
|
||||
getRoute(
|
||||
origin: myLocation,
|
||||
destination: latLngPassengerDestination,
|
||||
routeColor: Colors.blue);
|
||||
} else {
|
||||
// إذا كان السائق ذاهب للراكب
|
||||
getRoute(
|
||||
origin: myLocation,
|
||||
destination: latLngPassengerLocation,
|
||||
routeColor: Colors.yellow);
|
||||
}
|
||||
|
||||
// بدء الاستماع للموقع للملاحة وتحديث الماركر
|
||||
startListeningStepNavigation();
|
||||
}
|
||||
@@ -239,7 +249,7 @@ class MapDriverController extends GetxController {
|
||||
}
|
||||
|
||||
takeSnapMap() {
|
||||
mapController!.takeSnapshot();
|
||||
// mapController!.takeSnapshot();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -254,7 +264,7 @@ class MapDriverController extends GetxController {
|
||||
_passengerTimer?.cancel();
|
||||
_waitingTimer?.cancel();
|
||||
_posSub?.cancel();
|
||||
mapController?.dispose();
|
||||
// mapController?.dispose();
|
||||
}
|
||||
|
||||
Future openGoogleMapFromDriverToPassenger() async {
|
||||
@@ -307,7 +317,9 @@ class MapDriverController extends GetxController {
|
||||
box.remove(BoxName.rideArguments);
|
||||
|
||||
// 3. عرض رسالة للسائق
|
||||
if (Get.isDialogOpen == true) Get.back(); // إغلاق أي ديالوج مفتوح
|
||||
if (Get.isDialogOpen == true) {
|
||||
navigatorKey.currentState?.pop();
|
||||
}
|
||||
|
||||
Get.defaultDialog(
|
||||
title: "تم إلغاء الرحلة".tr,
|
||||
@@ -325,7 +337,7 @@ class MapDriverController extends GetxController {
|
||||
),
|
||||
confirm: ElevatedButton(
|
||||
onPressed: () {
|
||||
Get.back(); // إغلاق الديالوج
|
||||
navigatorKey.currentState?.pop(); // إغلاق الديالوج
|
||||
Get.offAll(() => HomeCaptain()); // العودة للرئيسية
|
||||
},
|
||||
child: Text("OK".tr),
|
||||
@@ -367,8 +379,8 @@ class MapDriverController extends GetxController {
|
||||
box.write(BoxName.statusDriverLocation, 'blocked');
|
||||
|
||||
// عرض رسالة العقوبة
|
||||
Get.snackbar("تم تقييد حسابك مؤقتاً ⛔",
|
||||
"بسبب كثرة الإلغاءات (3 مرات)، تم إيقاف استقبال الطلبات لمدة 4 ساعات.",
|
||||
Get.snackbar("Your account is temporarily restricted ⛔".tr,
|
||||
"Due to excessive cancellations (3 times), receiving orders has been suspended for 4 hours.".tr,
|
||||
duration: Duration(seconds: 8),
|
||||
backgroundColor: Colors.red,
|
||||
colorText: Colors.white,
|
||||
@@ -402,15 +414,21 @@ class MapDriverController extends GetxController {
|
||||
Get.put(HomeCaptainController()).getRefusedOrderByCaptain();
|
||||
}
|
||||
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
if (Get.isDialogOpen == true) {
|
||||
navigatorKey.currentState?.pop();
|
||||
}
|
||||
Get.offAll(
|
||||
() => HomeCaptain()); // العودة للرئيسية ليتم تطبيق الحظر هناك
|
||||
} else {
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
if (Get.isDialogOpen == true) {
|
||||
navigatorKey.currentState?.pop();
|
||||
}
|
||||
Get.snackbar("Error", "Failed to cancel ride");
|
||||
}
|
||||
} catch (e) {
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
if (Get.isDialogOpen == true) {
|
||||
navigatorKey.currentState?.pop();
|
||||
}
|
||||
Log.print("Error: $e");
|
||||
}
|
||||
}
|
||||
@@ -707,7 +725,9 @@ class MapDriverController extends GetxController {
|
||||
await calculateDistanceBetweenDriverAndPassengerLocation();
|
||||
|
||||
// إغلاق مؤشر التحميل لأننا حصلنا على النتيجة
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
if (Get.isDialogOpen == true) {
|
||||
navigatorKey.currentState?.pop();
|
||||
}
|
||||
|
||||
if (distanceToPassenger < 100) {
|
||||
// زدت المسافة قليلاً لمرونة أكبر (150م)
|
||||
@@ -752,15 +772,17 @@ class MapDriverController extends GetxController {
|
||||
});
|
||||
} else {
|
||||
// --- حالة الرفض (بعيد جداً) ---
|
||||
MyDialog().getDialog(
|
||||
'You are far from passenger location'.tr,
|
||||
MyDialog().getDialog('You are far from passenger location'.tr,
|
||||
'Please go closer to the passenger location (less than 150m)'.tr,
|
||||
() => Get.back() // إغلاق الديالوج فقط
|
||||
);
|
||||
() {
|
||||
// الديالوج يغلق نفسه الآن تلقائياً
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// تنظيف اللودينج في حال حدوث خطأ غير متوقع
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
if (Get.isDialogOpen == true) {
|
||||
navigatorKey.currentState?.pop();
|
||||
}
|
||||
Log.print("Error starting ride: $e");
|
||||
Get.snackbar("Error", "Could not start ride. Please check internet.");
|
||||
}
|
||||
@@ -1448,56 +1470,23 @@ class MapDriverController extends GetxController {
|
||||
}
|
||||
|
||||
void addCustomCarIcon() {
|
||||
ImageConfiguration config = ImageConfiguration(
|
||||
size: const Size(30, 35), devicePixelRatio: Get.pixelRatio);
|
||||
BitmapDescriptor.asset(
|
||||
config,
|
||||
'assets/images/car.png',
|
||||
// mipmaps: false,
|
||||
).then((value) {
|
||||
carIcon = value;
|
||||
update();
|
||||
});
|
||||
carIcon = InlqBitmap.fromAsset('assets/images/car.png');
|
||||
update();
|
||||
}
|
||||
|
||||
void addCustomStartIcon() async {
|
||||
// Create the marker with the resized image
|
||||
|
||||
ImageConfiguration config = ImageConfiguration(
|
||||
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio);
|
||||
BitmapDescriptor.asset(
|
||||
config,
|
||||
'assets/images/A.png',
|
||||
).then((value) {
|
||||
startIcon = value;
|
||||
update();
|
||||
});
|
||||
startIcon = InlqBitmap.fromAsset('assets/images/A.png');
|
||||
update();
|
||||
}
|
||||
|
||||
void addCustomEndIcon() {
|
||||
ImageConfiguration config = ImageConfiguration(
|
||||
size: const Size(25, 25), devicePixelRatio: Get.pixelRatio);
|
||||
BitmapDescriptor.asset(
|
||||
config,
|
||||
'assets/images/b.png',
|
||||
).then((value) {
|
||||
endIcon = value;
|
||||
update();
|
||||
});
|
||||
endIcon = InlqBitmap.fromAsset('assets/images/b.png');
|
||||
update();
|
||||
}
|
||||
|
||||
void addCustomPassengerIcon() {
|
||||
ImageConfiguration config = ImageConfiguration(
|
||||
size: const Size(30, 30), devicePixelRatio: Get.pixelRatio
|
||||
// scale: 1.0,
|
||||
);
|
||||
BitmapDescriptor.asset(
|
||||
config,
|
||||
'assets/images/picker.png',
|
||||
).then((value) {
|
||||
passengerIcon = value;
|
||||
update();
|
||||
});
|
||||
passengerIcon = InlqBitmap.fromAsset('assets/images/picker.png');
|
||||
update();
|
||||
}
|
||||
|
||||
var activeRouteSteps = <Map<String, dynamic>>[];
|
||||
@@ -1596,82 +1585,94 @@ class MapDriverController extends GetxController {
|
||||
required LatLng destination,
|
||||
required Color routeColor,
|
||||
}) async {
|
||||
// 1. استخدام الرابط الجديد والإعدادات الصحيحة
|
||||
String coordinates =
|
||||
'${origin.longitude},${origin.latitude};${destination.longitude},${destination.latitude}';
|
||||
// استخدام الرابط من الكلاس المرجعي لأنه أحدث
|
||||
var url =
|
||||
"${AppLink.mapOSM}/route/v1/driving/$coordinates?steps=true&overview=full";
|
||||
if (mapController == null) return;
|
||||
|
||||
try {
|
||||
var response = await http.get(Uri.parse(url));
|
||||
// 1. طلب المسار من الباكيج
|
||||
final response =
|
||||
await mapController!.getDirections(origin, destination, steps: true);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
var decoded = jsonDecode(response.body);
|
||||
// 2. التعامل مع الـ JSON المباشر (الذي أرسله المستخدم)
|
||||
// إذا كان الـ response يحتوي على الحقول مباشرة في الجذر
|
||||
final String? encodedPoints = response['points'];
|
||||
|
||||
if (decoded['code'] != 'Ok' || (decoded['routes'] as List).isEmpty) {
|
||||
mySnackeBarError("لم يتم العثور على مسار");
|
||||
return;
|
||||
}
|
||||
if (encodedPoints == null) {
|
||||
mySnackeBarError("No route points found".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
var route = decoded['routes'][0];
|
||||
// 🔥 فك التشفير باستخدام compute لضمان أداء ممتاز
|
||||
List<LatLng> fullRoute =
|
||||
await compute(PolylineUtils.decode, encodedPoints);
|
||||
|
||||
// أ) تشغيل الـ Isolate لفك التشفير (ممتاز، ابقِ عليه)
|
||||
final String pointsString = route["geometry"];
|
||||
List<LatLng> fullRoute =
|
||||
await compute(decodePolylineIsolate, pointsString);
|
||||
if (fullRoute.isEmpty) {
|
||||
mySnackeBarError("Failed to process route points".tr);
|
||||
return;
|
||||
}
|
||||
|
||||
// ب) تهيئة المتغيرات
|
||||
upcomingPathPoints.assignAll(fullRoute);
|
||||
traveledPathPoints.clear();
|
||||
_lastTraveledIndex = 0;
|
||||
// تحديث المسافة والوقت من الـ JSON الجديد
|
||||
distance = (response['distance'] ?? 0).toString();
|
||||
duration = (response['duration'] ?? 0).toString();
|
||||
|
||||
// ج) رسم المسار الأولي
|
||||
polyLines.clear();
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId("upcoming_route"),
|
||||
points: fullRoute,
|
||||
width: 8,
|
||||
color: routeColor,
|
||||
startCap: Cap.roundCap,
|
||||
endCap: Cap.roundCap,
|
||||
));
|
||||
// ب) تهيئة المتغيرات
|
||||
upcomingPathPoints.assignAll(fullRoute);
|
||||
traveledPathPoints.clear();
|
||||
_lastTraveledIndex = 0;
|
||||
|
||||
// د) معالجة الخطوات (Legs & Steps)
|
||||
List<dynamic> legs = route['legs'];
|
||||
if (legs.isNotEmpty) {
|
||||
final stepsList = List<Map<String, dynamic>>.from(legs[0]['steps']);
|
||||
// ج) رسم المسار الأولي
|
||||
polyLines.clear();
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId("upcoming_route"),
|
||||
points: fullRoute,
|
||||
width: 8,
|
||||
color: routeColor,
|
||||
));
|
||||
|
||||
// 🔥 استخدام دالة الترجمة المحسنة من الكلاس المرجعي
|
||||
for (var step in stepsList) {
|
||||
step['html_instructions'] =
|
||||
_createInstructionFromManeuverSmart(step);
|
||||
// تصحيح مواقع المناورات
|
||||
if (step['maneuver'] != null &&
|
||||
step['maneuver']['location'] != null) {
|
||||
var loc = step['maneuver']['location'];
|
||||
// د) معالجة الخطوات (Legs & Steps) إذا توفرت في الـ JSON
|
||||
List<dynamic> legs = response['legs'] ?? [];
|
||||
if (legs.isNotEmpty) {
|
||||
final stepsList =
|
||||
List<Map<String, dynamic>>.from(legs[0]['steps'] ?? []);
|
||||
|
||||
for (var step in stepsList) {
|
||||
step['html_instructions'] = _createInstructionFromManeuverSmart(step);
|
||||
|
||||
if (step['maneuver'] != null &&
|
||||
step['maneuver']['location'] != null) {
|
||||
var loc = step['maneuver']['location'];
|
||||
// التعامل مع تنسيق OSRM [lng, lat]
|
||||
if (loc is List && loc.length >= 2) {
|
||||
step['end_location'] = {'lat': loc[1], 'lng': loc[0]};
|
||||
} else if (loc is Map) {
|
||||
step['end_location'] = loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routeSteps = stepsList;
|
||||
currentStepIndex = 0;
|
||||
routeSteps = stepsList;
|
||||
currentStepIndex = 0;
|
||||
|
||||
// نطق أول تعليمة
|
||||
if (routeSteps.isNotEmpty) {
|
||||
currentInstruction = routeSteps[0]['html_instructions'];
|
||||
// نطق أول تعليمة
|
||||
if (routeSteps.isNotEmpty) {
|
||||
currentInstruction = routeSteps[0]['html_instructions'];
|
||||
if (Get.isRegistered<TextToSpeechController>()) {
|
||||
Get.find<TextToSpeechController>().speakText(currentInstruction);
|
||||
}
|
||||
}
|
||||
|
||||
// هـ) تحريك الكاميرا لتشمل المسار
|
||||
if (fullRoute.isNotEmpty) {
|
||||
final bounds = _boundsFromLatLngList(fullRoute);
|
||||
safeAnimateCamera(CameraUpdate.newLatLngBounds(bounds, 80));
|
||||
}
|
||||
|
||||
update();
|
||||
} else {
|
||||
// في حال عدم وجود steps، نقوم بتصفيرها
|
||||
routeSteps = [];
|
||||
currentInstruction = "";
|
||||
}
|
||||
|
||||
// هـ) تحريك الكاميرا لتشمل المسار
|
||||
if (fullRoute.isNotEmpty) {
|
||||
final bounds = _boundsFromLatLngList(fullRoute);
|
||||
safeAnimateCamera(CameraUpdate.newLatLngBounds(bounds,
|
||||
left: 80, top: 80, right: 80, bottom: 80));
|
||||
}
|
||||
|
||||
update();
|
||||
} catch (e) {
|
||||
Log.print("Route Error: $e");
|
||||
}
|
||||
@@ -1679,7 +1680,7 @@ class MapDriverController extends GetxController {
|
||||
|
||||
// 🔥 دالة الترجمة المحسنة (من NavigationController)
|
||||
String _createInstructionFromManeuverSmart(Map<String, dynamic> step) {
|
||||
if (step['maneuver'] == null) return "تابع المسير";
|
||||
if (step['maneuver'] == null) return "Continue straight".tr;
|
||||
|
||||
final maneuver = step['maneuver'];
|
||||
final type = maneuver['type'] ?? 'continue';
|
||||
@@ -1690,10 +1691,10 @@ class MapDriverController extends GetxController {
|
||||
|
||||
switch (type) {
|
||||
case 'depart':
|
||||
instruction = "انطلق";
|
||||
instruction = "Go".tr;
|
||||
break;
|
||||
case 'arrive':
|
||||
return "لقد وصلت إلى وجهتك، $name";
|
||||
return "You have arrived at your destination, @name".trParams({'name': name});
|
||||
case 'turn':
|
||||
case 'fork':
|
||||
case 'roundabout':
|
||||
@@ -1705,14 +1706,14 @@ class MapDriverController extends GetxController {
|
||||
_getTurnInstruction(modifier); // استخدم نفس دالتك المساعدة هنا
|
||||
break;
|
||||
default:
|
||||
instruction = "تابع المسير";
|
||||
instruction = "Continue straight".tr;
|
||||
}
|
||||
|
||||
if (name.isNotEmpty) {
|
||||
if (type == 'continue') {
|
||||
instruction += " على $name";
|
||||
instruction += " ${"on".tr} $name";
|
||||
} else {
|
||||
instruction += " نحو $name";
|
||||
instruction += " ${"towards".tr} $name";
|
||||
}
|
||||
}
|
||||
return instruction;
|
||||
@@ -1728,10 +1729,10 @@ class MapDriverController extends GetxController {
|
||||
|
||||
switch (type) {
|
||||
case 'depart':
|
||||
instruction = "انطلق";
|
||||
instruction = "Go".tr;
|
||||
break;
|
||||
case 'arrive':
|
||||
instruction = "لقد وصلت إلى وجهتك";
|
||||
instruction = "You have arrived at your destination".tr;
|
||||
if (name.isNotEmpty) instruction += "، $name";
|
||||
return instruction;
|
||||
case 'turn':
|
||||
@@ -1742,20 +1743,20 @@ class MapDriverController extends GetxController {
|
||||
instruction = _getTurnInstruction(modifier);
|
||||
break;
|
||||
case 'continue':
|
||||
instruction = "استمر";
|
||||
instruction = "Continue".tr;
|
||||
break;
|
||||
default:
|
||||
instruction = "اتجه";
|
||||
instruction = "Head".tr;
|
||||
}
|
||||
|
||||
if (name.isNotEmpty) {
|
||||
if (instruction == "استمر") {
|
||||
instruction += " على $name";
|
||||
instruction += " ${"on".tr} $name";
|
||||
} else {
|
||||
instruction += " إلى $name";
|
||||
instruction += " ${"to".tr} $name";
|
||||
}
|
||||
} else if (type == 'continue' && modifier == 'straight') {
|
||||
instruction = "استمر بشكل مستقيم";
|
||||
instruction = "Continue straight".tr;
|
||||
}
|
||||
|
||||
return instruction;
|
||||
@@ -1767,23 +1768,23 @@ class MapDriverController extends GetxController {
|
||||
String _getTurnInstruction(String modifier) {
|
||||
switch (modifier) {
|
||||
case 'uturn':
|
||||
return "قم بالاستدارة والعودة";
|
||||
return "Make a U-turn".tr;
|
||||
case 'sharp right':
|
||||
return "انعطف يمينًا بحدة";
|
||||
return "Turn sharp right".tr;
|
||||
case 'right':
|
||||
return "انعطف يمينًا";
|
||||
return "Turn right".tr;
|
||||
case 'slight right':
|
||||
return "انعطف يمينًا قليلاً";
|
||||
return "Turn slight right".tr;
|
||||
case 'straight':
|
||||
return "استمر بشكل مستقيم";
|
||||
return "Continue straight".tr;
|
||||
case 'slight left':
|
||||
return "انعطف يسارًا قليلاً";
|
||||
return "Turn slight left".tr;
|
||||
case 'left':
|
||||
return "انعطف يسارًا";
|
||||
return "Turn left".tr;
|
||||
case 'sharp left':
|
||||
return "انعطف يسارًا بحدة";
|
||||
return "Turn sharp left".tr;
|
||||
default:
|
||||
return "اتجه";
|
||||
return "Head".tr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1850,7 +1851,7 @@ class MapDriverController extends GetxController {
|
||||
void _advanceStep() {
|
||||
if (currentStepIndex >= _stepBounds.length - 1) {
|
||||
// وصل للنهاية
|
||||
currentInstruction = "لقد وصلت إلى وجهتك";
|
||||
currentInstruction = "You have arrived at your destination".tr;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1909,11 +1910,11 @@ class MapDriverController extends GetxController {
|
||||
routeColor: Colors.blue);
|
||||
} else {
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
mySnackeBarError("يجب أن تكون أقرب من 100 متر للوصول");
|
||||
mySnackeBarError("You must be closer than 100 meters to arrive".tr);
|
||||
}
|
||||
} catch (e) {
|
||||
if (Get.isDialogOpen == true) Get.back();
|
||||
mySnackeBarError("حدث خطأ في الاتصال");
|
||||
mySnackeBarError("A connection error occurred".tr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1941,9 +1942,7 @@ class MapDriverController extends GetxController {
|
||||
|
||||
// 2. فك تشفير البوليلاين الخاص بالخطوة وتحويله إلى LatLng
|
||||
// -->> هنا تم التصحيح <<--
|
||||
List<LatLng> pts = decodePolyline(s['polyline']['points'])
|
||||
.map((point) => LatLng(point[0].toDouble(), point[1].toDouble()))
|
||||
.toList();
|
||||
List<LatLng> pts = PolylineUtils.decode(s['polyline']['points']);
|
||||
|
||||
// أضف نقاط البداية والنهاية إذا لم تكن موجودة في البوليلاين لضمان دقة الحدود
|
||||
if (pts.isNotEmpty) {
|
||||
@@ -1962,14 +1961,9 @@ class MapDriverController extends GetxController {
|
||||
// A helper function to decode and convert the polyline string
|
||||
List<LatLng> decodePolylineToLatLng(String polylineString) {
|
||||
// 1. Decode the string into a list of number lists (e.g., [[lat, lng], ...])
|
||||
List<List<num>> decodedPoints = decodePolyline(polylineString);
|
||||
List<LatLng> decodedPoints = PolylineUtils.decode(polylineString);
|
||||
|
||||
// 2. Map each [lat, lng] pair to a LatLng object, ensuring conversion to double
|
||||
List<LatLng> latLngPoints = decodedPoints
|
||||
.map((point) => LatLng(point[0].toDouble(), point[1].toDouble()))
|
||||
.toList();
|
||||
|
||||
return latLngPoints;
|
||||
return decodedPoints;
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
@@ -1986,11 +1980,11 @@ class MapDriverController extends GetxController {
|
||||
|
||||
void _suggestOptimization() {
|
||||
Get.snackbar(
|
||||
"تحسين أداء التطبيق",
|
||||
"لضمان أفضل تجربة، نقترح تعديل الإعدادات لتناسب جهازك. هل تود المتابعة؟",
|
||||
"Improve app performance".tr,
|
||||
"To ensure the best experience, we suggest adjusting the settings to suit your device. Would you like to proceed?".tr,
|
||||
duration: const Duration(seconds: 15),
|
||||
mainButton: TextButton(
|
||||
child: const Text("نعم، قم بالتحسين"),
|
||||
child: Text("Yes, optimize".tr),
|
||||
onPressed: () {
|
||||
updateInterval.value = 8; // غير الفترة إلى 8 ثوانٍ
|
||||
// save setting to shared_preferences
|
||||
@@ -2017,7 +2011,8 @@ class MapDriverController extends GetxController {
|
||||
|
||||
Future<void> _fitToBounds(LatLngBounds b, {double padding = 60}) async {
|
||||
// نستخدم الدالة الآمنة التي أنشأناها
|
||||
await safeAnimateCamera(CameraUpdate.newLatLngBounds(b, padding));
|
||||
await safeAnimateCamera(CameraUpdate.newLatLngBounds(b,
|
||||
left: padding, top: padding, right: padding, bottom: padding));
|
||||
}
|
||||
|
||||
double distanceBetweenDriverAndPassengerWhenConfirm = 0;
|
||||
@@ -2154,7 +2149,8 @@ class MapDriverController extends GetxController {
|
||||
LatLngBounds(northeast: northeast, southwest: southwest);
|
||||
|
||||
// Fit the camera to the bounds
|
||||
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 140);
|
||||
var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData,
|
||||
left: 140, top: 140, right: 140, bottom: 140);
|
||||
safeAnimateCamera(cameraUpdate);
|
||||
}
|
||||
|
||||
@@ -2395,22 +2391,19 @@ class MapDriverController extends GetxController {
|
||||
polyLines.removeWhere((p) => p.polylineId.value == 'upcoming_route');
|
||||
polyLines.removeWhere((p) => p.polylineId.value == 'traveled_route');
|
||||
|
||||
// المسار المتبقي (أزرق)
|
||||
// المسار المتبقي
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId('upcoming_route'),
|
||||
polylineId: const PolylineId("upcoming_route"),
|
||||
points: remaining,
|
||||
color: Colors.blue,
|
||||
width: 8,
|
||||
zIndex: 2,
|
||||
startCap: Cap.roundCap,
|
||||
endCap: Cap.roundCap,
|
||||
color: isRideStarted ? Colors.blue : Colors.yellow,
|
||||
));
|
||||
|
||||
// المسار المقطوع (رمادي)
|
||||
polyLines.add(Polyline(
|
||||
polylineId: const PolylineId('traveled_route'),
|
||||
points: traveled,
|
||||
color: Colors.grey.withOpacity(0.8),
|
||||
color: Colors.grey.withValues(alpha: 0.8),
|
||||
width: 7,
|
||||
zIndex: 1,
|
||||
));
|
||||
|
||||
Reference in New Issue
Block a user