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