Fixes & Updates - 2026-06-01: Integrate Back-End v3 updates, fix call/connection issues across apps

This commit is contained in:
Hamza-Ayed
2026-06-01 23:36:27 +03:00
parent 118781fd66
commit 97945aa362
76 changed files with 19806 additions and 10822 deletions

View File

@@ -0,0 +1,436 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:intaleq_maps/intaleq_maps.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/links.dart';
import '../../../constant/style.dart';
import '../../../constant/info.dart';
import '../../../main.dart'; // contains global 'box'
import '../../../print.dart';
import '../../../services/emergency_signal_service.dart';
import '../../../views/widgets/elevated_btn.dart';
import '../../../views/widgets/mydialoug.dart';
import '../../../views/widgets/my_textField.dart';
import '../../../views/home/map_page_passenger.dart';
import '../../../views/widgets/error_snakbar.dart';
import '../../../models/model/painter_copoun.dart';
import '../../functions/launch.dart';
import '../../firebase/local_notification.dart';
import '../../firebase/notification_service.dart';
import '../../functions/crud.dart';
import '../../functions/tts.dart';
import 'ride_lifecycle_controller.dart';
import 'location_search_controller.dart';
import 'map_engine_controller.dart';
class UiInteractionsController extends GetxController {
TextEditingController sosPhonePassengerProfile = TextEditingController();
TextEditingController whatsAppLocationText = TextEditingController();
final sosFormKey = GlobalKey<FormState>();
@override
void onInit() {
super.onInit();
EmergencySignalService.instance.startListening(() {
final rideLifecycle = Get.find<RideLifecycleController>();
if (rideLifecycle.statusRide == 'Begin' ||
rideLifecycle.statusRide == 'start') {
Log.print("🚨 Emergency shake verified! Prompting SOS...");
sosPassenger();
}
});
}
Future<void> _ensureSosNumber(Function onSuccess) async {
String? storedPhone = box.read(BoxName.sosPhonePassenger);
if (storedPhone != null && storedPhone.isNotEmpty) {
onSuccess();
return;
}
sosPhonePassengerProfile.clear();
Get.defaultDialog(
title: 'Add SOS Phone'.tr,
titleStyle: AppStyle.title,
content: Form(
key: sosFormKey,
child: Column(
children: [
MyTextForm(
controller: sosPhonePassengerProfile,
label: 'insert sos phone'.tr,
hint: 'e.g. 0912345678 (Default +963)'.tr,
type: TextInputType.phone,
),
const SizedBox(height: 10),
Text(
"Note: If no country code is entered, it will be saved as Syrian (+963).".tr,
style: TextStyle(fontSize: 12, color: Colors.grey),
textAlign: TextAlign.center,
),
],
),
),
confirm: MyElevatedButton(
title: 'Save'.tr,
onPressed: () async {
if (sosFormKey.currentState!.validate()) {
Get.back();
var numberPhone =
formatSyrianPhoneNumber(sosPhonePassengerProfile.text);
await CRUD().post(
link: AppLink.updateprofile,
payload: {
'id': box.read(BoxName.passengerID),
'sosPhone': numberPhone,
},
);
box.write(BoxName.sosPhonePassenger, numberPhone);
onSuccess();
}
},
),
cancel: MyElevatedButton(
title: 'Cancel'.tr,
onPressed: () => Get.back(),
kolor: AppColor.redColor,
)
);
}
void sosPassenger() {
_ensureSosNumber(() {
Get.defaultDialog(
barrierDismissible: false,
title: "Emergency SOS".tr,
titleStyle: AppStyle.title.copyWith(color: AppColor.redColor),
content: Column(
children: [
Icon(Icons.warning_amber_rounded, size: 50, color: AppColor.redColor),
const SizedBox(height: 10),
Text(
"Do you want to send an emergency message to your SOS contact?".tr,
textAlign: TextAlign.center,
style: AppStyle.title,
),
],
),
confirm: MyElevatedButton(
title: "Send SOS".tr,
kolor: AppColor.redColor,
onPressed: () {
Get.back();
_shareTripDetailsSOS();
},
),
cancel: MyElevatedButton(
title: "I'm Safe".tr,
kolor: AppColor.greenColor,
onPressed: () {
Get.back();
},
),
);
});
}
void _shareTripDetailsSOS() {
final rideLifecycle = Get.find<RideLifecycleController>();
final locSearch = Get.find<LocationSearchController>();
String message = "**Emergency SOS from Passenger:**\n";
String origin = locSearch.startNameAddress;
String destination = locSearch.endNameAddress;
message += "* ${'Origin'.tr}: $origin\n";
message += "* ${'Destination'.tr}: $destination\n";
message += "* ${'Driver Name'.tr}: ${rideLifecycle.driverName}\n";
message +=
"* ${'Car'.tr}: ${rideLifecycle.make} - ${rideLifecycle.model} - ${rideLifecycle.licensePlate}\n";
message += "* ${'Phone'.tr}: ${rideLifecycle.driverPhone}\n\n";
message +=
"${'Location'.tr}: https://www.google.com/maps/search/?api=1&query=${locSearch.passengerLocation.latitude},${locSearch.passengerLocation.longitude}\n";
message += "Please help! Contact me as soon as possible.".tr;
launchCommunication(
'whatsapp', box.read(BoxName.sosPhonePassenger), message);
}
String formatSyrianPhone(String phone) {
phone = phone.replaceAll(' ', '').replaceAll('+', '');
if (phone.startsWith('00963')) {
phone = phone.replaceFirst('00963', '963');
}
if (phone.startsWith('0963')) {
phone = phone.replaceFirst('0963', '963');
}
if (phone.startsWith('963')) {
return phone;
}
if (phone.startsWith('09')) {
return '963' + phone.substring(1);
}
if (phone.startsWith('9') && phone.length == 9) {
return '963' + phone;
}
return phone;
}
String formatSyrianPhoneNumber(String phoneNumber) {
String trimmedPhone = phoneNumber.trim();
if (trimmedPhone.startsWith('09')) {
return '963${trimmedPhone.substring(1)}';
}
if (trimmedPhone.startsWith('963')) {
return trimmedPhone;
}
return '963$trimmedPhone';
}
void sendSMS(String to) async {
final rideLifecycle = Get.find<RideLifecycleController>();
String formattedDriverPhone =
rideLifecycle.driverPhone.replaceAll(' ', '').replaceAll('+', '');
String message =
'Hi! This is ${(box.read(BoxName.name).toString().split(' ')[0]).toString()}.\n I am using ${box.read(AppInformation.appName)} to ride with ${rideLifecycle.passengerName} as the driver. ${rideLifecycle.passengerName} \nis driving a ${rideLifecycle.model}\n with license plate ${rideLifecycle.licensePlate}.\n I am currently located at ${Get.find<LocationSearchController>().passengerLocation}.\n If you need to reach me, please contact the driver directly at\n\n $formattedDriverPhone.';
launchCommunication('sms', to, message);
}
void sendWhatsapp(String to) async {
final rideLifecycle = Get.find<RideLifecycleController>();
final locSearch = Get.find<LocationSearchController>();
String formattedPhone = formatSyrianPhone(to);
String message =
'${'${'Hi! This is'.tr} ${(box.read(BoxName.name).toString().split(' ')[0]).toString()}.\n${' I am using'.tr}'} ${AppInformation.appName}${' to ride with'.tr} ${rideLifecycle.passengerName}${' as the driver.'.tr} ${rideLifecycle.passengerName} \n${'is driving a '.tr}${rideLifecycle.model}\n${' with license plate '.tr}${rideLifecycle.licensePlate}.\n${' I am currently located at '.tr} https://www.google.com/maps/place/${locSearch.passengerLocation.latitude},${locSearch.passengerLocation.longitude}.\n${' If you need to reach me, please contact the driver directly at'.tr}\n\n ${rideLifecycle.driverPhone}.';
launchCommunication('whatsapp', formattedPhone, message);
}
Future<dynamic> driverArrivePassengerDialoge() {
final rideLifecycle = Get.find<RideLifecycleController>();
return Get.defaultDialog(
barrierDismissible: false,
title: 'Hi ,I Arrive your location'.tr,
titleStyle: AppStyle.title,
middleText: 'Please go to Car Driver'.tr,
middleTextStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'Ok I will go now.'.tr,
onPressed: () {
NotificationService.sendNotification(
target: rideLifecycle.driverToken.toString(),
title: 'Hi ,I will go now'.tr,
body: 'I will go now'.tr,
isTopic: false,
tone: 'ding',
driverList: [],
category: 'Hi ,I will go now',
);
Get.back();
rideLifecycle.remainingTime = 0;
rideLifecycle.update();
},
),
);
}
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
final textToSpeechController = Get.find<TextToSpeechController>();
Get.defaultDialog(
title: title,
titleStyle: AppStyle.title,
middleTextStyle: AppStyle.title,
content: Column(
children: [
IconButton(
onPressed: () async {
await textToSpeechController.speakText(title ?? midTitle!);
},
icon: const Icon(Icons.headphones),
),
Text(
midTitle!,
style: AppStyle.title,
)
],
),
confirm: MyElevatedButton(
title: 'Ok'.tr,
onPressed: onPressed,
kolor: AppColor.greenColor,
),
cancel: MyElevatedButton(
title: 'Cancel',
kolor: AppColor.redColor,
onPressed: () {
Get.back();
},
),
);
}
Future shareTripWithFamily() async {
_ensureSosNumber(() {
final rideLifecycle = Get.find<RideLifecycleController>();
String storedPhone = box.read(BoxName.sosPhonePassenger)!;
if (rideLifecycle.rideId == 'yet' || rideLifecycle.driverId.isEmpty) {
Get.snackbar("Alert".tr, "Wait for the trip to start first".tr);
return;
}
var numberPhone = formatSyrianPhoneNumber(storedPhone);
String trackingLink = rideLifecycle.generateTrackingLink(
rideLifecycle.rideId, rideLifecycle.driverId);
String message = """
مرحباً، تابع رحلتي مباشرة على تطبيق انطلق 🚗
يمكنك تتبع مسار الرحلة من هنا:
$trackingLink
السائق: ${rideLifecycle.passengerName}
السيارة: ${rideLifecycle.model} - ${rideLifecycle.licensePlate}
شكراً لاستخدامك انطلق!
"""
.tr;
String messageEn = """Hello, follow my trip live on Intaleq 🚗
Track my ride here:
$trackingLink
Driver: ${rideLifecycle.passengerName}
Car: ${rideLifecycle.model} - ${rideLifecycle.licensePlate}
Thank you for using Intaleq!
""";
String userLanguage = box.read(BoxName.lang) ?? 'ar';
message = (userLanguage == 'ar') ? message : messageEn;
Log.print("Sending WhatsApp to: $numberPhone");
launchCommunication('whatsapp', numberPhone, message);
box.write(BoxName.parentTripSelected, true);
update();
});
}
Future getTokenForParent() async {
_ensureSosNumber(() async {
String storedPhone = box.read(BoxName.sosPhonePassenger)!;
var numberPhone = formatSyrianPhoneNumber(storedPhone);
Log.print("Searching for Parent Token with Phone: $numberPhone");
var res = await CRUD()
.post(link: AppLink.getTokenParent, payload: {'phone': numberPhone});
if (res is Map<String, dynamic>) {
handleResponse(res);
} else {
try {
var decoded = jsonDecode(res);
handleResponse(decoded);
} catch (e) {
Log.print("Error parsing parent response: $res");
}
}
});
}
void handleResponse(Map<String, dynamic> res) {
final rideLifecycle = Get.find<RideLifecycleController>();
if (res['status'] == 'failure') {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(
title: "No user found".tr,
titleStyle: AppStyle.title,
content: Column(
children: [
Text(
"No passenger found for the given phone number".tr,
style: AppStyle.title,
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
"Send Intaleq app to him".tr,
style: AppStyle.title
.copyWith(color: AppColor.greenColor, fontSize: 14),
textAlign: TextAlign.center,
)
],
),
confirm: MyElevatedButton(
title: 'Send Invite'.tr,
onPressed: () {
Get.back();
var rawPhone = box.read(BoxName.sosPhonePassenger);
if (rawPhone == null) return;
var phone = formatSyrianPhoneNumber(rawPhone);
var message = '''Dear Friend,
🚀 I have just started an exciting trip on Intaleq!
Download the app to track my ride:
👉 Android: https://play.google.com/store/apps/details?id=com.Intaleq.intaleq&hl=en-US
👉 iOS: https://apps.apple.com/st/app/intaleq-rider/id6748075179
See you there!
Intaleq Team''';
launchCommunication('whatsapp', phone, message);
},
),
cancel: MyElevatedButton(
title: 'Cancel'.tr,
onPressed: () {
Get.back();
},
),
);
} else if (res['status'] == 'success') {
if (Get.isDialogOpen ?? false) Get.back();
Get.snackbar("Success".tr, "The invitation was sent successfully".tr,
backgroundColor: AppColor.greenColor, colorText: Colors.white);
List tokensData = res['data'];
for (var device in tokensData) {
String tokenParent = device['token'];
NotificationService.sendNotification(
category: "Trip Monitoring",
target: tokenParent,
title: "Trip Monitoring".tr,
body: "Click to track the trip".tr,
isTopic: false,
tone: 'tone1',
driverList: [rideLifecycle.rideId, rideLifecycle.driverId],
);
box.write(BoxName.tokenParent, tokenParent);
}
box.write(BoxName.parentTripSelected, true);
}
}
@override
void onClose() {
EmergencySignalService.instance.stopListening();
super.onClose();
}
}