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 '../../../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/my_textField.dart'; import '../../functions/launch.dart'; import '../../firebase/notification_service.dart'; import '../../functions/crud.dart'; import '../../functions/tts.dart'; import 'ride_lifecycle_controller.dart'; import 'location_search_controller.dart'; class UiInteractionsController extends GetxController { TextEditingController sosPhonePassengerProfile = TextEditingController(); TextEditingController whatsAppLocationText = TextEditingController(); final sosFormKey = GlobalKey(); @override void onInit() { super.onInit(); EmergencySignalService.instance.startListening(() { final rideLifecycle = Get.find(); if (rideLifecycle.statusRide == 'Begin' || rideLifecycle.statusRide == 'start') { Log.print("🚨 Emergency shake verified! Prompting SOS..."); sosPassenger(); } }); } Future _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(); final locSearch = Get.find(); 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(); 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().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(); final locSearch = Get.find(); 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 driverArrivePassengerDialoge() { final rideLifecycle = Get.find(); 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(); 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(); 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) { handleResponse(res); } else { try { var decoded = jsonDecode(res); handleResponse(decoded); } catch (e) { Log.print("Error parsing parent response: $res"); } } }); } void handleResponse(Map res) { final rideLifecycle = Get.find(); 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(); } }