change to map-saas api key and env - 2026-04-12

This commit is contained in:
Hamza-Ayed
2026-04-12 02:25:44 +03:00
parent 454276d1e0
commit 0aa1f15f25
16 changed files with 14974 additions and 13857 deletions

View File

@@ -12,7 +12,8 @@ class ContactUsController extends GetxController {
final TimeOfDay workStartTime = const TimeOfDay(hour: 10, minute: 0);
final TimeOfDay workEndTime = const TimeOfDay(hour: 16, minute: 0);
bool _isWithinWorkTime(TimeOfDay now) {
bool get isWorkTime {
final now = TimeOfDay.now();
return (now.hour > workStartTime.hour ||
(now.hour == workStartTime.hour &&
now.minute >= workStartTime.minute)) &&
@@ -20,6 +21,11 @@ class ContactUsController extends GetxController {
(now.hour == workEndTime.hour && now.minute <= workEndTime.minute));
}
/// Helper to format working hours for UI
String get workHoursString =>
'${workStartTime.hour.toString().padLeft(2, '0')}:${workStartTime.minute.toString().padLeft(2, '0')} - '
'${workEndTime.hour.toString().padLeft(2, '0')}:${workEndTime.minute.toString().padLeft(2, '0')}';
/// PHONE LIST (USED FOR CALLS + WHATSAPP)
final List<String> phoneNumbers = [
'+963952475734',
@@ -33,10 +39,24 @@ class ContactUsController extends GetxController {
return phoneNumbers[random.nextInt(phoneNumbers.length)];
}
/// SHOW DIALOG
/// DIRECT ACTIONS
void makeCall() {
if (isWorkTime) {
makePhoneCall(getRandomPhone());
}
}
void sendWhatsApp() {
launchCommunication('whatsapp', getRandomPhone(), 'Hello'.tr);
}
void sendEmail() {
launchCommunication('email', 'support@intaleqapp.com', 'Hello'.tr);
}
/// SHOW DIALOG (Optional legacy support)
void showContactDialog(BuildContext context) {
TimeOfDay now = TimeOfDay.now();
bool withinHours = _isWithinWorkTime(now);
bool withinHours = isWorkTime;
showCupertinoModalPopup(
context: context,
@@ -44,7 +64,6 @@ class ContactUsController extends GetxController {
title: Text('Contact Us'.tr),
message: Text('Choose a contact option'.tr),
actions: <Widget>[
/// 📞 CALL (RANDOM) — ONLY DURING WORK HOURS
if (withinHours)
CupertinoActionSheetAction(
child: Row(
@@ -55,12 +74,10 @@ class ContactUsController extends GetxController {
],
),
onPressed: () {
final phone = getRandomPhone();
makePhoneCall(phone);
Navigator.pop(context);
makeCall();
},
),
/// ⛔ OUTSIDE WORK HOURS — SHOW INFO
if (!withinHours)
CupertinoActionSheetAction(
child: Text(
@@ -70,8 +87,6 @@ class ContactUsController extends GetxController {
),
onPressed: () => Navigator.pop(context),
),
/// 💬 WHATSAPP (RANDOM)
CupertinoActionSheetAction(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
@@ -84,20 +99,18 @@ class ContactUsController extends GetxController {
],
),
onPressed: () {
final phone = getRandomPhone();
launchCommunication('whatsapp', phone, 'Hello'.tr);
Navigator.pop(context);
sendWhatsApp();
},
),
/// 📧 EMAIL
CupertinoActionSheetAction(
child: Text('Send Email'.tr),
onPressed: () => launchCommunication(
'email', 'support@intaleqapp.com', 'Hello'.tr),
onPressed: () {
Navigator.pop(context);
sendEmail();
},
),
],
/// ❌ CANCEL BUTTON
cancelButton: CupertinoActionSheetAction(
child: Text('Cancel'.tr),
onPressed: () => Navigator.pop(context),

View File

@@ -611,53 +611,56 @@ class MapPassengerController extends GetxController {
if (response.statusCode == 200) {
final responseData = json.decode(response.body);
if (responseData['code'] == 'Ok' || responseData['routes'] != null) {
var routeData = responseData['routes'][0];
// Support both old format (routes[0]) and new SaaS format (top-level)
var routeData = responseData['routes'] != null
? responseData['routes'][0]
: responseData;
// 2. تحديث المتغيرات (المسافة والوقت)
double durationSecondsRaw = (routeData['duration'] as num).toDouble();
int finalDurationSeconds =
(durationSecondsRaw * kDurationScalar).toInt();
double distanceMeters = (routeData['distance'] as num).toDouble();
// 2. تحديث المتغيرات (المسافة والوقت)
double durationSecondsRaw = (routeData['duration'] as num).toDouble();
int finalDurationSeconds =
(durationSecondsRaw * kDurationScalar).toInt();
double distanceMeters = (routeData['distance'] as num).toDouble();
timeToPassengerFromDriverAfterApplied = finalDurationSeconds;
remainingTimeToPassengerFromDriverAfterApplied = finalDurationSeconds;
distanceByPassenger = distanceMeters.toStringAsFixed(0);
timeToPassengerFromDriverAfterApplied = finalDurationSeconds;
remainingTimeToPassengerFromDriverAfterApplied = finalDurationSeconds;
distanceByPassenger = distanceMeters.toStringAsFixed(0);
// تحديث نصوص الواجهة
int minutes = (finalDurationSeconds / 60).floor();
int seconds = finalDurationSeconds % 60;
stringRemainingTimeToPassenger =
'$minutes:${seconds.toString().padLeft(2, '0')}';
// تحديث نصوص الواجهة
int minutes = (finalDurationSeconds / 60).floor();
int seconds = finalDurationSeconds % 60;
stringRemainingTimeToPassenger =
'$minutes:${seconds.toString().padLeft(2, '0')}';
Log.print(
'✅ Driver Route Info: $minutes min, ${distanceMeters.toInt()} m');
Log.print(
'✅ Driver Route Info: $minutes min, ${distanceMeters.toInt()} m');
// 3. معالجة الرسم (Polyline)
String pointsString = routeData['geometry'] ?? "";
if (pointsString.isNotEmpty) {
List<LatLng> decodedPoints =
await compute(decodePolylineIsolate, pointsString);
// حفظ نسخة للمقارنة
_currentDriverRoutePoints = decodedPoints;
// إزالة خط مسار السائق القديم فقط
polyLines = polyLines.where((p) => p.lineOpacity != 0.999).toList();
// 3. معالجة الرسم (Polyline)
// SaaS uses 'points', OSRM uses 'geometry'
String pointsString =
routeData['points'] ?? routeData['geometry'] ?? "";
if (pointsString.isNotEmpty) {
List<LatLng> decodedPoints =
await compute(decodePolylineIsolate, pointsString);
// حفظ نسخة للمقارنة
_currentDriverRoutePoints = decodedPoints;
// إزالة خط مسار السائق القديم فقط
polyLines = polyLines.where((p) => p.lineOpacity != 0.999).toList();
// إضافة الخط الجديد (بستايل مميز للسائق)
polyLines.add(LineOptions(
geometry: decodedPoints,
lineColor: '#333333', // لون مختلف عن مسار الرحلة الأساسي
lineWidth: 5,
lineOpacity: 0.999, // acting as ID
));
refreshMapElements();
}
// 4. ضبط الكاميرا لتشمل السائق والراكب
_fitCameraToPoints(driverPos, passengerPos);
update(); // تحديث واحد للكل
// إضافة الخط الجديد (بستايل مميز للسائق)
polyLines.add(LineOptions(
geometry: decodedPoints,
lineColor: '#333333', // لون مختلف عن مسار الرحلة الأساسي
lineWidth: 5,
lineOpacity: 0.999, // acting as ID
));
refreshMapElements();
}
// 4. ضبط الكاميرا لتشمل السائق والراكب
_fitCameraToPoints(driverPos, passengerPos);
update(); // تحديث واحد للكل
}
} catch (e) {
Log.print('❌ Error calculating driver route: $e');
@@ -6478,30 +6481,29 @@ Intaleq Team''';
double lngDest = double.parse(coordDestination[1]);
myDestination = LatLng(latDest, lngDest);
// ── 2. Routing Decision: Hybrid Strategy ──────────────────────────
final bool isSaaSRequest = activeMenuWaypointCount == 0;
// ── 2. Unified SaaS Routing Strategy ──────────────────────────
final bool isSaaSRequest = true;
Uri uri;
if (isSaaSRequest) {
// Mapping SaaS format: Query Parameters
var originCoords = origin.split(',');
final Map<String, String> queryParams = {
'fromLat': originCoords[0].trim(),
'fromLng': originCoords[1].trim(),
'toLat': latDest.toString(),
'toLng': lngDest.toString(),
};
uri =
Uri.parse(AppLink.mapSaasRoute).replace(queryParameters: queryParams);
} else {
// Legacy OSRM format for multi-waypoint support
var originCoords = origin.split(',');
String waypointCoords = _buildOsrmWaypointCoords();
String osrmUrl =
'${AppLink.routesOsm}/route/v1/driving/${originCoords[1]},${originCoords[0]}$waypointCoords;$lngDest,$latDest';
uri = Uri.parse('$osrmUrl?steps=false&overview=full');
var originCoords = origin.split(',');
final Map<String, String> queryParams = {
'fromLat': originCoords[0].trim(),
'fromLng': originCoords[1].trim(),
'toLat': latDest.toString(),
'toLng': lngDest.toString(),
};
// Add multi-stop waypoints to the query parameters
for (int i = 0; i < activeMenuWaypointCount; i++) {
final wp = menuWaypoints[i];
if (wp != null) {
queryParams['stop${i + 1}Lat'] = wp.latitude.toString();
queryParams['stop${i + 1}Lng'] = wp.longitude.toString();
}
}
uri = Uri.parse(AppLink.mapSaasRoute).replace(queryParameters: queryParams);
Log.print(
'Requesting Route URI (${isSaaSRequest ? "SaaS" : "OSRM"}, Attempt: ${attemptCount + 1}): $uri');

View File

@@ -7,6 +7,7 @@ import 'package:Intaleq/controller/functions/crud.dart';
import 'package:flutter/material.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:share_plus/share_plus.dart';
import '../../../main.dart';
@@ -107,7 +108,37 @@ ${'Download the Intaleq app now and enjoy your ride!'.tr}
/// tried to access the first phone number of a contact that had none.
Future<void> pickContacts() async {
try {
if (await FlutterContacts.requestPermission(readonly: true)) {
// 1. Check current permission status using permission_handler for better control
PermissionStatus status = await Permission.contacts.status;
// 2. If status is permanently denied, direct user to settings
if (status.isPermanentlyDenied) {
Get.defaultDialog(
title: 'Permission Required'.tr,
middleText:
'Contact permission is permanently denied. Please enable it in settings to continue.'
.tr,
textConfirm: 'Settings'.tr,
textCancel: 'Cancel'.tr,
confirmTextColor: Colors.white,
onConfirm: () {
openAppSettings();
Get.back();
},
);
return;
}
// 3. Request permission if not already granted
if (!status.isGranted) {
status = await Permission.contacts.request();
}
// 4. Proceed if granted
if (status.isGranted) {
// Also call flutter_contacts requestPermission to ensure it's synced (internal state)
await FlutterContacts.requestPermission(readonly: true);
final List<Contact> allContacts =
await FlutterContacts.getContacts(withProperties: true);
final int totalContactsOnDevice = allContacts.length;