diff --git a/android/app/build.gradle b/android/app/build.gradle
index 3f33bef..d93fa6f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -148,8 +148,8 @@ android {
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdk = 23
targetSdk = flutter.targetSdkVersion
- versionCode = 94
- versionName = '1.5.94'
+ versionCode = 97
+ versionName = '1.5.97'
multiDexEnabled =true
// manifestPlaceholders can be specified here if needed
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index ad2e15e..bef9833 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -41,11 +41,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 67
+ 69
CFBundleSignature
????
CFBundleVersion
- 4.3.67
+ 4.3.69
NSHumanReadableCopyright
FirebaseAppDelegateProxyEnabled
diff --git a/lib/controller/firebase/local_notification.dart b/lib/controller/firebase/local_notification.dart
index 0370ab5..e471e04 100644
--- a/lib/controller/firebase/local_notification.dart
+++ b/lib/controller/firebase/local_notification.dart
@@ -1,92 +1,12 @@
-// import 'package:flutter_local_notifications/flutter_local_notifications.dart';
-// import 'package:get/get.dart';
-// import 'package:timezone/data/latest.dart' as tz;
-// import 'package:timezone/timezone.dart' as tz;
-
-// class NotificationController extends GetxController {
-// final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
-// FlutterLocalNotificationsPlugin();
-
-// // Initializes the local notifications plugin
-// Future initNotifications() async {
-// const AndroidInitializationSettings android =
-// AndroidInitializationSettings('@mipmap/launcher_icon');
-// const InitializationSettings initializationSettings =
-// InitializationSettings(android: android);
-// await _flutterLocalNotificationsPlugin.initialize(initializationSettings);
-// }
-
-// // Displays a notification with the given title and message
-// void showNotification(String title, String message, String tone) async {
-// AndroidNotificationDetails android = AndroidNotificationDetails(
-// 'high_importance_channel',
-// 'High Importance Notifications',
-// importance: Importance.max,
-// priority: Priority.high,
-// showWhen: false,
-// sound: RawResourceAndroidNotificationSound(tone),
-// );
-// DarwinNotificationDetails ios = const DarwinNotificationDetails(
-// sound: 'default',
-// presentAlert: true,
-// presentBadge: true,
-// presentSound: true,
-// );
-// NotificationDetails details =
-// NotificationDetails(android: android, iOS: ios);
-// await _flutterLocalNotificationsPlugin.show(0, title, message, details);
-// }
-
-// // Schedules a notification after 1 minute
-// void scheduleNotificationAfter1Minute(
-// String title, String message, String tone) async {
-// AndroidNotificationDetails android = AndroidNotificationDetails(
-// 'high_importance_channel', 'High Importance Notifications',
-// importance: Importance.max,
-// priority: Priority.high,
-// showWhen: false,
-// sound: RawResourceAndroidNotificationSound(tone));
-
-// DarwinNotificationDetails ios = const DarwinNotificationDetails(
-// sound: 'default',
-// presentAlert: true,
-// presentBadge: true,
-// presentSound: true,
-// );
-
-// NotificationDetails details =
-// NotificationDetails(android: android, iOS: ios);
-
-// // Schedule the notification to be shown after 1 minute
-// final now = tz.TZDateTime.now(tz.local);
-// final scheduledTime = now.add(const Duration(minutes: 1));
-
-// await _flutterLocalNotificationsPlugin.zonedSchedule(
-// 0,
-// title,
-// message,
-// scheduledTime,
-// details,
-// androidAllowWhileIdle: true,
-// uiLocalNotificationDateInterpretation:
-// UILocalNotificationDateInterpretation.absoluteTime,
-// matchDateTimeComponents: DateTimeComponents.time,
-// );
-// }
-// }
import 'dart:async';
import 'dart:io';
-import 'package:SEFER/constant/box_name.dart';
-import 'package:SEFER/main.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
-import '../../print.dart';
-
class NotificationController extends GetxController {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
@@ -139,8 +59,11 @@ class NotificationController extends GetxController {
await _flutterLocalNotificationsPlugin.show(0, title, message, details);
print('Notification shown: $title - $message');
}
+// /Users/hamzaaleghwairyeen/development/App/ride 2/lib/controller/firebase/local_notification.dart
- void scheduleDailyNotifications(
+// Assume _flutterLocalNotificationsPlugin is initialized somewhere in your code
+
+ void scheduleNotificationsForSevenDays(
String title, String message, String tone) async {
final AndroidNotificationDetails android = AndroidNotificationDetails(
'high_importance_channel',
@@ -172,53 +95,68 @@ class NotificationController extends GetxController {
}
}
- // Schedule notifications for 10:00 AM and 3:00 PM daily
- await _scheduleNotificationForTime(8, 0, title, message, details);
- await _scheduleNotificationForTime(15, 0, title, message, details);
- await _scheduleNotificationForTime(20, 0, title, message, details);
- // await _scheduleNotificationForTime(0, 22, title, message, details);
+ // Schedule notifications for the next 7 days
+ for (int day = 0; day < 7; day++) {
+ // Schedule for 8:00 AM
+ await _scheduleNotificationForTime(
+ day, 8, 0, title, message, details, day * 1000 + 1); // Unique ID
- print('Daily notifications scheduled successfully');
+ // Schedule for 3:00 PM
+ await _scheduleNotificationForTime(
+ day, 15, 0, title, message, details, day * 1000 + 2); // Unique ID
+
+ // Schedule for 8:00 PM
+ await _scheduleNotificationForTime(
+ day, 20, 0, title, message, details, day * 1000 + 3); // Unique ID
+ }
+
+ print('Notifications scheduled successfully for the next 7 days');
}
-// Helper function to get the next instance of a specific hour and minute
- Future _scheduleNotificationForTime(int hour, int minute, String title,
- String message, NotificationDetails details) async {
+ Future _scheduleNotificationForTime(
+ int dayOffset,
+ int hour,
+ int minute,
+ String title,
+ String message,
+ NotificationDetails details,
+ int notificationId,
+ ) async {
// Initialize and set Cairo timezone
tz.initializeTimeZones();
- var cairoLocation;
- // if (box.read(BoxName.countryCode).toString() == 'Egypt') {
- cairoLocation = tz.getLocation('Africa/Cairo');
- // } else {
- // cairoLocation = tz.getLocation('UTC');
- // } // todo get for location country
- // Set Cairo timezone
- Log.print('cairoLocation: ${cairoLocation}');
- final now = tz.TZDateTime.now(
- cairoLocation); // Use Cairo timezone for the current time
+ var cairoLocation = tz.getLocation('Africa/Cairo');
+ final now = tz.TZDateTime.now(cairoLocation);
tz.TZDateTime scheduledDate = tz.TZDateTime(
- cairoLocation, now.year, now.month, now.day, hour, minute);
+ cairoLocation,
+ now.year,
+ now.month,
+ now.day + dayOffset, // Add offset to schedule for the next days
+ hour,
+ minute,
+ );
- // If scheduled time is already past today, schedule it for the next day
+ // If the scheduled time is in the past, move it to the next day
if (scheduledDate.isBefore(now)) {
- scheduledDate = scheduledDate.add(const Duration(days: 1));
+ scheduledDate = scheduledDate.add(Duration(days: 1));
}
print('Current time (Cairo): $now');
print('Scheduling notification for: $scheduledDate');
await _flutterLocalNotificationsPlugin.zonedSchedule(
- 0, // Use unique IDs if you want to manage each notification separately
+ notificationId, // Unique ID for each notification
title,
message,
scheduledDate,
details,
- androidAllowWhileIdle: true,
+ androidScheduleMode: AndroidScheduleMode.exact,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
- matchDateTimeComponents: DateTimeComponents.time,
+ matchDateTimeComponents:
+ null, // Don't repeat automatically; we handle 7 days manually
);
- print('Notification scheduled successfully for Cairo timezone');
+
+ print('Notification scheduled successfully for: $scheduledDate');
}
}
diff --git a/lib/controller/functions/crud.dart b/lib/controller/functions/crud.dart
index 8c0e3a3..96995b0 100644
--- a/lib/controller/functions/crud.dart
+++ b/lib/controller/functions/crud.dart
@@ -1,18 +1,13 @@
import 'dart:convert';
-import 'dart:io';
-import 'dart:ui';
import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/constant/links.dart';
import 'package:SEFER/main.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:SEFER/env/env.dart';
-import 'package:http_parser/http_parser.dart';
-import 'package:mime/mime.dart';
import '../../constant/api_key.dart';
-import '../../constant/colors.dart';
import '../../print.dart';
import '../../views/widgets/elevated_btn.dart';
import 'add_error.dart';
@@ -79,17 +74,20 @@ class CRUD {
}
Future sendWhatsAppAuth(String to, String token) async {
+ var res = await CRUD()
+ .get(link: AppLink.getApiKey, payload: {'keyName': 'whatsapp_key'});
+ var accesstoken = jsonDecode(res)['message']['whatsapp_key'];
var headers = {
- 'Authorization': 'Bearer ${Env.whatsapp}',
+ 'Authorization': 'Bearer $accesstoken',
'Content-Type': 'application/json'
};
- var request = http.Request(
- 'POST',
- Uri.parse(
- 'https://graph.facebook.com/v20.0/${Env.whatappID}/messages'));
- request.body = json.encode({
+
+ var url = 'https://graph.facebook.com/v20.0/${Env.whatappID}/messages';
+ var request = http.Request('POST', Uri.parse(url));
+
+ var body = json.encode({
"messaging_product": "whatsapp",
- "to": to, //"962798583052",
+ "to": to,
"type": "template",
"template": {
"name": "sefer1",
@@ -107,22 +105,38 @@ class CRUD {
]
}
});
+
+ request.body = body;
request.headers.addAll(headers);
- http.StreamedResponse response = await request.send();
+ try {
+ print('Sending request to $url');
+ print('Request headers: $headers');
+ print('Request body: $body');
- if (response.statusCode == 200) {
- print(await response.stream.bytesToString());
- Get.defaultDialog(
+ http.StreamedResponse response = await request.send();
+
+ if (response.statusCode == 200) {
+ String responseBody = await response.stream.bytesToString();
+ print('Response: $responseBody');
+
+ Get.defaultDialog(
title: 'You will receive a code in WhatsApp Messenger'.tr,
middleText: 'wait 1 minute to recive message'.tr,
confirm: MyElevatedButton(
- title: 'OK'.tr,
- onPressed: () {
- Get.back();
- }));
- } else {
- print(response.reasonPhrase);
+ title: 'OK'.tr,
+ onPressed: () {
+ Get.back();
+ },
+ ),
+ );
+ } else {
+ String errorBody = await response.stream.bytesToString();
+ print('Error ${response.statusCode}: ${response.reasonPhrase}');
+ print('Error body: $errorBody');
+ }
+ } catch (e) {
+ print('Exception occurred: $e');
}
}
diff --git a/lib/controller/home/map_passenger_controller.dart b/lib/controller/home/map_passenger_controller.dart
index 4664b64..f17c4f5 100644
--- a/lib/controller/home/map_passenger_controller.dart
+++ b/lib/controller/home/map_passenger_controller.dart
@@ -1,8 +1,11 @@
import 'dart:async';
import 'dart:convert';
-import 'dart:math' show Random, cos, pi, pow, sin, sqrt;
+import 'dart:math' show Random, cos, max, min, pi, pow, sin, sqrt;
import 'dart:math' as math;
+import 'dart:ui';
import 'package:SEFER/constant/univeries_polygon.dart';
+import 'package:SEFER/controller/firebase/local_notification.dart';
+import 'package:flutter/cupertino.dart';
import 'package:flutter_confetti/flutter_confetti.dart';
import 'package:vector_math/vector_math.dart' show radians, degrees;
@@ -1364,7 +1367,7 @@ class MapPassengerController extends GetxController {
Set notifiedDrivers = {};
- confirmRideForAllDriverAvailable() async {
+ confirmRideForAllDriverAvailable11() async {
// Fetch car locations
await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 3000);
@@ -1419,7 +1422,7 @@ class MapPassengerController extends GetxController {
// Timer for 5 iterations, runs every 2 seconds
int iteration = 0;
Timer.periodic(const Duration(seconds: 2), (timer) async {
- if (iteration >= 5) {
+ if (iteration >= 10) {
timer.cancel();
return;
}
@@ -1539,94 +1542,117 @@ class MapPassengerController extends GetxController {
}
}
- confirmRideForAllDriverAvailable1() async {
- int attempts = 0;
- const int maxAttempts = 4;
- const Duration delayDuration = Duration(seconds: 2);
+ Future confirmRideForAllDriverAvailable() async {
+ // Try to fetch car locations up to 4 times with a 2-second delay
+ bool driversFound = false;
+ for (int attempt = 0; attempt < 4; attempt++) {
+ await getCarsLocationByPassengerAndReloadMarker(
+ box.read(BoxName.carType), 3000);
- // Initial data fetch
- await getCarsLocationByPassengerAndReloadMarker(
- box.read(BoxName.carType), 3000);
-
- if (dataCarsLocationByPassenger != null &&
- dataCarsLocationByPassenger != 'failure') {
- PaymentController paymentController = Get.find();
- rideConfirm = true;
- shouldFetch = true;
- isBottomSheetShown = false;
- timeToPassengerFromDriverAfterApplied = 60;
-
- // Create a set to keep track of notified driver IDs
- Set notifiedDriverIds = {};
-
- // Send the initial ride request once
- rideId = await CRUD().post(
- link: "${AppLink.seferCairoServer}/ride/rides/add.php",
- payload: {
- "start_location":
- '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
- "end_location":
- '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
- "date": DateTime.now().toString(),
- "time": DateTime.now().toString(),
- "endtime": durationToAdd.toString(),
- "price": totalPassenger.toStringAsFixed(2),
- "passenger_id": box.read(BoxName.passengerID).toString(),
- "driver_id": dataCarsLocationByPassenger['data'][carsOrder]
- ['driver_id']
- .toString(),
- "status": "waiting",
- 'carType': box.read(BoxName.carType),
- "price_for_driver": totalPassenger.toString(),
- "price_for_passenger": totalME.toString(),
- "distance": distance.toString(),
- "paymentMethod": paymentController.isWalletChecked.toString(),
- }).then((value) => jsonDecode(value)['message']);
-
- if (AppLink.endPoint != AppLink.seferCairoServer) {
- CRUD().post(link: '${AppLink.endPoint}/ride/rides/add.php', payload: {
- "start_location": //'${data[0]['start_address']}',
- '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
- "end_location": //'${data[0]['end_address']}',
- '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
- "date": DateTime.now().toString(),
- "time": DateTime.now().toString(),
- "endtime": durationToAdd.toString(),
- "price": totalPassenger.toStringAsFixed(2),
- "passenger_id": box.read(BoxName.passengerID).toString(),
- "driver_id": dataCarsLocationByPassenger['data'][carsOrder]
- ['driver_id']
- .toString(),
- "status": "waiting",
- 'carType': box.read(BoxName.carType),
- "price_for_driver": totalPassenger.toString(),
- "price_for_passenger": totalME.toString(),
- "distance": distance.toString(),
- "paymentMethod": paymentController.isWalletChecked.toString(),
- });
- }
- // Add the initially available drivers to the notified set
- for (var driver in dataCarsLocationByPassenger['data']) {
- notifiedDriverIds.add(driver['driver_id'].toString());
+ // Check if dataCarsLocationByPassenger is valid and contains drivers
+ if (dataCarsLocationByPassenger != 'failure' &&
+ dataCarsLocationByPassenger != null &&
+ dataCarsLocationByPassenger.containsKey('data') &&
+ dataCarsLocationByPassenger['data'] != null) {
+ driversFound = true;
+ break; // Exit loop if drivers are found
}
- // Periodically check for new drivers
- Timer.periodic(delayDuration, (Timer timer) async {
- attempts++;
+ // Wait 2 seconds before next attempt
+ await Future.delayed(const Duration(seconds: 2));
+ }
+ // If no drivers were found after 4 attempts, show a dialog
+ if (!driversFound) {
+ Get.dialog(
+ BackdropFilter(
+ filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
+ child: CupertinoAlertDialog(
+ title: Text(
+ "No Car or Driver Found in your area.".tr,
+ style: AppStyle.title.copyWith(
+ fontSize: 20,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ content: Text(
+ "No Car or Driver Found in your area.".tr,
+ style: AppStyle.title.copyWith(fontSize: 16),
+ ),
+ actions: [
+ CupertinoDialogAction(
+ onPressed: () {
+ Get.back();
+ Get.offAll(() => const MapPagePassenger());
+ },
+ child: Text('OK'.tr,
+ style: const TextStyle(color: AppColor.greenColor)),
+ ),
+ ],
+ ),
+ ),
+ barrierDismissible: false,
+ );
+
+ return;
+ }
+
+ // Proceed with the rest of the function if drivers are found
+ PaymentController paymentController = Get.find();
+ rideConfirm = true;
+ shouldFetch = true;
+ isBottomSheetShown = false;
+ timeToPassengerFromDriverAfterApplied = 60;
+
+ // Add ride to database
+ await CRUD()
+ .post(link: "${AppLink.seferCairoServer}/ride/rides/add.php", payload: {
+ "start_location":
+ '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
+ "end_location":
+ '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
+ "date": DateTime.now().toString(),
+ "time": DateTime.now().toString(),
+ "endtime": durationToAdd.toString(),
+ "price": totalPassenger.toStringAsFixed(2),
+ "passenger_id": box.read(BoxName.passengerID).toString(),
+ "driver_id": dataCarsLocationByPassenger['data'][carsOrder]['driver_id']
+ .toString(),
+ "status": "waiting",
+ 'carType': box.read(BoxName.carType),
+ "price_for_driver": totalPassenger.toString(),
+ "price_for_passenger": totalME.toString(),
+ "distance": distance.toString(),
+ "paymentMethod": paymentController.isWalletChecked.toString(),
+ }).then((value) {
+ if (value is String) {
+ final parsedValue = jsonDecode(value);
+ rideId = parsedValue['message'];
+ } else if (value is Map) {
+ rideId = value['message'];
+ } else {
+ Log.print('Unexpected response type: ${value.runtimeType}');
+ }
+
+ // Timer to notify drivers every 2 seconds for 5 iterations
+ int iteration = 0;
+ Timer.periodic(const Duration(seconds: 2), (timer) async {
+ if (iteration >= 5) {
+ timer.cancel();
+ return;
+ }
+ iteration++;
+
+ // Reload driver locations and notify available drivers
await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 3000);
-
- if (dataCarsLocationByPassenger != 'failure') {
- // Check for new drivers and notify them
- for (var driver in dataCarsLocationByPassenger['data']) {
- String driverId = driver['driver_id'].toString();
-
- // Only notify new drivers
- if (!notifiedDriverIds.contains(driverId)) {
- notifiedDriverIds.add(driverId);
-
- // Prepare notification body
+ if (dataCarsLocationByPassenger != null &&
+ dataCarsLocationByPassenger.containsKey('data') &&
+ dataCarsLocationByPassenger['data'] != null) {
+ for (var driverData in dataCarsLocationByPassenger['data']) {
+ String driverId = driverData['driver_id'].toString();
+ if (!notifiedDrivers.contains(driverId)) {
+ notifiedDrivers.add(driverId);
List body = [
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
@@ -1642,10 +1668,11 @@ class MapPassengerController extends GetxController {
durationByPassenger.toString(),
distanceByPassenger.toString(),
paymentController.isWalletChecked.toString(),
- driver['token'].toString(),
+ driverData['token'].toString(),
durationToPassenger.toString(),
rideId,
rideTimerBegin.toString(),
+ driverId,
durationToRide.toString(),
Get.find().wayPoints.length > 1
? 'haveSteps'
@@ -1656,10 +1683,10 @@ class MapPassengerController extends GetxController {
placesCoordinate[3],
placesCoordinate[4],
costForDriver.toStringAsFixed(2),
- double.parse(box.read(BoxName.passengerWalletTotal)) < 0
+ (double.parse(box.read(BoxName.passengerWalletTotal)) < 0
? double.parse(box.read(BoxName.passengerWalletTotal))
.toStringAsFixed(2)
- : '0',
+ : '0'),
box.read(BoxName.email).toString(),
data[0]['start_address'],
data[0]['end_address'],
@@ -1667,37 +1694,43 @@ class MapPassengerController extends GetxController {
kazan.toStringAsFixed(0),
passengerRate.toStringAsFixed(2),
];
-
- // Send notification to the new driver
FirebaseMessagesController().sendNotificationToDriverMAP(
'OrderSpeed',
- rideId.toString(),
- driver['token'].toString(),
+ rideId,
+ driverData['token'].toString(),
body,
'order.wav',
);
}
}
- } else {
- MyDialog().getDialog("No Car or Driver Found in your area.".tr,
- "No Car or Driver Found in your area.".tr, () {
- Get.back();
- Get.offAll(const MapPagePassenger());
- });
- }
-
- // Stop after max attempts
- if (attempts >= maxAttempts) {
- timer.cancel();
}
});
- } else {
- MyDialog().getDialog("No Car or Driver Found in your area.".tr,
- "No Car or Driver Found in your area.".tr, () {
- Get.back();
- Get.offAll(const MapPagePassenger());
+ });
+
+ // If an additional endpoint is available, post data there as well
+ if (AppLink.endPoint != AppLink.seferCairoServer) {
+ CRUD().post(link: '${AppLink.endPoint}/ride/rides/add.php', payload: {
+ "start_location":
+ '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
+ "end_location":
+ '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
+ "date": DateTime.now().toString(),
+ "time": DateTime.now().toString(),
+ "endtime": durationToAdd.toString(),
+ "price": totalPassenger.toStringAsFixed(2),
+ "passenger_id": box.read(BoxName.passengerID).toString(),
+ "driver_id": dataCarsLocationByPassenger['data'][carsOrder]['driver_id']
+ .toString(),
+ "status": "waiting",
+ 'carType': box.read(BoxName.carType),
+ "price_for_driver": totalPassenger.toString(),
+ "price_for_passenger": totalME.toString(),
+ "distance": distance.toString(),
+ "paymentMethod": paymentController.isWalletChecked.toString(),
});
}
+ delayAndFetchRideStatusForAllDriverAvailable(rideId);
+ update();
}
icreaseForSameRideAndDelay() {
@@ -1781,7 +1814,7 @@ class MapPassengerController extends GetxController {
confirmRideForAllDriverAvailable();
// delayAndFetchRideStatusForAllDriverAvailable(rideId);
} else if (rideStatusDelayed == 'Apply' || statusRide == 'Apply') {
- Log.print('rideStatusDelayed == Apply: ${rideStatusDelayed}');
+ Log.print('rideStatusDelayed == Apply: $rideStatusDelayed');
// todo play sound
Get.find()
.playSoundFromAssets('assets/start.wav');
@@ -1837,17 +1870,29 @@ class MapPassengerController extends GetxController {
int attemptCounter = 0;
bool isApplied = false;
tick = 0;
- Log.print('tick delayAndFetchRideStatusForAllDriverAvailable: $tick');
+ bool shouldContinueSearching = true; // Flag to control searching
void fetchRideStatus() async {
- if (attemptCounter < maxAttempts && isApplied == false || tick < 15) {
+ if (attemptCounter < maxAttempts &&
+ !isApplied &&
+ shouldContinueSearching) {
attemptCounter++;
tick++;
var res = await getRideStatus(rideId);
String rideStatusDelayed = res.toString();
- if (rideStatusDelayed == 'Apply' || rideStatusDelayed == 'Applied') {
+ if (rideStatusDelayed == 'Cancel') {
+ shouldContinueSearching = false; // Stop searching
+ attemptCounter = maxAttempts + 1;
+ NotificationController().showNotification(
+ "Order Cancelled".tr, "you canceled order".tr, 'ding');
+ } else if (rideStatusDelayed == 'Apply' ||
+ rideStatusDelayed == 'Applied') {
await getUpdatedRideForDriverApply(rideId);
+ NotificationController().showNotification(
+ 'Order Accepted'.tr,
+ '$driverName ${'accepted your order at price'.tr} ${totalPassenger.toStringAsFixed(1)} ${'with type'.tr} ${box.read(BoxName.carType)}',
+ 'ding');
isApplied = true;
shouldFetch = false;
statusRide = 'Apply';
@@ -1855,89 +1900,14 @@ class MapPassengerController extends GetxController {
isSearchingWindow = false;
startTimer();
-
update();
startTimerFromDriverToPassengerAfterApplied();
+ shouldContinueSearching = false; // Stop searching if applied
} else if (attemptCounter >= maxAttempts &&
rideStatusDelayed != 'Cancel') {
- shouldFetch = false;
- // If the status is still not "Apply" after 15 attempts
- MyDialog().getDialog('upgrade price'.tr,
- 'You can upgrade price to may driver accept your order'.tr, () {
- Get.back();
- Get.defaultDialog(
- barrierDismissible: false,
- title: "Increase Your Trip Fee (Optional)".tr,
- titleStyle: AppStyle.title,
- content: Column(
- children: [
- Text(
- "We haven't found any drivers yet. Consider increasing your trip fee to make your offer more attractive to drivers."
- .tr,
- style: AppStyle.title,
- textAlign: TextAlign.center,
- ),
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- IconButton(
- onPressed: () {
- increasFeeFromPassenger.text =
- (totalPassenger + 6).toStringAsFixed(1);
- update();
- },
- icon: Column(
- children: [
- Text(
- '6',
- style: AppStyle.number,
- ),
- Container(
- decoration: const BoxDecoration(
- shape: BoxShape.circle,
- color: AppColor.greenColor),
- child: const Icon(
- Icons.arrow_circle_up,
- size: 30,
- color: AppColor.secondaryColor,
- ),
- ),
- ],
- ),
- ),
- SizedBox(
- width: 100,
- child: Form(
- key: increaseFeeFormKey,
- child: MyTextForm(
- controller: increasFeeFromPassenger,
- label: totalPassenger.toStringAsFixed(2),
- hint: totalPassenger.toStringAsFixed(2),
- type: TextInputType.number),
- ),
- ),
- ],
- )
- ],
- ),
- actions: [
- MyElevatedButton(
- title: "No, thanks",
- onPressed: () async {
- await cancelRide();
- Get.back();
- }),
- MyElevatedButton(
- title: "Increase Fee".tr,
- kolor: AppColor.greenColor,
- onPressed: () {
- increaseFeeByPassengerAndReOrder();
- })
- ],
- );
- });
+ shouldContinueSearching = false; // Stop searching
+ // Show dialog to increase fee...
update();
- print('Stopped fetching ride status after 15 attempts.');
} else {
Timer(const Duration(seconds: 2), fetchRideStatus);
}
@@ -2026,7 +1996,7 @@ class MapPassengerController extends GetxController {
FirebaseMessagesController().sendNotificationToDriverMAP(
'Order Applied'.tr,
'$driverName Apply order\nTake attention in other order'.tr,
- driverToken,
+ driverToken.toString(),
[],
'start.wav',
);
@@ -2912,7 +2882,7 @@ class MapPassengerController extends GetxController {
FirebaseMessagesController().sendNotificationToDriverMAP(
'Cancel Trip'.tr,
'Trip Cancelled'.tr,
- driverToken,
+ driverToken.toString(),
[],
'cancel.wav',
);
@@ -3313,23 +3283,56 @@ class MapPassengerController extends GetxController {
// Log.print('BoxName.serverChosen: ${box.read(BoxName.serverChosen)}');
newStartPointLocation = passengerLocation;
- Log.print('passengerLocation: ${passengerLocation}');
+ Log.print('passengerLocation: $passengerLocation');
speed = _locationData.speed!;
// //print location details
isLoading = false;
update();
}
+ // LatLngBounds calculateBounds(double lat, double lng, double radiusInMeters) {
+ // const double earthRadius = 6378137.0; // Earth's radius in meters
+
+ // double latDelta = radiusInMeters / earthRadius * (180 / pi);
+ // double lngDelta =
+ // radiusInMeters / (earthRadius * cos(pi * lat / 180)) * (180 / pi);
+
+ // return LatLngBounds(
+ // southwest: LatLng(lat - latDelta, lng - lngDelta),
+ // northeast: LatLng(lat + latDelta, lng + lngDelta),
+ // );
+ // }
LatLngBounds calculateBounds(double lat, double lng, double radiusInMeters) {
const double earthRadius = 6378137.0; // Earth's radius in meters
- double latDelta = radiusInMeters / earthRadius * (180 / pi);
+ double latDelta = (radiusInMeters / earthRadius) * (180 / pi);
double lngDelta =
- radiusInMeters / (earthRadius * cos(pi * lat / 180)) * (180 / pi);
+ (radiusInMeters / (earthRadius * cos(pi * lat / 180))) * (180 / pi);
+
+ double minLat = lat - latDelta;
+ double maxLat = lat + latDelta;
+
+ double minLng = lng - lngDelta;
+ double maxLng = lng + lngDelta;
+
+ // Ensure the latitude is between -90 and 90
+ minLat = max(-90.0, minLat);
+ maxLat = min(90.0, maxLat);
+
+ // Ensure the longitude is between -180 and 180
+ minLng = (minLng + 180) % 360 - 180;
+ maxLng = (maxLng + 180) % 360 - 180;
+
+ // Ensure the bounds are in the correct order
+ if (minLng > maxLng) {
+ double temp = minLng;
+ minLng = maxLng;
+ maxLng = temp;
+ }
return LatLngBounds(
- southwest: LatLng(lat - latDelta, lng - lngDelta),
- northeast: LatLng(lat + latDelta, lng + lngDelta),
+ southwest: LatLng(minLat, minLng),
+ northeast: LatLng(maxLat, maxLng),
);
}
@@ -3470,7 +3473,7 @@ class MapPassengerController extends GetxController {
i < dataCarsLocationByPassenger['message'].length;
i++) {
var carLocation = dataCarsLocationByPassenger['message'][i];
- Log.print('carLocation: ${carLocation}');
+ Log.print('carLocation: $carLocation');
// Calculate distance between passenger's location and current driver's location
final distance = Geolocator.distanceBetween(
@@ -3482,8 +3485,8 @@ class MapPassengerController extends GetxController {
// Calculate duration assuming an average speed of 25 km/h (adjust as needed)
int durationToPassenger = (distance * 25 * (1000 / 3600)).round();
- Log.print('distance: ${distance}');
- Log.print('durationToPassenger: ${durationToPassenger}');
+ Log.print('distance: $distance');
+ Log.print('durationToPassenger: $durationToPassenger');
// Update the UI with the distance and duration for each car
update();
@@ -3499,7 +3502,7 @@ class MapPassengerController extends GetxController {
latitude: double.parse(carLocation['latitude']),
longitude: double.parse(carLocation['longitude']),
);
- Log.print('nearestCar: ${nearestCar}');
+ Log.print('nearestCar: $nearestCar');
// Update the UI with the nearest driver
update();
}
@@ -4283,7 +4286,7 @@ class MapPassengerController extends GetxController {
totalCostPassenger = totalDriver1 + (totalDriver1 * kazan / 100);
totalPassenger = costSpeed + (costSpeed * kazan / 100);
if (isInUniversity) {
- Log.print('isInUniversity: ${isInUniversity}');
+ Log.print('isInUniversity: $isInUniversity');
totalPassengerComfort =
20 + (costComfort + (costComfort * kazan / 100)).ceilToDouble();
totalPassengerLady =
@@ -4325,7 +4328,7 @@ class MapPassengerController extends GetxController {
totalME = totalCostPassenger - tax;
costForDriver = fuelPrice * (20 / 210) * distance;
} else {
- Log.print('isInUniversity: ${isInUniversity}');
+ Log.print('isInUniversity: $isInUniversity');
totalPassengerComfort =
(costComfort + (costComfort * kazan / 100)).ceilToDouble();
totalPassengerLady =
diff --git a/lib/controller/home/profile/invit_controller.dart b/lib/controller/home/profile/invit_controller.dart
index 13e1628..e7307f2 100644
--- a/lib/controller/home/profile/invit_controller.dart
+++ b/lib/controller/home/profile/invit_controller.dart
@@ -4,8 +4,8 @@ import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/constant/links.dart';
import 'package:SEFER/controller/functions/crud.dart';
-import 'package:SEFER/controller/home/payment/captain_wallet_controller.dart';
import 'package:SEFER/controller/payment/payment_controller.dart';
+import 'package:SEFER/views/widgets/mysnakbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_contacts/contact.dart';
import 'package:flutter_contacts/flutter_contacts.dart';
@@ -13,6 +13,7 @@ import 'package:get/get.dart';
import 'package:share/share.dart';
import '../../../main.dart';
+import '../../../print.dart';
import '../../../views/widgets/my_dialog.dart';
import '../../functions/launch.dart';
import '../../notification/notification_captain_controller.dart';
@@ -117,23 +118,49 @@ Download the SEFER app now and enjoy your ride!
Future pickContacts() async {
try {
+ // Request contacts permission
if (await FlutterContacts.requestPermission(readonly: true)) {
- final List fetchedContacts =
- await FlutterContacts.getContacts(withProperties: true);
- contacts = fetchedContacts;
+ // Fetch all contacts with full properties
+ final List allContacts = await FlutterContacts.getContacts(
+ withProperties: true,
+ withThumbnail: false,
+ withPhoto: true,
+ );
- // Convert contacts to a list of maps
- contactMaps.value = fetchedContacts.map((contact) {
- return {
- 'name': contact.displayName,
- 'phones':
- contact.phones.map((phone) => phone.normalizedNumber).toList(),
- 'emails': contact.emails.map((email) => email.address).toList(),
- };
- }).toList();
- update();
+ // Check if contacts are available
+ if (allContacts.isNotEmpty) {
+ // Store the contacts
+ contacts = allContacts;
+ Log.print('contacts: $contacts');
- if (contacts.isEmpty) {
+ // Convert contacts to a list of maps
+ contactMaps.value = await Future.wait(contacts.map((contact) async {
+ Log.print('Contact name: ${contact.displayName}');
+
+ // Fetch phone numbers separately
+ final phones = await contact.phones;
+ Log.print('Contact phones: $phones');
+
+ // Fetch email addresses separately
+ final emails = await contact.emails;
+ Log.print('Contact emails: $emails');
+
+ // Handle empty or null values
+ return {
+ 'name': contact.displayName ?? '',
+ 'phones': phones
+ .where((phone) => phone.normalizedNumber != null)
+ .map((phone) => phone.normalizedNumber ?? 'No number')
+ .toList(),
+ 'emails': emails
+ .where((email) => email.address != null)
+ .map((email) => email.address ?? 'No email')
+ .toList(),
+ };
+ }).toList());
+
+ update();
+ } else {
Get.snackbar('No contacts available'.tr,
'Please add contacts to your phone.'.tr);
}
@@ -225,8 +252,10 @@ Download the SEFER app now and enjoy your ride!
}
void sendInviteToPassenger() async {
- if (invitePhoneController.text.isEmpty) {
- Get.snackbar('Error', 'Please enter an phone address'.tr);
+ if (invitePhoneController.text.isEmpty ||
+ invitePhoneController.text.length < 11) {
+ mySnackeBarError('Please enter a correct phone'.tr);
+
return;
}
diff --git a/lib/controller/local/local_controller.dart b/lib/controller/local/local_controller.dart
index 1f61cb8..ebb51cb 100644
--- a/lib/controller/local/local_controller.dart
+++ b/lib/controller/local/local_controller.dart
@@ -20,72 +20,58 @@ class LocaleController extends GetxController {
case "ar":
locale = const Locale("ar");
appTheme = themeArabic;
- box.write(BoxName.lang, 'ar');
break;
case "en":
locale = const Locale("en");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'en');
break;
case "tr":
locale = const Locale("tr");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'tr');
break;
case "fr":
locale = const Locale("fr");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'fr');
break;
case "it":
locale = const Locale("it");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'it');
break;
case "de":
locale = const Locale("de");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'de');
break;
case "el":
locale = const Locale("el");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'el');
break;
case "es":
locale = const Locale("es");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'es');
break;
case "fa":
locale = const Locale("fa");
- appTheme = themeEnglish;
- box.write(BoxName.lang, 'fa');
+ appTheme = themeArabic;
break;
case "zh":
locale = const Locale("zh");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'zh');
break;
case "ru":
locale = const Locale("ru");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'ru');
break;
case "hi":
locale = const Locale("hi");
appTheme = themeEnglish;
- box.write(BoxName.lang, 'hi');
break;
default:
locale = Locale(Get.deviceLocale!.languageCode);
- box.write(BoxName.lang, Get.deviceLocale!.languageCode);
appTheme = themeEnglish;
break;
}
box.write(BoxName.lang, langcode);
- // box.write(BoxName.lang, langcode);
Get.changeTheme(appTheme);
Get.updateLocale(locale);
restartApp();
@@ -94,62 +80,15 @@ class LocaleController extends GetxController {
@override
void onInit() {
- String storedLang = box.read(BoxName.lang) ?? "ar";
- switch (storedLang) {
- case "ar":
- language = const Locale("ar");
- appTheme = themeArabic;
- break;
- case "en":
- language = const Locale("en");
- appTheme = themeEnglish;
- break;
- case "tr":
- language = const Locale("tr");
- appTheme = themeEnglish;
- break;
- case "fr":
- language = const Locale("fr");
- appTheme = themeEnglish;
- break;
- case "it":
- language = const Locale("it");
- appTheme = themeEnglish;
- break;
- case "de":
- language = const Locale("de");
- appTheme = themeEnglish;
- break;
- case "el":
- language = const Locale("el");
- appTheme = themeEnglish;
- break;
- case "es":
- language = const Locale("es");
- appTheme = themeEnglish;
- break;
- case "fa":
- language = const Locale("fa");
- appTheme = themeArabic;
- break;
- case "zh":
- language = const Locale("zh");
- appTheme = themeEnglish;
- break;
- case "ru":
- language = const Locale("ru");
- appTheme = themeEnglish;
- break;
- case "hi":
- language = const Locale("hi");
- appTheme = themeEnglish;
- break;
- default:
- language = Locale(Get.deviceLocale!.languageCode);
- appTheme = themeEnglish;
- break;
+ String? storedLang = box.read(BoxName.lang);
+ if (storedLang == null) {
+ // Use device language if no language is stored
+ storedLang = Get.deviceLocale!.languageCode;
+ box.write(BoxName.lang, storedLang);
}
+ changeLang(storedLang);
+
super.onInit();
}
}
diff --git a/lib/controller/local/translations.dart b/lib/controller/local/translations.dart
index d46e785..2f75fa8 100644
--- a/lib/controller/local/translations.dart
+++ b/lib/controller/local/translations.dart
@@ -52,13 +52,18 @@ class MyTranslation extends Translations {
"Pick or Tap to confirm": "حدد أو انقر للتأكيد",
"Select Order Type": "حدد نوع الطلب",
"Choose who this order is for": "اختر لمن هذا الطلب",
+ "Order Accepted": "تم قبول الطلب", "with type": "مع النوع",
+ "accepted your order at price": "قبل طلبك بالسعر",
"I want to order for myself": "أريد أن أطلب لنفسي",
"I want to order for someone else": "أريد أن أطلب لشخص آخر",
"Cancel Trip from driver": "إلغاء الرحلة من السائق",
+ "Order Cancelled": "تم إلغاء الطلب",
+ "you canceled order": "لقد قمت بإلغاء الطلب",
"If you want order to another person": "إذا كنت تريد الطلب لشخص آخر",
"Ok I will go now.": "حسنًا، سأذهب الآن.",
"Hi, I will go now": "مرحبًا، سأذهب الآن.",
"upgrade price": "رفع السعر",
+ 'Please enter a correct phone': 'يرجى إدخال رقم هاتف صحيح',
'airport': 'مطار',
"Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.":
"أفضل اختيار لسيارة مريحة مع طريق ونقاط توقف مرنة. يقدم هذا المطار تأشيرة دخول بهذا السعر.",
diff --git a/lib/controller/payment/payment_controller.dart b/lib/controller/payment/payment_controller.dart
index b698d24..4aa3bd7 100644
--- a/lib/controller/payment/payment_controller.dart
+++ b/lib/controller/payment/payment_controller.dart
@@ -699,7 +699,8 @@ class PaymentController extends GetxController {
);
// if (response!.success == true && response.responseCode == '200') {
- if (response!.responseCode == '200' && response.success == true) {
+ if (response!.responseCode.toString() == '200' &&
+ response.success == true) {
// Log.print('transactionID wewer: ${response.transactionID}');
Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor);
method();
diff --git a/lib/main.dart b/lib/main.dart
index 4bf3b65..534e1a2 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -45,18 +45,6 @@ void main() async {
// if (Platform.isAndroid) {
NotificationController notificationController =
Get.put(NotificationController());
- await notificationController.initNotifications();
-
- // Generate a random index to pick a message
- final random = Random();
- final randomMessage = messages[random.nextInt(messages.length)];
-
- // Schedule the notification with the random message
- notificationController.scheduleDailyNotifications(
- randomMessage.split(':')[0],
- randomMessage.split(':')[1],
- "ding",
- );
// await NotificationController().initNotifications();
// }
@@ -100,13 +88,18 @@ void main() async {
userTokenExpiration: 200,
iFrameID: 837992,
);
- // Get device information
- // List