fix: stabilize passenger mapping interactions and finalize localization
This commit is contained in:
2
.env
2
.env
@@ -113,4 +113,4 @@ W=T
|
||||
X=D
|
||||
Y=S
|
||||
Z=M
|
||||
mapSaasKey=zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX
|
||||
mapSaasKey=in_9478b32836d19cff73db3063
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
// في ملف: constant/country_polygons.dart
|
||||
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
class CountryPolygons {
|
||||
// ==========================================================
|
||||
|
||||
@@ -17,6 +17,8 @@ class AppLink {
|
||||
'https://map-saas.intaleqapp.com/api/geocoding/reverse';
|
||||
static String searchGeocoding =
|
||||
'https://map-saas.intaleqapp.com/api/geocoding/search';
|
||||
static String mapSaasPlaces =
|
||||
'https://map-saas.intaleqapp.com/api/geocoding/places';
|
||||
|
||||
///https://location.intaleq.xyz/intaleq/ride/location
|
||||
///locationServerSide هو السيرفر الجانبي الخاص بموقع السائقين، حيث يتم إرسال تحديثات الموقع من التطبيق إلى هذا السيرفر، ومن ثم يقوم هذا السيرفر بتوزيع هذه التحديثات إلى الركاب المتصلين الذين يتابعون السائق في الوقت الحقيقي.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
class UniversitiesPolygons {
|
||||
// AUC polygon points
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:Intaleq/constant/api_key.dart';
|
||||
import 'package:Intaleq/controller/firebase/firbase_messge.dart';
|
||||
import 'package:Intaleq/views/auth/otp_page.dart';
|
||||
@@ -10,7 +10,7 @@ import 'package:http/http.dart' as http;
|
||||
import 'package:Intaleq/constant/info.dart';
|
||||
import 'package:Intaleq/controller/functions/add_error.dart';
|
||||
import 'package:Intaleq/views/auth/login_page.dart';
|
||||
import 'package:Intaleq/views/auth/sms_verfy_page.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
@@ -18,17 +18,16 @@ import 'package:Intaleq/constant/links.dart';
|
||||
import 'package:Intaleq/controller/functions/crud.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:Intaleq/views/home/map_page_passenger.dart';
|
||||
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||
import 'package:location/location.dart';
|
||||
import 'package:secure_string_operations/secure_string_operations.dart';
|
||||
|
||||
import '../../constant/char_map.dart';
|
||||
import 'package:location/location.dart';
|
||||
|
||||
|
||||
|
||||
import '../../print.dart';
|
||||
import '../../views/auth/otp_token_page.dart';
|
||||
import '../functions/encrypt_decrypt.dart';
|
||||
import '../functions/package_info.dart';
|
||||
import '../functions/secure_storage.dart';
|
||||
import '../functions/securty_check.dart';
|
||||
|
||||
|
||||
class LoginController extends GetxController {
|
||||
final formKey = GlobalKey<FormState>();
|
||||
@@ -88,20 +87,7 @@ class LoginController extends GetxController {
|
||||
update();
|
||||
}
|
||||
|
||||
void _showJwtErrorDialog(String message) {
|
||||
if (Get.context == null) return;
|
||||
|
||||
Get.defaultDialog(
|
||||
title: "خطأ في الاتصال",
|
||||
middleText: message,
|
||||
textConfirm: "إعادة المحاولة",
|
||||
confirmTextColor: Colors.white,
|
||||
onConfirm: () {
|
||||
Get.back();
|
||||
getJwtWallet();
|
||||
},
|
||||
);
|
||||
}
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// LoginController — دوال إدارة الـ JWT
|
||||
// ───────────────────────────────────────────────────────────────
|
||||
@@ -141,8 +127,8 @@ class LoginController extends GetxController {
|
||||
);
|
||||
Log.print('AppLink.loginFirstTime: ${AppLink.loginFirstTime}');
|
||||
|
||||
Log.print('payload: ${payload}');
|
||||
Log.print('response: ${response}');
|
||||
Log.print('payload: $payload');
|
||||
Log.print('response: $response');
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = jsonDecode(response.body);
|
||||
@@ -169,7 +155,7 @@ class LoginController extends GetxController {
|
||||
);
|
||||
Log.print('AppLink.loginJwtRider: ${AppLink.loginJwtRider}');
|
||||
|
||||
Log.print('payload: ${payload}');
|
||||
Log.print('payload: $payload');
|
||||
Log.print('response: ${response.body}');
|
||||
if (response.statusCode == 200) {
|
||||
final decoded = jsonDecode(response.body);
|
||||
@@ -361,7 +347,7 @@ class LoginController extends GetxController {
|
||||
}
|
||||
|
||||
Get.offAll(() => const MapPagePassenger());
|
||||
} catch (e, st) {
|
||||
} catch (e) {
|
||||
addError('$e', 'loginUsingCredentials');
|
||||
Get.snackbar('Error', e.toString(), backgroundColor: Colors.redAccent);
|
||||
} finally {
|
||||
@@ -433,7 +419,7 @@ class LoginController extends GetxController {
|
||||
}
|
||||
}
|
||||
|
||||
goToMapPage() {
|
||||
void goToMapPage() {
|
||||
if (box.read(BoxName.email) != null) {
|
||||
Get.offAll(() => const MapPagePassenger());
|
||||
}
|
||||
|
||||
@@ -675,4 +675,32 @@ class CRUD {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<dynamic> postMapSaas({
|
||||
required String link,
|
||||
required Map<String, dynamic> payload,
|
||||
}) async {
|
||||
var url = Uri.parse(link);
|
||||
try {
|
||||
var response = await http.post(
|
||||
url,
|
||||
body: jsonEncode(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-api-key': Env.mapSaasKey,
|
||||
},
|
||||
);
|
||||
Log.print('post -MapSaas link: $link');
|
||||
Log.print('post -MapSaas payload: $payload');
|
||||
Log.print('post -MapSaas response: ${response.body}');
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
return jsonDecode(response.body);
|
||||
}
|
||||
Log.print('MapSaas Post Error: ${response.statusCode} - ${response.body}');
|
||||
return null;
|
||||
} catch (e) {
|
||||
Log.print('MapSaas Post Exception: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
List<LatLng> decodePolylineIsolate(String encoded) {
|
||||
List<LatLng> points = [];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:Intaleq/constant/style.dart';
|
||||
import 'package:Intaleq/controller/home/map_passenger_controller.dart';
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ import 'package:Intaleq/controller/functions/crud.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
class TripMonitorController extends GetxController {
|
||||
bool isLoading = false;
|
||||
Map tripData = {};
|
||||
late String rideId;
|
||||
late String driverId;
|
||||
MapLibreMapController? mapController;
|
||||
IntaleqMapController? mapController;
|
||||
List myListString = [];
|
||||
late Timer timer;
|
||||
late LatLng parentLocation;
|
||||
@@ -23,6 +23,8 @@ class TripMonitorController extends GetxController {
|
||||
double rotation = 0;
|
||||
double speed = 0;
|
||||
bool isStyleLoaded = false;
|
||||
|
||||
Set<Marker> markers = {};
|
||||
|
||||
getLocationParent() async {
|
||||
var res = await CRUD().get(
|
||||
@@ -34,76 +36,56 @@ class TripMonitorController extends GetxController {
|
||||
double.parse(tripData['message'][0]['longitude'].toString()));
|
||||
rotation = double.parse(tripData['message'][0]['heading'].toString());
|
||||
speed = double.parse(tripData['message'][0]['speed'].toString());
|
||||
|
||||
_updateMarker();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void onMapCreated(MapLibreMapController controller) async {
|
||||
void onMapCreated(IntaleqMapController controller) async {
|
||||
mapController = controller;
|
||||
update();
|
||||
}
|
||||
|
||||
void onStyleLoaded() async {
|
||||
isStyleLoaded = true;
|
||||
await _loadMapIcons();
|
||||
mapController?.animateCamera(
|
||||
CameraUpdate.newLatLng(parentLocation),
|
||||
);
|
||||
refreshMapElements();
|
||||
_updateMarker();
|
||||
|
||||
// Set up a timer or interval to trigger the marker update every 10 seconds.
|
||||
timer = Timer.periodic(const Duration(seconds: 10), (_) async {
|
||||
await getLocationParent();
|
||||
mapController?.animateCamera(CameraUpdate.newLatLng(parentLocation));
|
||||
refreshMapElements();
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _loadMapIcons() async {
|
||||
if (mapController == null) return;
|
||||
final icons = {
|
||||
'car': 'assets/images/car.png',
|
||||
'moto': 'assets/images/moto1.png',
|
||||
'lady': 'assets/images/lady1.png',
|
||||
};
|
||||
for (var entry in icons.entries) {
|
||||
final bytes = await rootBundle.load(entry.value);
|
||||
await mapController!.addImage(entry.key, bytes.buffer.asUint8List());
|
||||
}
|
||||
}
|
||||
|
||||
void refreshMapElements() async {
|
||||
if (!isStyleLoaded || mapController == null) return;
|
||||
await mapController!.clearSymbols();
|
||||
|
||||
String iconToUse = carIcon;
|
||||
void _updateMarker() {
|
||||
String iconPath = 'assets/images/car.png';
|
||||
if (tripData['message'] != null && tripData['message'].isNotEmpty) {
|
||||
final model = tripData['message'][0]['model'].toString();
|
||||
final gender = tripData['message'][0]['gender'].toString();
|
||||
if (model.contains('دراجة')) {
|
||||
iconToUse = motoIcon;
|
||||
iconPath = 'assets/images/moto1.png';
|
||||
} else if (gender == 'Female') {
|
||||
iconToUse = ladyIcon;
|
||||
iconPath = 'assets/images/lady1.png';
|
||||
}
|
||||
}
|
||||
|
||||
await mapController!.addSymbol(SymbolOptions(
|
||||
geometry: parentLocation,
|
||||
iconImage: iconToUse,
|
||||
iconRotate: rotation,
|
||||
textField: 'driver',
|
||||
textOpacity: 0,
|
||||
));
|
||||
markers = {
|
||||
Marker(
|
||||
markerId: const MarkerId('driver'),
|
||||
position: parentLocation,
|
||||
icon: InlqBitmap.fromAsset(iconPath),
|
||||
rotation: rotation,
|
||||
anchor: const Offset(0.5, 0.5),
|
||||
),
|
||||
};
|
||||
update();
|
||||
}
|
||||
|
||||
// init() async {
|
||||
// final arguments = Get.arguments;
|
||||
// driverId = arguments['driverId'];
|
||||
// rideId = arguments['rideId'];
|
||||
// await getLocationParent();
|
||||
// }
|
||||
|
||||
Future<void> init({String? rideId, String? driverId}) async {
|
||||
this.driverId = driverId!;
|
||||
this.rideId = rideId!;
|
||||
@@ -120,7 +102,6 @@ class TripMonitorController extends GetxController {
|
||||
void onClose() {
|
||||
timer.cancel();
|
||||
mapController = null;
|
||||
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ class MyTranslation extends Translations {
|
||||
"Email Support": "الدعم عبر البريد الإلكتروني",
|
||||
"For official inquiries": "للاستفسارات الرسمية",
|
||||
"Intaleq Support": "دعم انطلق",
|
||||
'Change Home location ?': 'تغيير موقع المنزل؟',
|
||||
'Change Work location ?': 'تغيير موقع العمل؟',
|
||||
"Reach out to us via": "تواصل معنا عبر",
|
||||
"Support is Away": "الدعم غير متاح حالياً",
|
||||
"Support is currently Online": "الدعم متاح حالياً",
|
||||
|
||||
26306
lib/env/env.g.dart
vendored
26306
lib/env/env.g.dart
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:get_storage/get_storage.dart';
|
||||
import 'dart:math' as math;
|
||||
import '../../main.dart';
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import 'dart:io';
|
||||
import 'package:Intaleq/controller/home/trip_monitor_controller.dart';
|
||||
import 'package:Intaleq/env/env.dart';
|
||||
import 'package:Intaleq/views/widgets/my_scafold.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:vibration/vibration.dart';
|
||||
|
||||
import '../../../../constant/colors.dart';
|
||||
@@ -23,15 +24,16 @@ class TripMonitor extends StatelessWidget {
|
||||
return MyScafolld(
|
||||
title: 'Trip Monitor'.tr,
|
||||
body: [
|
||||
MapLibreMap(
|
||||
IntaleqMap(
|
||||
apiKey: Env.mapSaasKey,
|
||||
onMapCreated: tripMonitorController.onMapCreated,
|
||||
onStyleLoadedCallback: tripMonitorController.onStyleLoaded,
|
||||
onStyleLoaded: tripMonitorController.onStyleLoaded,
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: tripMonitorController.parentLocation,
|
||||
zoom: 16,
|
||||
tilt: 40,
|
||||
),
|
||||
styleString: "assets/style.json",
|
||||
markers: tripMonitorController.markers,
|
||||
),
|
||||
speedCircle()
|
||||
],
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:Intaleq/controller/home/trip_monitor_controller.dart';
|
||||
import 'package:Intaleq/env/env.dart';
|
||||
import 'package:Intaleq/views/widgets/my_scafold.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:vibration/vibration.dart';
|
||||
|
||||
import '../../../../constant/colors.dart';
|
||||
@@ -30,15 +31,16 @@ class TripMonitor extends StatelessWidget {
|
||||
return MyScafolld(
|
||||
title: 'Trip Monitor'.tr,
|
||||
body: [
|
||||
MapLibreMap(
|
||||
IntaleqMap(
|
||||
apiKey: Env.mapSaasKey,
|
||||
onMapCreated: tripMonitorController.onMapCreated,
|
||||
onStyleLoadedCallback: tripMonitorController.onStyleLoaded,
|
||||
onStyleLoaded: controller.onStyleLoaded,
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: tripMonitorController.parentLocation,
|
||||
zoom: 16,
|
||||
tilt: 40,
|
||||
),
|
||||
styleString: "assets/style.json",
|
||||
markers: tripMonitorController.markers,
|
||||
),
|
||||
speedCircle()
|
||||
],
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'package:Intaleq/print.dart';
|
||||
import 'package:Intaleq/views/widgets/mydialoug.dart';
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:Intaleq/constant/box_name.dart';
|
||||
import 'package:Intaleq/constant/table_names.dart';
|
||||
import 'package:Intaleq/views/widgets/elevated_btn.dart';
|
||||
@@ -131,8 +132,7 @@ class _SearchFieldState extends State<_SearchField> {
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.controller.hintTextDestinationPoint,
|
||||
hintStyle: AppStyle.subtitle.copyWith(color: Colors.grey[600]),
|
||||
prefixIcon:
|
||||
Icon(Icons.search, color: AppColor.primaryColor),
|
||||
prefixIcon: Icon(Icons.search, color: AppColor.primaryColor),
|
||||
// --- [إصلاح] تم استبدال Obx بشرط بسيط لأن `setState` يعيد بناء الواجهة الآن ---
|
||||
suffixIcon: widget
|
||||
.controller.placeDestinationController.text.isNotEmpty
|
||||
@@ -365,6 +365,11 @@ class _SearchResults extends StatelessWidget {
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.passengerStartLocationFromMap = true;
|
||||
controller.isPickerShown = true;
|
||||
|
||||
// ✅ FIX: Draw the route after setting destination (matching the "Another Order" flow)
|
||||
controller.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
'${controller.myDestination.latitude},${controller.myDestination.longitude}');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,22 +412,18 @@ Widget _buildQuickActionButton({
|
||||
|
||||
void _showChangeLocationDialog(
|
||||
MapPassengerController controller, String locationType) {
|
||||
Get.defaultDialog(
|
||||
title: 'Change $locationType location?'.tr,
|
||||
middleText: '',
|
||||
confirm: MyElevatedButton(
|
||||
title: 'Yes'.tr,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
if (locationType == 'Work') {
|
||||
controller.workLocationFromMap = true;
|
||||
} else {
|
||||
controller.homeLocationFromMap = true;
|
||||
}
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
),
|
||||
MyDialog().getDialog(
|
||||
locationType == 'Work' ? 'Change Work location ?'.tr : 'Change Home location ?'.tr,
|
||||
'',
|
||||
() {
|
||||
if (locationType == 'Work') {
|
||||
controller.workLocationFromMap = true;
|
||||
} else {
|
||||
controller.homeLocationFromMap = true;
|
||||
}
|
||||
controller.changeMainBottomMenuMap();
|
||||
controller.changePickerShown();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -455,4 +456,4 @@ void _handleQuickAction(
|
||||
Log.print("Error handling quick action: $e");
|
||||
Toast.show(Get.context!, "Failed to get location".tr, AppColor.redColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:Intaleq/constant/table_names.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
@@ -16,8 +17,7 @@ GetBuilder<MapPassengerController> formSearchPlaces(int index) {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Container(
|
||||
decoration:
|
||||
BoxDecoration(color: AppColor.secondaryColor),
|
||||
decoration: BoxDecoration(color: AppColor.secondaryColor),
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(
|
||||
@@ -82,7 +82,15 @@ GetBuilder<MapPassengerController> formSearchPlaces(int index) {
|
||||
var res = controller.placeListResponseAll[index][i];
|
||||
return InkWell(
|
||||
onTap: () async {
|
||||
// ── Extract selected location ──
|
||||
final double lat = res['geometry']['location']['lat'];
|
||||
final double lng = res['geometry']['location']['lng'];
|
||||
final String placeName = res['name'].toString();
|
||||
final selectedLatLng = LatLng(lat, lng);
|
||||
|
||||
controller.changeHeightPlaces();
|
||||
|
||||
// ── Update start/end based on context ──
|
||||
if (controller.currentLocationToFormPlacesAll[index] ==
|
||||
true) {
|
||||
controller.newStartPointLocation =
|
||||
@@ -92,7 +100,20 @@ GetBuilder<MapPassengerController> formSearchPlaces(int index) {
|
||||
controller.newStartPointLocation;
|
||||
}
|
||||
|
||||
// ✅ FIX: Set the waypoint to the selected location
|
||||
controller.menuWaypoints[index] = selectedLatLng;
|
||||
controller.menuWaypointNames[index] = placeName;
|
||||
|
||||
// ✅ FIX: Update hint text and coordinates
|
||||
controller.convertHintTextPlaces(index, res);
|
||||
|
||||
// ✅ FIX: Draw the route with the updated waypoint
|
||||
final String start =
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}';
|
||||
final String dest =
|
||||
'${controller.myDestination.latitude},${controller.myDestination.longitude}';
|
||||
|
||||
await controller.getDirectionMap(start, dest);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import 'package:Intaleq/print.dart';
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:Intaleq/env/env.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:Intaleq/controller/home/points_for_rider_controller.dart';
|
||||
import 'package:Intaleq/services/offline_map_service.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import '../../../controller/home/map_passenger_controller.dart';
|
||||
import '../../widgets/mycircular.dart';
|
||||
import '../../widgets/mydialoug.dart';
|
||||
@@ -27,82 +25,53 @@ class GoogleMapPassengerWidget extends StatelessWidget {
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: MapLibreMap(
|
||||
attributionButtonPosition: AttributionButtonPosition.bottomLeft,
|
||||
attributionButtonMargins: null,
|
||||
child: IntaleqMap(
|
||||
apiKey: Env.mapSaasKey,
|
||||
styleUrl: Get.isDarkMode
|
||||
? 'assets/style_dark.json'
|
||||
: 'assets/style.json',
|
||||
onMapCreated: controller.onMapCreated,
|
||||
onStyleLoadedCallback: () => controller.onStyleLoaded(),
|
||||
styleString: Get.isDarkMode ? "assets/style_dark.json" : "assets/style.json",
|
||||
|
||||
// ✅ Performance: Smoother zoom limits for low-end devices
|
||||
minMaxZoomPreference: controller.lowPerf
|
||||
? const MinMaxZoomPreference(6, 17)
|
||||
: const MinMaxZoomPreference(6, 18),
|
||||
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: controller.passengerLocation,
|
||||
zoom: controller.lowPerf ? 14.5 : 15,
|
||||
),
|
||||
|
||||
// ✅ Map Settings
|
||||
myLocationEnabled: true,
|
||||
trackCameraPosition: true,
|
||||
|
||||
// ✅ Camera Movement Logic
|
||||
onStyleLoaded: controller.onStyleLoaded,
|
||||
onCameraMove: controller.onCameraMoveThrottled,
|
||||
onCameraIdle: () {
|
||||
if (controller.mapController != null) {
|
||||
final position = controller.mapController!.cameraPosition;
|
||||
if (position != null) {
|
||||
Log.print('✅ onCameraIdle targeted: ${position.target}');
|
||||
// 1. Always update current view target (for pickers)
|
||||
controller
|
||||
.updateCurrentLocationFromCamera(position.target);
|
||||
|
||||
// 2. Cache explicitly when panning around
|
||||
// Optional: Limit this to only cache smaller regions (1km) so it doesn't overload on fast panning
|
||||
OfflineMapService.instance.downloadRegion(position.target, radiusKm: 1.0);
|
||||
OfflineMapService.instance
|
||||
.downloadRegion(position.target, radiusKm: 1.0);
|
||||
} else {
|
||||
Log.print('⚠️ onCameraIdle: cameraPosition is NULL');
|
||||
}
|
||||
} else {
|
||||
Log.print('⚠️ onCameraIdle: mapController is NULL');
|
||||
}
|
||||
},
|
||||
|
||||
onMapLongClick: (point, latlng) {
|
||||
markers: controller.markers,
|
||||
polylines: controller.polyLines,
|
||||
polygons: controller.polygons,
|
||||
circles: controller.circles,
|
||||
initialCameraPosition: CameraPosition(
|
||||
target: controller.passengerLocation,
|
||||
zoom: controller.lowPerf ? 14.5 : 15,
|
||||
),
|
||||
myLocationEnabled: true,
|
||||
onTap: (latlng) => controller.hidePlaces(),
|
||||
onLongPress: (latlng) {
|
||||
MyDialog().getDialog('Are you want to go to this site'.tr, '',
|
||||
() async {
|
||||
controller.clearPolyline();
|
||||
if (controller.carsLocationByPassenger.isNotEmpty) {
|
||||
await controller.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
'${latlng.latitude},${latlng.longitude}',
|
||||
);
|
||||
Get.back(); // Close Dialog
|
||||
await controller.bottomSheet();
|
||||
controller.showBottomSheet1();
|
||||
} else {
|
||||
Get.back();
|
||||
Get.snackbar(
|
||||
'We Are Sorry That we dont have cars in your Location!'
|
||||
.tr,
|
||||
'',
|
||||
colorText: AppColor.redColor,
|
||||
duration: const Duration(seconds: 5),
|
||||
backgroundColor: AppColor.secondaryColor,
|
||||
icon: Icon(Icons.error, color: AppColor.redColor),
|
||||
titleText: Text('Error'.tr,
|
||||
style: TextStyle(color: AppColor.redColor)),
|
||||
messageText: Text(
|
||||
'We Are Sorry That we dont have cars in your Location!'
|
||||
.tr,
|
||||
style: AppStyle.title),
|
||||
);
|
||||
}
|
||||
controller.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
'${latlng.latitude},${latlng.longitude}',
|
||||
);
|
||||
controller.showBottomSheet1();
|
||||
});
|
||||
},
|
||||
|
||||
onMapClick: (point, latlng) {
|
||||
controller.hidePlaces();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:Intaleq/views/widgets/mycircular.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'dart:ui'; // مهم لإضافة تأثير الضبابية
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
|
||||
@@ -9,7 +9,7 @@ import 'package:Intaleq/controller/home/map_passenger_controller.dart';
|
||||
import 'package:Intaleq/main.dart';
|
||||
import 'package:Intaleq/views/home/map_widget.dart/form_search_places_destenation.dart';
|
||||
import 'package:Intaleq/views/widgets/elevated_btn.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/table_names.dart';
|
||||
import '../../widgets/error_snakbar.dart';
|
||||
@@ -607,26 +607,32 @@ class _MapPickerOverlay extends StatelessWidget {
|
||||
const _MapPickerOverlay({required this.controller});
|
||||
|
||||
String _getModeTitle(BuildContext context) {
|
||||
if (controller.isPickingWaypoint)
|
||||
if (controller.isPickingWaypoint) {
|
||||
return 'Move map to set stop'.tr +
|
||||
' ${controller.pickingWaypointIndex + 1}'.tr;
|
||||
if (controller.passengerStartLocationFromMap)
|
||||
}
|
||||
if (controller.passengerStartLocationFromMap) {
|
||||
return controller.isAnotherOreder
|
||||
? 'Now set the pickup point for the other person'.tr
|
||||
: 'Move map to your pickup point'.tr;
|
||||
if (controller.startLocationFromMap)
|
||||
}
|
||||
if (controller.startLocationFromMap) {
|
||||
return 'Move map to set start location'.tr;
|
||||
if (controller.workLocationFromMap)
|
||||
}
|
||||
if (controller.workLocationFromMap) {
|
||||
return 'Move map to your work location'.tr;
|
||||
if (controller.homeLocationFromMap)
|
||||
}
|
||||
if (controller.homeLocationFromMap) {
|
||||
return 'Move map to your home location'.tr;
|
||||
}
|
||||
return 'Move map to select destination'.tr;
|
||||
}
|
||||
|
||||
String _getConfirmLabel(BuildContext context) {
|
||||
if (controller.isPickingWaypoint) return 'Set as Stop'.tr;
|
||||
if (controller.passengerStartLocationFromMap)
|
||||
if (controller.passengerStartLocationFromMap) {
|
||||
return 'Confirm Pickup Location'.tr;
|
||||
}
|
||||
if (controller.workLocationFromMap) return 'Set as Work'.tr;
|
||||
if (controller.homeLocationFromMap) return 'Set as Home'.tr;
|
||||
return 'Set Destination'.tr;
|
||||
@@ -634,8 +640,9 @@ class _MapPickerOverlay extends StatelessWidget {
|
||||
|
||||
IconData _getModeIcon() {
|
||||
if (controller.isPickingWaypoint) return Icons.add_location_alt_rounded;
|
||||
if (controller.passengerStartLocationFromMap)
|
||||
if (controller.passengerStartLocationFromMap) {
|
||||
return Icons.person_pin_circle_rounded;
|
||||
}
|
||||
if (controller.workLocationFromMap) return Icons.work_rounded;
|
||||
if (controller.homeLocationFromMap) return Icons.home_rounded;
|
||||
return Icons.location_on_rounded;
|
||||
@@ -760,6 +767,8 @@ class _MapPickerOverlay extends StatelessWidget {
|
||||
|
||||
Future<void> _onConfirmTap(
|
||||
MapPassengerController controller, BuildContext context) async {
|
||||
Log.print(
|
||||
'🔘 _onConfirmTap: isPickingWaypoint=${controller.isPickingWaypoint}, newMyLocation=${controller.newMyLocation}');
|
||||
await Future.delayed(const Duration(milliseconds: 280));
|
||||
final LatLng currentCameraPosition = LatLng(
|
||||
controller.newMyLocation.latitude, controller.newMyLocation.longitude);
|
||||
@@ -905,7 +914,6 @@ class _RecentPlaceChip extends StatelessWidget {
|
||||
'Are you want to go this site'.tr,
|
||||
' ',
|
||||
() async {
|
||||
Get.back();
|
||||
await controller.getLocation();
|
||||
await controller.getDirectionMap(
|
||||
'${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}',
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../../../constant/box_name.dart';
|
||||
import '../../../constant/links.dart';
|
||||
@@ -47,7 +47,7 @@ class NavigationController extends GetxController
|
||||
static const int _offRouteTriggerSeconds = 6;
|
||||
|
||||
bool isLoading = false;
|
||||
MaplibreMapController? mapController;
|
||||
IntaleqMapController? mapController;
|
||||
bool isStyleLoaded = false;
|
||||
final TextEditingController placeDestinationController =
|
||||
TextEditingController();
|
||||
@@ -65,11 +65,10 @@ class NavigationController extends GetxController
|
||||
double currentSpeed = 0.0;
|
||||
double totalDistance = 0.0;
|
||||
|
||||
Symbol? carSymbol;
|
||||
Symbol? originSymbol;
|
||||
Symbol? destinationSymbol;
|
||||
Line? remainingRouteLine;
|
||||
Line? traveledRouteLine;
|
||||
Set<Marker> markers = {};
|
||||
Set<Polyline> polylines = {};
|
||||
Set<Circle> circles = {};
|
||||
Set<Polygon> polygons = {};
|
||||
|
||||
Timer? _locationUpdateTimer;
|
||||
LatLng? _lastProcessedLocation;
|
||||
@@ -102,6 +101,61 @@ class NavigationController extends GetxController
|
||||
bool _cameraLockedToUser = true;
|
||||
bool _mapReady = false;
|
||||
|
||||
bool isSelectingPlaceLocation = false;
|
||||
|
||||
void togglePlaceSelectionMode() {
|
||||
isSelectingPlaceLocation = !isSelectingPlaceLocation;
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> submitNewPlace(String name, String category) async {
|
||||
if (mapController == null || name.isEmpty || category.isEmpty) return;
|
||||
|
||||
// Get current center of the map as the picked location
|
||||
final LatLng pickedPos = mapController!.cameraPosition!.target;
|
||||
|
||||
isLoading = true;
|
||||
update();
|
||||
|
||||
final String country =
|
||||
box.read(BoxName.countryCode) == 'SY' ? 'syria' : 'jordan';
|
||||
|
||||
final Map<String, dynamic> payload = {
|
||||
'name': name,
|
||||
'category': category,
|
||||
'lat': pickedPos.latitude,
|
||||
'lng': pickedPos.longitude,
|
||||
'country': country,
|
||||
};
|
||||
|
||||
try {
|
||||
final response = await CRUD().postMapSaas(
|
||||
link: AppLink.mapSaasPlaces,
|
||||
payload: payload,
|
||||
);
|
||||
|
||||
isLoading = false;
|
||||
if (response != null) {
|
||||
HapticFeedback.lightImpact();
|
||||
mySnackbarSuccess(box.read(BoxName.lang) == 'ar'
|
||||
? 'تمت إضافة المكان بنجاح! شكراً لمساهمتك.'
|
||||
: 'Place added successfully! Thanks for your contribution.');
|
||||
isSelectingPlaceLocation = false;
|
||||
} else {
|
||||
mySnackbarWarning(box.read(BoxName.lang) == 'ar'
|
||||
? 'تعذر إضافة المكان. يرجى المحاولة لاحقاً.'
|
||||
: 'Failed to add place. Please try again later.');
|
||||
}
|
||||
update();
|
||||
} catch (e) {
|
||||
isLoading = false;
|
||||
mySnackbarWarning(box.read(BoxName.lang) == 'ar'
|
||||
? 'حدث خطأ أثناء الاتصال بالخادم.'
|
||||
: 'An error occurred while connecting to the server.');
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
DateTime? _offRouteStartTime;
|
||||
bool _autoRecalcInProgress = false;
|
||||
|
||||
@@ -114,7 +168,7 @@ class NavigationController extends GetxController
|
||||
|
||||
List<RouteData> routes = [];
|
||||
int selectedRouteIndex = 0;
|
||||
List<Line> alternativeRouteLines = [];
|
||||
|
||||
List<Map<String, dynamic>> recentLocations = [];
|
||||
|
||||
double get _targetZoom {
|
||||
@@ -131,6 +185,85 @@ class NavigationController extends GetxController
|
||||
return 55.0;
|
||||
}
|
||||
|
||||
// Categories list for the picker
|
||||
static final List<Map<String, String>> placeCategories = [
|
||||
{
|
||||
'id': 'restaurant',
|
||||
'en': 'Restaurant',
|
||||
'ar': 'مطعم',
|
||||
'icon': 'restaurant'
|
||||
},
|
||||
{'id': 'cafe', 'en': 'Cafe', 'ar': 'مقهى', 'icon': 'coffee'},
|
||||
{
|
||||
'id': 'supermarket',
|
||||
'en': 'Supermarket',
|
||||
'ar': 'سوبر ماركت',
|
||||
'icon': 'shopping_basket'
|
||||
},
|
||||
{
|
||||
'id': 'pharmacy',
|
||||
'en': 'Pharmacy',
|
||||
'ar': 'صيدلية',
|
||||
'icon': 'local_pharmacy'
|
||||
},
|
||||
{
|
||||
'id': 'gas_station',
|
||||
'en': 'Gas Station',
|
||||
'ar': 'محطة وقود',
|
||||
'icon': 'local_gas_station'
|
||||
},
|
||||
{'id': 'atm', 'en': 'ATM', 'ar': 'صراف آلي', 'icon': 'atm'},
|
||||
{'id': 'bank', 'en': 'Bank', 'ar': 'بنك', 'icon': 'account_balance'},
|
||||
{'id': 'mosque', 'en': 'Mosque', 'ar': 'مسجد', 'icon': 'mosque'},
|
||||
{
|
||||
'id': 'hospital',
|
||||
'en': 'Hospital',
|
||||
'ar': 'مستشفى',
|
||||
'icon': 'local_hospital'
|
||||
},
|
||||
{'id': 'school', 'en': 'School', 'ar': 'مدرسة', 'icon': 'school'},
|
||||
{
|
||||
'id': 'university',
|
||||
'en': 'University',
|
||||
'ar': 'جامعة',
|
||||
'icon': 'account_balance'
|
||||
},
|
||||
{'id': 'park', 'en': 'Park', 'ar': 'منتزه', 'icon': 'park'},
|
||||
{'id': 'hotel', 'en': 'Hotel', 'ar': 'فندق', 'icon': 'hotel'},
|
||||
{
|
||||
'id': 'mall',
|
||||
'en': 'Shopping Mall',
|
||||
'ar': 'مركز تسوق',
|
||||
'icon': 'shopping_mall'
|
||||
},
|
||||
{'id': 'gym', 'en': 'Gym', 'ar': 'نادي رياضي', 'icon': 'fitness_center'},
|
||||
{
|
||||
'id': 'salon',
|
||||
'en': 'Beauty Salon',
|
||||
'ar': 'صالون تجميل',
|
||||
'icon': 'content_cut'
|
||||
},
|
||||
{'id': 'bakery', 'en': 'Bakery', 'ar': 'مخبز', 'icon': 'bakery_dining'},
|
||||
{
|
||||
'id': 'laundry',
|
||||
'ar': 'مصبغة',
|
||||
'en': 'Laundry',
|
||||
'icon': 'local_laundry_service'
|
||||
},
|
||||
{
|
||||
'id': 'car_repair',
|
||||
'en': 'Car Repair',
|
||||
'ar': 'تصليح سيارات',
|
||||
'icon': 'build'
|
||||
},
|
||||
{
|
||||
'id': 'government',
|
||||
'en': 'Government Office',
|
||||
'ar': 'دائرة حكومية',
|
||||
'icon': 'gavel'
|
||||
},
|
||||
];
|
||||
|
||||
static final String _routeApiBaseUrl =
|
||||
"${AppLink.routesOsm}/route/v1/driving";
|
||||
|
||||
@@ -179,11 +312,11 @@ class NavigationController extends GetxController
|
||||
|
||||
if (isStyleLoaded) {
|
||||
_updateCarMarker();
|
||||
if (_fullRouteCoordinates.isNotEmpty && _cameraLockedToUser) {
|
||||
if (_cameraLockedToUser) {
|
||||
animateCameraToPosition(myLocation!,
|
||||
bearing: _smoothedHeading,
|
||||
zoom: _targetZoom,
|
||||
tilt: _targetTilt);
|
||||
zoom: isNavigating ? _targetZoom : 17.0,
|
||||
tilt: isNavigating ? _targetTilt : 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +341,7 @@ class NavigationController extends GetxController
|
||||
} else {
|
||||
parsed = [];
|
||||
}
|
||||
|
||||
|
||||
recentLocations = parsed
|
||||
.map((e) => Map<String, dynamic>.from(e))
|
||||
.toList()
|
||||
@@ -238,23 +371,29 @@ class NavigationController extends GetxController
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void onMapCreated(MaplibreMapController controller) {
|
||||
void onMapCreated(IntaleqMapController controller) async {
|
||||
Log.print("DEBUG: NavigationController.onMapCreated called");
|
||||
mapController = controller;
|
||||
await onStyleLoaded();
|
||||
}
|
||||
|
||||
Future<void> onStyleLoaded() async {
|
||||
Log.print("DEBUG: NavigationController.onStyleLoaded called");
|
||||
isStyleLoaded = true;
|
||||
await _loadCustomIcons();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
if (!_mapReady) {
|
||||
Log.print("DEBUG: NavigationController setting _mapReady = true");
|
||||
_mapReady = true;
|
||||
if (myLocation != null) {
|
||||
Log.print("DEBUG: Animating camera to initial location: $myLocation");
|
||||
animateCameraToPosition(myLocation!);
|
||||
_updateCarMarker();
|
||||
}
|
||||
if (_fullRouteCoordinates.isNotEmpty) {
|
||||
Log.print("DEBUG: Updating initial polylines");
|
||||
_updatePolylinesSets([], _fullRouteCoordinates);
|
||||
}
|
||||
}
|
||||
@@ -319,9 +458,11 @@ class NavigationController extends GetxController
|
||||
|
||||
Future<void> _getCurrentLocationAndStartUpdates() async {
|
||||
try {
|
||||
Log.print("DEBUG: Getting initial location...");
|
||||
final position = await Geolocator.getCurrentPosition(
|
||||
desiredAccuracy: LocationAccuracy.high);
|
||||
myLocation = LatLng(position.latitude, position.longitude);
|
||||
Log.print("DEBUG: Initial location acquired: $myLocation");
|
||||
_targetHeading = position.heading;
|
||||
_oldHeading = position.heading;
|
||||
_smoothedHeading = position.heading;
|
||||
@@ -330,7 +471,7 @@ class NavigationController extends GetxController
|
||||
_startLocationTimer();
|
||||
_startBatchTimers();
|
||||
} catch (e) {
|
||||
Log.print("Error getting initial location: $e");
|
||||
Log.print("DEBUG: Error getting initial location: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +481,10 @@ class NavigationController extends GetxController
|
||||
Timer.periodic(const Duration(seconds: 4), (_) => _tick());
|
||||
}
|
||||
|
||||
bool _isTicking = false;
|
||||
Future<void> _tick() async {
|
||||
if (_isTicking) return;
|
||||
_isTicking = true;
|
||||
try {
|
||||
final position = await Geolocator.getCurrentPosition(
|
||||
desiredAccuracy: LocationAccuracy.high);
|
||||
@@ -356,6 +500,8 @@ class NavigationController extends GetxController
|
||||
);
|
||||
if (d < _minMoveToProcess) return;
|
||||
}
|
||||
Log.print(
|
||||
"DEBUG: Location tick - Speed: ${currentSpeed.toStringAsFixed(1)} km/h, Loc: $newLoc");
|
||||
|
||||
if (_lastDistanceLocation != null) {
|
||||
final d = Geolocator.distanceBetween(
|
||||
@@ -396,7 +542,9 @@ class NavigationController extends GetxController
|
||||
}
|
||||
update();
|
||||
} catch (e) {
|
||||
Log.print("Error occurred: $e");
|
||||
Log.print("DEBUG: Error in _tick: $e");
|
||||
} finally {
|
||||
_isTicking = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,32 +649,7 @@ class NavigationController extends GetxController
|
||||
}
|
||||
|
||||
Future<void> _updateCarMarker() async {
|
||||
if (myLocation == null || mapController == null || !isStyleLoaded) return;
|
||||
|
||||
// Check if symbol still exists in map controller's internal list
|
||||
bool exists =
|
||||
carSymbol != null && mapController!.symbols.contains(carSymbol);
|
||||
|
||||
if (!exists) {
|
||||
if (carSymbol != null) {
|
||||
try {
|
||||
await mapController!.removeSymbol(carSymbol!);
|
||||
} catch (_) {}
|
||||
}
|
||||
carSymbol = await mapController!.addSymbol(SymbolOptions(
|
||||
geometry: myLocation,
|
||||
iconImage: 'car_icon',
|
||||
iconSize: 1.6,
|
||||
iconRotate: _smoothedHeading,
|
||||
));
|
||||
} else {
|
||||
mapController!.updateSymbol(
|
||||
carSymbol!,
|
||||
SymbolOptions(
|
||||
geometry: myLocation,
|
||||
iconRotate: _smoothedHeading,
|
||||
));
|
||||
}
|
||||
// Car marker is now handled natively by myLocationEnabled: true.
|
||||
}
|
||||
|
||||
void animateCameraToPosition(LatLng position,
|
||||
@@ -618,49 +741,41 @@ class NavigationController extends GetxController
|
||||
|
||||
Future<void> _updatePolylinesSets(
|
||||
List<LatLng> traveled, List<LatLng> remaining) async {
|
||||
if (mapController == null || !isStyleLoaded) return;
|
||||
|
||||
// Clear old alternative lines
|
||||
for (var line in alternativeRouteLines) {
|
||||
await mapController!.removeLine(line);
|
||||
}
|
||||
alternativeRouteLines.clear();
|
||||
Log.print(
|
||||
"DEBUG: Updating polylines. Traveled: ${traveled.length}, Remaining: ${remaining.length}");
|
||||
Set<Polyline> newPolylines = {};
|
||||
|
||||
if (remainingRouteLine != null) {
|
||||
await mapController!.removeLine(remainingRouteLine!);
|
||||
}
|
||||
if (traveledRouteLine != null) {
|
||||
await mapController!.removeLine(traveledRouteLine!);
|
||||
}
|
||||
|
||||
// Render Alternative Routes first (so they are below)
|
||||
// Render Alternative Routes first
|
||||
for (int i = 0; i < routes.length; i++) {
|
||||
if (i == selectedRouteIndex) continue;
|
||||
final altLine = await mapController!.addLine(LineOptions(
|
||||
geometry: routes[i].coordinates,
|
||||
lineColor: '#B0BEC5', // Soft gray for alternatives
|
||||
lineWidth: 6.0,
|
||||
lineJoin: 'round',
|
||||
lineOpacity: 0.8,
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: PolylineId('alt_$i'),
|
||||
points: routes[i].coordinates,
|
||||
color: const Color(0xFFB0BEC5).withOpacity(0.8),
|
||||
width: 6,
|
||||
));
|
||||
alternativeRouteLines.add(altLine);
|
||||
}
|
||||
|
||||
if (remaining.isNotEmpty) {
|
||||
remainingRouteLine = await mapController!.addLine(LineOptions(
|
||||
geometry: remaining,
|
||||
lineColor: '#00e5ff', // Cyan/Blue for selected
|
||||
lineWidth: 8.0,
|
||||
lineJoin: 'round'));
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: const PolylineId('remaining'),
|
||||
points: remaining,
|
||||
color: const Color(0xFF00E5FF),
|
||||
width: 8,
|
||||
));
|
||||
}
|
||||
|
||||
if (traveled.isNotEmpty) {
|
||||
traveledRouteLine = await mapController!.addLine(LineOptions(
|
||||
geometry: traveled,
|
||||
lineColor: '#BDBDBD',
|
||||
lineWidth: 5.0,
|
||||
lineJoin: 'round',
|
||||
lineOpacity: 0.6));
|
||||
newPolylines.add(Polyline(
|
||||
polylineId: const PolylineId('traveled'),
|
||||
points: traveled,
|
||||
color: const Color(0xFFBDBDBD).withOpacity(0.6),
|
||||
width: 5,
|
||||
));
|
||||
}
|
||||
|
||||
polylines = newPolylines;
|
||||
update();
|
||||
}
|
||||
|
||||
void selectRoute(int index) {
|
||||
@@ -671,7 +786,7 @@ class NavigationController extends GetxController
|
||||
routeSteps = r.steps;
|
||||
_routeTotalDistanceM = r.distanceM;
|
||||
_routeTotalDurationS = r.durationS;
|
||||
|
||||
|
||||
_lastTraveledIndexInFullRoute = 0;
|
||||
_recomputeETA();
|
||||
_updatePolylinesSets([], _fullRouteCoordinates);
|
||||
@@ -763,7 +878,8 @@ class NavigationController extends GetxController
|
||||
routes.clear();
|
||||
final primaryPts = data['points']?.toString() ?? "";
|
||||
if (primaryPts.isNotEmpty) {
|
||||
final coords = await compute<String, List<LatLng>>(decodePolylineIsolate, primaryPts);
|
||||
final coords = await compute<String, List<LatLng>>(
|
||||
decodePolylineIsolate, primaryPts);
|
||||
routes.add(RouteData(
|
||||
coordinates: coords,
|
||||
steps: List<Map<String, dynamic>>.from(data['instructions'] ?? []),
|
||||
@@ -778,7 +894,8 @@ class NavigationController extends GetxController
|
||||
for (var alt in data['alternatives']) {
|
||||
final altPts = alt['points']?.toString() ?? "";
|
||||
if (altPts.isEmpty) continue;
|
||||
final altCoords = await compute<String, List<LatLng>>(decodePolylineIsolate, altPts);
|
||||
final altCoords = await compute<String, List<LatLng>>(
|
||||
decodePolylineIsolate, altPts);
|
||||
routes.add(RouteData(
|
||||
coordinates: altCoords,
|
||||
steps: List<Map<String, dynamic>>.from(alt['instructions'] ?? []),
|
||||
@@ -899,19 +1016,27 @@ class NavigationController extends GetxController
|
||||
try {
|
||||
_finalDestination = destination;
|
||||
await clearRoute(isNewRoute: true);
|
||||
if (isStyleLoaded && mapController != null) {
|
||||
destinationSymbol = await mapController!.addSymbol(SymbolOptions(
|
||||
geometry: destination,
|
||||
iconImage: 'dest_icon',
|
||||
iconSize: 1.0,
|
||||
textField: infoWindowTitle,
|
||||
textOffset: const Offset(0, 2)));
|
||||
if (myLocation != null) {
|
||||
originSymbol = await mapController!.addSymbol(SymbolOptions(
|
||||
geometry: myLocation, iconImage: 'start_icon', iconSize: 1.0));
|
||||
}
|
||||
|
||||
// Preserve car marker if it exists
|
||||
markers = markers.where((m) => m.markerId.value == 'car').toSet();
|
||||
|
||||
markers.add(Marker(
|
||||
markerId: const MarkerId('destination'),
|
||||
position: destination,
|
||||
icon: InlqBitmap.fromStyleImage('dest_icon'),
|
||||
infoWindow: infoWindowTitle.isNotEmpty
|
||||
? InfoWindow(title: infoWindowTitle)
|
||||
: InfoWindow.noText,
|
||||
));
|
||||
|
||||
if (myLocation != null) {
|
||||
markers.add(Marker(
|
||||
markerId: const MarkerId('origin'),
|
||||
position: myLocation!,
|
||||
icon: InlqBitmap.fromStyleImage('start_icon'),
|
||||
));
|
||||
await getRoute(myLocation!, destination);
|
||||
}
|
||||
if (myLocation != null) await getRoute(myLocation!, destination);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
update();
|
||||
@@ -928,32 +1053,27 @@ class NavigationController extends GetxController
|
||||
update();
|
||||
}
|
||||
|
||||
Future<void> clearEverything() async {
|
||||
placeDestinationController.clear();
|
||||
placesDestination = [];
|
||||
await clearRoute();
|
||||
}
|
||||
|
||||
Future<void> clearRoute({bool isNewRoute = false}) async {
|
||||
_offRouteStartTime = null;
|
||||
_autoRecalcInProgress = false;
|
||||
if (!isNewRoute) {
|
||||
if (destinationSymbol != null && mapController != null) {
|
||||
await mapController!.removeSymbol(destinationSymbol!);
|
||||
destinationSymbol = null;
|
||||
}
|
||||
if (originSymbol != null && mapController != null) {
|
||||
await mapController!.removeSymbol(originSymbol!);
|
||||
originSymbol = null;
|
||||
}
|
||||
if (remainingRouteLine != null && mapController != null) {
|
||||
await mapController!.removeLine(remainingRouteLine!);
|
||||
remainingRouteLine = null;
|
||||
}
|
||||
if (traveledRouteLine != null && mapController != null) {
|
||||
await mapController!.removeLine(traveledRouteLine!);
|
||||
traveledRouteLine = null;
|
||||
}
|
||||
markers = {};
|
||||
polylines = {};
|
||||
circles = {};
|
||||
polygons = {};
|
||||
_finalDestination = null;
|
||||
isNavigating = false;
|
||||
routes = [];
|
||||
await _flushBufferToServer();
|
||||
}
|
||||
routeSteps.clear();
|
||||
_fullRouteCoordinates.clear();
|
||||
routeSteps = [];
|
||||
_fullRouteCoordinates = [];
|
||||
_lastTraveledIndexInFullRoute = 0;
|
||||
currentInstruction = "";
|
||||
nextInstruction = "";
|
||||
@@ -964,6 +1084,10 @@ class NavigationController extends GetxController
|
||||
arrivalTime = "--:--";
|
||||
_routeTotalDistanceM = 0;
|
||||
_routeTotalDurationS = 0;
|
||||
|
||||
if (!isNewRoute) {
|
||||
await _updateCarMarker();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,11 @@
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:Intaleq/env/env.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/style.dart';
|
||||
@@ -413,7 +414,9 @@ class _RideDetailSheet extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _RideDetailSheetState extends State<_RideDetailSheet> {
|
||||
MapLibreMapController? _mc;
|
||||
IntaleqMapController? _mc;
|
||||
Set<Marker> _markers = {};
|
||||
Set<Polyline> _polylines = {};
|
||||
|
||||
LatLngBounds? get _bounds {
|
||||
final latDiff = (widget.start.latitude - widget.end.latitude).abs();
|
||||
@@ -431,7 +434,7 @@ class _RideDetailSheetState extends State<_RideDetailSheet> {
|
||||
);
|
||||
}
|
||||
|
||||
void _onMapCreated(MapLibreMapController c) => _mc = c;
|
||||
void _onMapCreated(IntaleqMapController c) => _mc = c;
|
||||
|
||||
Future<void> _onStyleLoaded() async {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
@@ -442,48 +445,45 @@ class _RideDetailSheetState extends State<_RideDetailSheet> {
|
||||
}
|
||||
|
||||
Future<void> _draw() async {
|
||||
final mc = _mc;
|
||||
if (mc == null || !mounted) return;
|
||||
if (!mounted) return;
|
||||
|
||||
try {
|
||||
final aData = await rootBundle.load('assets/images/A.png');
|
||||
await mc.addImage('det_start', aData.buffer.asUint8List());
|
||||
final bData = await rootBundle.load('assets/images/b.png');
|
||||
await mc.addImage('det_end', bData.buffer.asUint8List());
|
||||
} catch (_) {}
|
||||
setState(() {
|
||||
_polylines = {
|
||||
Polyline(
|
||||
polylineId: const PolylineId('route'),
|
||||
points: [widget.start, widget.end],
|
||||
color: AppColor.primaryColor,
|
||||
width: 4,
|
||||
),
|
||||
};
|
||||
|
||||
await mc.addLine(LineOptions(
|
||||
geometry: [widget.start, widget.end],
|
||||
lineColor:
|
||||
'#${AppColor.primaryColor.value.toRadixString(16).substring(2)}',
|
||||
lineWidth: 4.0,
|
||||
lineOpacity: 1.0,
|
||||
));
|
||||
await mc.addSymbol(SymbolOptions(
|
||||
geometry: widget.start,
|
||||
iconImage: 'det_start',
|
||||
iconSize: 0.8,
|
||||
iconAnchor: 'bottom',
|
||||
));
|
||||
await mc.addSymbol(SymbolOptions(
|
||||
geometry: widget.end,
|
||||
iconImage: 'det_end',
|
||||
iconSize: 0.8,
|
||||
iconAnchor: 'bottom',
|
||||
));
|
||||
_markers = {
|
||||
Marker(
|
||||
markerId: const MarkerId('start'),
|
||||
position: widget.start,
|
||||
icon: InlqBitmap.fromAsset('assets/images/A.png'),
|
||||
anchor: const Offset(0.5, 1.0),
|
||||
),
|
||||
Marker(
|
||||
markerId: const MarkerId('end'),
|
||||
position: widget.end,
|
||||
icon: InlqBitmap.fromAsset('assets/images/b.png'),
|
||||
anchor: const Offset(0.5, 1.0),
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
final b = _bounds;
|
||||
if (b != null) {
|
||||
await mc.animateCamera(CameraUpdate.newLatLngBounds(b,
|
||||
await _mc?.animateCamera(CameraUpdate.newLatLngBounds(b,
|
||||
left: 60, top: 60, right: 60, bottom: 60));
|
||||
} else {
|
||||
await mc.animateCamera(CameraUpdate.newLatLngZoom(widget.start, 14));
|
||||
await _mc?.animateCamera(CameraUpdate.newLatLngZoom(widget.start, 14));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_mc?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -524,14 +524,20 @@ class _RideDetailSheetState extends State<_RideDetailSheet> {
|
||||
topLeft: Radius.circular(16),
|
||||
topRight: Radius.circular(16),
|
||||
),
|
||||
child: MapLibreMap(
|
||||
styleString: 'assets/style.json',
|
||||
child: IntaleqMap(
|
||||
apiKey: Env.mapSaasKey,
|
||||
styleUrl: Get.isDarkMode
|
||||
? 'assets/style_dark.json'
|
||||
: 'assets/style.json',
|
||||
initialCameraPosition:
|
||||
CameraPosition(target: center, zoom: 12),
|
||||
onMapCreated: _onMapCreated,
|
||||
onStyleLoadedCallback: _onStyleLoaded,
|
||||
onMapCreated: (c) {
|
||||
_mc = c;
|
||||
_onStyleLoaded();
|
||||
},
|
||||
myLocationEnabled: false,
|
||||
trackCameraPosition: false,
|
||||
markers: _markers,
|
||||
polylines: _polylines,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -319,90 +319,100 @@ class MyDialog extends GetxController {
|
||||
HapticFeedback.mediumImpact();
|
||||
|
||||
Get.dialog(
|
||||
_DialogShell(
|
||||
child: _GlassCard(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// ── Body ──────────────────────────────────────────────
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 28, 24, 20),
|
||||
child: Column(
|
||||
children: [
|
||||
// Icon badge
|
||||
Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: (isDestructive
|
||||
? AppColor.redColor
|
||||
: AppColor.primaryColor)
|
||||
.withOpacity(0.1),
|
||||
border: Border.all(
|
||||
Builder(builder: (dialogContext) {
|
||||
return _DialogShell(
|
||||
child: _GlassCard(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// ── Body ──────────────────────────────────────────────
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 28, 24, 20),
|
||||
child: Column(
|
||||
children: [
|
||||
// Icon badge
|
||||
Container(
|
||||
width: 56,
|
||||
height: 56,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: (isDestructive
|
||||
? AppColor.redColor
|
||||
: AppColor.primaryColor)
|
||||
.withOpacity(0.2),
|
||||
.withOpacity(0.1),
|
||||
border: Border.all(
|
||||
color: (isDestructive
|
||||
? AppColor.redColor
|
||||
: AppColor.primaryColor)
|
||||
.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
icon ??
|
||||
(isDestructive
|
||||
? Icons.warning_amber_rounded
|
||||
: Icons.info_outline_rounded),
|
||||
color: isDestructive
|
||||
? AppColor.redColor
|
||||
: AppColor.primaryColor,
|
||||
size: 26,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Title
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.4,
|
||||
color: AppColor.writeColor,
|
||||
),
|
||||
),
|
||||
|
||||
if (midTitle != null && midTitle.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
midTitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
fontSize: 14.5,
|
||||
height: 1.5,
|
||||
color: Colors.grey[600],
|
||||
child: Icon(
|
||||
icon ??
|
||||
(isDestructive
|
||||
? Icons.warning_amber_rounded
|
||||
: Icons.info_outline_rounded),
|
||||
color: isDestructive
|
||||
? AppColor.redColor
|
||||
: AppColor.primaryColor,
|
||||
size: 26,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// TTS button
|
||||
_SpeakButton(
|
||||
texts: [title, if (midTitle.isNotEmpty) midTitle]),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
// Title
|
||||
Text(
|
||||
title,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.title.copyWith(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.4,
|
||||
color: AppColor.writeColor,
|
||||
),
|
||||
),
|
||||
|
||||
// ── Actions ───────────────────────────────────────────
|
||||
_ActionRow(
|
||||
onCancel: () => Get.back(),
|
||||
onConfirm: onPressed,
|
||||
confirmLabel: 'OK'.tr,
|
||||
isDestructive: isDestructive,
|
||||
),
|
||||
],
|
||||
if (midTitle != null && midTitle.isNotEmpty) ...[
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
midTitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
fontSize: 14.5,
|
||||
height: 1.5,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// TTS button
|
||||
_SpeakButton(
|
||||
texts: [title, if (midTitle.isNotEmpty) midTitle]),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Actions ───────────────────────────────────────────
|
||||
_ActionRow(
|
||||
onCancel: () =>
|
||||
Navigator.of(dialogContext, rootNavigator: true).pop(),
|
||||
onConfirm: () {
|
||||
// إغلاق الديالوج مباشرة باستخدام Navigator.pop
|
||||
Navigator.of(dialogContext, rootNavigator: true).pop();
|
||||
// تنفيذ الأمر بعد إغلاق الديالوج
|
||||
Future.delayed(const Duration(milliseconds: 100), () {
|
||||
onPressed();
|
||||
});
|
||||
},
|
||||
confirmLabel: 'OK'.tr,
|
||||
isDestructive: isDestructive,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
barrierDismissible: true,
|
||||
barrierColor: _DC.barrierColor,
|
||||
);
|
||||
@@ -493,7 +503,12 @@ class MyDialogContent extends GetxController {
|
||||
// ── Actions ───────────────────────────────────────────
|
||||
_ActionRow(
|
||||
onCancel: () => Get.back(),
|
||||
onConfirm: onPressed,
|
||||
onConfirm: () {
|
||||
Get.back(); // Dismiss dialog first
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
onPressed();
|
||||
});
|
||||
},
|
||||
confirmLabel: confirmLabel.tr,
|
||||
isDestructive: isDestructive,
|
||||
),
|
||||
|
||||
35
pubspec.lock
35
pubspec.lock
@@ -125,10 +125,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187"
|
||||
sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -141,10 +141,10 @@ packages:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "39ad4ca8a2876779737c60e4228b4bcd35d4352ef7e14e47514093edc012c734"
|
||||
sha256: "521daf8d189deb79ba474e43a696b41c49fb3987818dbacf3308f1e03673a75e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.1"
|
||||
version: "2.13.1"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -380,18 +380,18 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: envied
|
||||
sha256: "2ca9842c7f513ab527e4f35a58331d6f9a7f90f270b5ba501d73ff2d9fa449ff"
|
||||
sha256: cac8bf0df6c53bd3c3511a6ee295ba6b86e6547df25c8c8648fc479128d2317c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.4"
|
||||
envied_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: envied_generator
|
||||
sha256: "4ed57d61dccb8e546a811b6a3dc5ebcef24bdfe60febbbd6fef31342ab15f9e5"
|
||||
sha256: ac7c2d0871a25a917f145a42ca6b4596b81b97d71017a511e0b3ffa60067cf75
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
version: "1.3.4"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1037,7 +1037,7 @@ packages:
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
image:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image
|
||||
sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce
|
||||
@@ -1132,6 +1132,13 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.2"
|
||||
intaleq_maps:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "/Users/hamzaaleghwairyeen/development/App/map-saas/packages/flutter-sdk/"
|
||||
relative: false
|
||||
source: path
|
||||
version: "2.1.3"
|
||||
internet_connection_checker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1212,14 +1219,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
latlong2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: latlong2
|
||||
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.1"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1333,7 +1332,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
maplibre_gl:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: maplibre_gl
|
||||
sha256: d9773555ae4ebab94bbc3ae2176b077cfda486ec729eefe01e1613f164cb8410
|
||||
|
||||
14
pubspec.yaml
14
pubspec.yaml
@@ -41,9 +41,9 @@ dependencies:
|
||||
# camera: ^0.10.5+5 #to be remove
|
||||
flutter_widget_from_html: ^0.17.1
|
||||
local_auth: ^3.0.1
|
||||
# image: ^4.1.3 #to be remove
|
||||
image: ^4.1.3
|
||||
image_cropper: ^11.0.0
|
||||
envied: ^1.3.3
|
||||
envied: ^1.3.4
|
||||
# cached_network_image: ^3.3.0
|
||||
calendar_builder:
|
||||
path: ./packages/calendar_builder
|
||||
@@ -81,8 +81,8 @@ dependencies:
|
||||
internet_connection_checker: ^3.0.1
|
||||
connectivity_plus: ^6.1.5
|
||||
app_links: ^7.0.0
|
||||
latlong2: ^0.9.1
|
||||
maplibre_gl: ^0.25.0
|
||||
intaleq_maps:
|
||||
path: /Users/hamzaaleghwairyeen/development/App/map-saas/packages/flutter-sdk/
|
||||
socket_io_client: 1.0.2
|
||||
# home_widget: ^0.7.0+1
|
||||
|
||||
@@ -90,8 +90,8 @@ dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: ^6.0.0
|
||||
envied_generator: ^1.3.3
|
||||
build_runner: ^2.11.1
|
||||
envied_generator: ^1.3.4
|
||||
build_runner: ^2.13.1
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: "launcher_icon"
|
||||
@@ -131,6 +131,7 @@ flutter:
|
||||
- asset: assets/fonts/digit.ttf
|
||||
|
||||
dependency_overrides:
|
||||
|
||||
# record_platform_interface: "1.2.0"
|
||||
get:
|
||||
path: ./packages/get
|
||||
@@ -140,3 +141,4 @@ dependency_overrides:
|
||||
path: ./packages/calendar_builder
|
||||
flutter_paypal:
|
||||
path: ./packages/flutter_paypal
|
||||
|
||||
Reference in New Issue
Block a user