405 lines
14 KiB
Dart
405 lines
14 KiB
Dart
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';
|
|
import '../../functions/country_logic.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: CountryLogic.getPhoneHint(
|
|
box.read(BoxName.countryCode) ?? 'Syria').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 =
|
|
CountryLogic.formatCurrentCountryPhone(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);
|
|
}
|
|
|
|
// removed formatSyrianPhone and formatSyrianPhoneNumber
|
|
|
|
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 = CountryLogic.formatCurrentCountryPhone(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 = CountryLogic.formatCurrentCountryPhone(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 Siro 🚗
|
|
|
|
Track my ride here:
|
|
$trackingLink
|
|
|
|
Driver: ${rideLifecycle.passengerName}
|
|
Car: ${rideLifecycle.model} - ${rideLifecycle.licensePlate}
|
|
Thank you for using Siro!
|
|
""";
|
|
|
|
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 = CountryLogic.formatCurrentCountryPhone(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 Siro 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 = CountryLogic.formatCurrentCountryPhone(rawPhone);
|
|
|
|
var message = '''Dear Friend,
|
|
|
|
🚀 I have just started an exciting trip on Siro!
|
|
Download the app to track my ride:
|
|
|
|
👉 Android: https://play.google.com/store/apps/details?id=com.Siro.siro&hl=en-US
|
|
👉 iOS: https://apps.apple.com/st/app/siro-rider/id6748075179
|
|
|
|
See you there!
|
|
Siro 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();
|
|
}
|
|
}
|