This commit is contained in:
Hamza-Ayed
2024-11-17 12:02:54 +02:00
parent bf8a29b814
commit f796f4bc48
13 changed files with 611 additions and 493 deletions

View File

@@ -148,8 +148,8 @@ android {
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdk = 23 minSdk = 23
targetSdk = flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode = 94 versionCode = 97
versionName = '1.5.94' versionName = '1.5.97'
multiDexEnabled =true multiDexEnabled =true
// manifestPlaceholders can be specified here if needed // manifestPlaceholders can be specified here if needed

View File

@@ -41,11 +41,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>67</string> <string>69</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>4.3.67</string> <string>4.3.69</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string></string> <string></string>
<key>FirebaseAppDelegateProxyEnabled</key> <key>FirebaseAppDelegateProxyEnabled</key>

View File

@@ -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<void> 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:async';
import 'dart:io'; 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:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/data/latest.dart' as tz;
import 'package:timezone/timezone.dart' as tz; import 'package:timezone/timezone.dart' as tz;
import '../../print.dart';
class NotificationController extends GetxController { class NotificationController extends GetxController {
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin(); FlutterLocalNotificationsPlugin();
@@ -139,8 +59,11 @@ class NotificationController extends GetxController {
await _flutterLocalNotificationsPlugin.show(0, title, message, details); await _flutterLocalNotificationsPlugin.show(0, title, message, details);
print('Notification shown: $title - $message'); 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 { String title, String message, String tone) async {
final AndroidNotificationDetails android = AndroidNotificationDetails( final AndroidNotificationDetails android = AndroidNotificationDetails(
'high_importance_channel', 'high_importance_channel',
@@ -172,53 +95,68 @@ class NotificationController extends GetxController {
} }
} }
// Schedule notifications for 10:00 AM and 3:00 PM daily // Schedule notifications for the next 7 days
await _scheduleNotificationForTime(8, 0, title, message, details); for (int day = 0; day < 7; day++) {
await _scheduleNotificationForTime(15, 0, title, message, details); // Schedule for 8:00 AM
await _scheduleNotificationForTime(20, 0, title, message, details); await _scheduleNotificationForTime(
// await _scheduleNotificationForTime(0, 22, title, message, details); 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<void> _scheduleNotificationForTime(
Future<void> _scheduleNotificationForTime(int hour, int minute, String title, int dayOffset,
String message, NotificationDetails details) async { int hour,
int minute,
String title,
String message,
NotificationDetails details,
int notificationId,
) async {
// Initialize and set Cairo timezone // Initialize and set Cairo timezone
tz.initializeTimeZones(); tz.initializeTimeZones();
var cairoLocation; var cairoLocation = tz.getLocation('Africa/Cairo');
// 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
final now = tz.TZDateTime.now(cairoLocation);
tz.TZDateTime scheduledDate = tz.TZDateTime( 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)) { if (scheduledDate.isBefore(now)) {
scheduledDate = scheduledDate.add(const Duration(days: 1)); scheduledDate = scheduledDate.add(Duration(days: 1));
} }
print('Current time (Cairo): $now'); print('Current time (Cairo): $now');
print('Scheduling notification for: $scheduledDate'); print('Scheduling notification for: $scheduledDate');
await _flutterLocalNotificationsPlugin.zonedSchedule( await _flutterLocalNotificationsPlugin.zonedSchedule(
0, // Use unique IDs if you want to manage each notification separately notificationId, // Unique ID for each notification
title, title,
message, message,
scheduledDate, scheduledDate,
details, details,
androidAllowWhileIdle: true, androidScheduleMode: AndroidScheduleMode.exact,
uiLocalNotificationDateInterpretation: uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime, 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');
} }
} }

View File

@@ -1,18 +1,13 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:ui';
import 'package:SEFER/constant/box_name.dart'; import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/constant/links.dart'; import 'package:SEFER/constant/links.dart';
import 'package:SEFER/main.dart'; import 'package:SEFER/main.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:SEFER/env/env.dart'; 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/api_key.dart';
import '../../constant/colors.dart';
import '../../print.dart'; import '../../print.dart';
import '../../views/widgets/elevated_btn.dart'; import '../../views/widgets/elevated_btn.dart';
import 'add_error.dart'; import 'add_error.dart';
@@ -79,17 +74,20 @@ class CRUD {
} }
Future sendWhatsAppAuth(String to, String token) async { 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 = { var headers = {
'Authorization': 'Bearer ${Env.whatsapp}', 'Authorization': 'Bearer $accesstoken',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}; };
var request = http.Request(
'POST', var url = 'https://graph.facebook.com/v20.0/${Env.whatappID}/messages';
Uri.parse( var request = http.Request('POST', Uri.parse(url));
'https://graph.facebook.com/v20.0/${Env.whatappID}/messages'));
request.body = json.encode({ var body = json.encode({
"messaging_product": "whatsapp", "messaging_product": "whatsapp",
"to": to, //"962798583052", "to": to,
"type": "template", "type": "template",
"template": { "template": {
"name": "sefer1", "name": "sefer1",
@@ -107,22 +105,38 @@ class CRUD {
] ]
} }
}); });
request.body = body;
request.headers.addAll(headers); 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) { http.StreamedResponse response = await request.send();
print(await response.stream.bytesToString());
Get.defaultDialog( 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, title: 'You will receive a code in WhatsApp Messenger'.tr,
middleText: 'wait 1 minute to recive message'.tr, middleText: 'wait 1 minute to recive message'.tr,
confirm: MyElevatedButton( confirm: MyElevatedButton(
title: 'OK'.tr, title: 'OK'.tr,
onPressed: () { onPressed: () {
Get.back(); Get.back();
})); },
} else { ),
print(response.reasonPhrase); );
} else {
String errorBody = await response.stream.bytesToString();
print('Error ${response.statusCode}: ${response.reasonPhrase}');
print('Error body: $errorBody');
}
} catch (e) {
print('Exception occurred: $e');
} }
} }

View File

@@ -1,8 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; 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:math' as math;
import 'dart:ui';
import 'package:SEFER/constant/univeries_polygon.dart'; 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:flutter_confetti/flutter_confetti.dart';
import 'package:vector_math/vector_math.dart' show radians, degrees; import 'package:vector_math/vector_math.dart' show radians, degrees;
@@ -1364,7 +1367,7 @@ class MapPassengerController extends GetxController {
Set<String> notifiedDrivers = {}; Set<String> notifiedDrivers = {};
confirmRideForAllDriverAvailable() async { confirmRideForAllDriverAvailable11() async {
// Fetch car locations // Fetch car locations
await getCarsLocationByPassengerAndReloadMarker( await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 3000); box.read(BoxName.carType), 3000);
@@ -1419,7 +1422,7 @@ class MapPassengerController extends GetxController {
// Timer for 5 iterations, runs every 2 seconds // Timer for 5 iterations, runs every 2 seconds
int iteration = 0; int iteration = 0;
Timer.periodic(const Duration(seconds: 2), (timer) async { Timer.periodic(const Duration(seconds: 2), (timer) async {
if (iteration >= 5) { if (iteration >= 10) {
timer.cancel(); timer.cancel();
return; return;
} }
@@ -1539,94 +1542,117 @@ class MapPassengerController extends GetxController {
} }
} }
confirmRideForAllDriverAvailable1() async { Future<void> confirmRideForAllDriverAvailable() async {
int attempts = 0; // Try to fetch car locations up to 4 times with a 2-second delay
const int maxAttempts = 4; bool driversFound = false;
const Duration delayDuration = Duration(seconds: 2); for (int attempt = 0; attempt < 4; attempt++) {
await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 3000);
// Initial data fetch // Check if dataCarsLocationByPassenger is valid and contains drivers
await getCarsLocationByPassengerAndReloadMarker( if (dataCarsLocationByPassenger != 'failure' &&
box.read(BoxName.carType), 3000); dataCarsLocationByPassenger != null &&
dataCarsLocationByPassenger.containsKey('data') &&
if (dataCarsLocationByPassenger != null && dataCarsLocationByPassenger['data'] != null) {
dataCarsLocationByPassenger != 'failure') { driversFound = true;
PaymentController paymentController = Get.find<PaymentController>(); break; // Exit loop if drivers are found
rideConfirm = true;
shouldFetch = true;
isBottomSheetShown = false;
timeToPassengerFromDriverAfterApplied = 60;
// Create a set to keep track of notified driver IDs
Set<String> 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());
} }
// Periodically check for new drivers // Wait 2 seconds before next attempt
Timer.periodic(delayDuration, (Timer timer) async { await Future.delayed(const Duration(seconds: 2));
attempts++; }
// 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<PaymentController>();
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( await getCarsLocationByPassengerAndReloadMarker(
box.read(BoxName.carType), 3000); box.read(BoxName.carType), 3000);
if (dataCarsLocationByPassenger != null &&
if (dataCarsLocationByPassenger != 'failure') { dataCarsLocationByPassenger.containsKey('data') &&
// Check for new drivers and notify them dataCarsLocationByPassenger['data'] != null) {
for (var driver in dataCarsLocationByPassenger['data']) { for (var driverData in dataCarsLocationByPassenger['data']) {
String driverId = driver['driver_id'].toString(); String driverId = driverData['driver_id'].toString();
if (!notifiedDrivers.contains(driverId)) {
// Only notify new drivers notifiedDrivers.add(driverId);
if (!notifiedDriverIds.contains(driverId)) {
notifiedDriverIds.add(driverId);
// Prepare notification body
List<String> body = [ List<String> body = [
'${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}', '${data[0]["start_location"]['lat']},${data[0]["start_location"]['lng']}',
'${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}', '${data[0]["end_location"]['lat']},${data[0]["end_location"]['lng']}',
@@ -1642,10 +1668,11 @@ class MapPassengerController extends GetxController {
durationByPassenger.toString(), durationByPassenger.toString(),
distanceByPassenger.toString(), distanceByPassenger.toString(),
paymentController.isWalletChecked.toString(), paymentController.isWalletChecked.toString(),
driver['token'].toString(), driverData['token'].toString(),
durationToPassenger.toString(), durationToPassenger.toString(),
rideId, rideId,
rideTimerBegin.toString(), rideTimerBegin.toString(),
driverId,
durationToRide.toString(), durationToRide.toString(),
Get.find<WayPointController>().wayPoints.length > 1 Get.find<WayPointController>().wayPoints.length > 1
? 'haveSteps' ? 'haveSteps'
@@ -1656,10 +1683,10 @@ class MapPassengerController extends GetxController {
placesCoordinate[3], placesCoordinate[3],
placesCoordinate[4], placesCoordinate[4],
costForDriver.toStringAsFixed(2), costForDriver.toStringAsFixed(2),
double.parse(box.read(BoxName.passengerWalletTotal)) < 0 (double.parse(box.read(BoxName.passengerWalletTotal)) < 0
? double.parse(box.read(BoxName.passengerWalletTotal)) ? double.parse(box.read(BoxName.passengerWalletTotal))
.toStringAsFixed(2) .toStringAsFixed(2)
: '0', : '0'),
box.read(BoxName.email).toString(), box.read(BoxName.email).toString(),
data[0]['start_address'], data[0]['start_address'],
data[0]['end_address'], data[0]['end_address'],
@@ -1667,37 +1694,43 @@ class MapPassengerController extends GetxController {
kazan.toStringAsFixed(0), kazan.toStringAsFixed(0),
passengerRate.toStringAsFixed(2), passengerRate.toStringAsFixed(2),
]; ];
// Send notification to the new driver
FirebaseMessagesController().sendNotificationToDriverMAP( FirebaseMessagesController().sendNotificationToDriverMAP(
'OrderSpeed', 'OrderSpeed',
rideId.toString(), rideId,
driver['token'].toString(), driverData['token'].toString(),
body, body,
'order.wav', '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, () { // If an additional endpoint is available, post data there as well
Get.back(); if (AppLink.endPoint != AppLink.seferCairoServer) {
Get.offAll(const MapPagePassenger()); 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() { icreaseForSameRideAndDelay() {
@@ -1781,7 +1814,7 @@ class MapPassengerController extends GetxController {
confirmRideForAllDriverAvailable(); confirmRideForAllDriverAvailable();
// delayAndFetchRideStatusForAllDriverAvailable(rideId); // delayAndFetchRideStatusForAllDriverAvailable(rideId);
} else if (rideStatusDelayed == 'Apply' || statusRide == 'Apply') { } else if (rideStatusDelayed == 'Apply' || statusRide == 'Apply') {
Log.print('rideStatusDelayed == Apply: ${rideStatusDelayed}'); Log.print('rideStatusDelayed == Apply: $rideStatusDelayed');
// todo play sound // todo play sound
Get.find<AudioRecorderController>() Get.find<AudioRecorderController>()
.playSoundFromAssets('assets/start.wav'); .playSoundFromAssets('assets/start.wav');
@@ -1837,17 +1870,29 @@ class MapPassengerController extends GetxController {
int attemptCounter = 0; int attemptCounter = 0;
bool isApplied = false; bool isApplied = false;
tick = 0; tick = 0;
Log.print('tick delayAndFetchRideStatusForAllDriverAvailable: $tick'); bool shouldContinueSearching = true; // Flag to control searching
void fetchRideStatus() async { void fetchRideStatus() async {
if (attemptCounter < maxAttempts && isApplied == false || tick < 15) { if (attemptCounter < maxAttempts &&
!isApplied &&
shouldContinueSearching) {
attemptCounter++; attemptCounter++;
tick++; tick++;
var res = await getRideStatus(rideId); var res = await getRideStatus(rideId);
String rideStatusDelayed = res.toString(); 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); 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; isApplied = true;
shouldFetch = false; shouldFetch = false;
statusRide = 'Apply'; statusRide = 'Apply';
@@ -1855,89 +1900,14 @@ class MapPassengerController extends GetxController {
isSearchingWindow = false; isSearchingWindow = false;
startTimer(); startTimer();
update(); update();
startTimerFromDriverToPassengerAfterApplied(); startTimerFromDriverToPassengerAfterApplied();
shouldContinueSearching = false; // Stop searching if applied
} else if (attemptCounter >= maxAttempts && } else if (attemptCounter >= maxAttempts &&
rideStatusDelayed != 'Cancel') { rideStatusDelayed != 'Cancel') {
shouldFetch = false; shouldContinueSearching = false; // Stop searching
// If the status is still not "Apply" after 15 attempts // Show dialog to increase fee...
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();
})
],
);
});
update(); update();
print('Stopped fetching ride status after 15 attempts.');
} else { } else {
Timer(const Duration(seconds: 2), fetchRideStatus); Timer(const Duration(seconds: 2), fetchRideStatus);
} }
@@ -2026,7 +1996,7 @@ class MapPassengerController extends GetxController {
FirebaseMessagesController().sendNotificationToDriverMAP( FirebaseMessagesController().sendNotificationToDriverMAP(
'Order Applied'.tr, 'Order Applied'.tr,
'$driverName Apply order\nTake attention in other order'.tr, '$driverName Apply order\nTake attention in other order'.tr,
driverToken, driverToken.toString(),
[], [],
'start.wav', 'start.wav',
); );
@@ -2912,7 +2882,7 @@ class MapPassengerController extends GetxController {
FirebaseMessagesController().sendNotificationToDriverMAP( FirebaseMessagesController().sendNotificationToDriverMAP(
'Cancel Trip'.tr, 'Cancel Trip'.tr,
'Trip Cancelled'.tr, 'Trip Cancelled'.tr,
driverToken, driverToken.toString(),
[], [],
'cancel.wav', 'cancel.wav',
); );
@@ -3313,23 +3283,56 @@ class MapPassengerController extends GetxController {
// Log.print('BoxName.serverChosen: ${box.read(BoxName.serverChosen)}'); // Log.print('BoxName.serverChosen: ${box.read(BoxName.serverChosen)}');
newStartPointLocation = passengerLocation; newStartPointLocation = passengerLocation;
Log.print('passengerLocation: ${passengerLocation}'); Log.print('passengerLocation: $passengerLocation');
speed = _locationData.speed!; speed = _locationData.speed!;
// //print location details // //print location details
isLoading = false; isLoading = false;
update(); 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) { LatLngBounds calculateBounds(double lat, double lng, double radiusInMeters) {
const double earthRadius = 6378137.0; // Earth's radius in meters const double earthRadius = 6378137.0; // Earth's radius in meters
double latDelta = radiusInMeters / earthRadius * (180 / pi); double latDelta = (radiusInMeters / earthRadius) * (180 / pi);
double lngDelta = 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( return LatLngBounds(
southwest: LatLng(lat - latDelta, lng - lngDelta), southwest: LatLng(minLat, minLng),
northeast: LatLng(lat + latDelta, lng + lngDelta), northeast: LatLng(maxLat, maxLng),
); );
} }
@@ -3470,7 +3473,7 @@ class MapPassengerController extends GetxController {
i < dataCarsLocationByPassenger['message'].length; i < dataCarsLocationByPassenger['message'].length;
i++) { i++) {
var carLocation = dataCarsLocationByPassenger['message'][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 // Calculate distance between passenger's location and current driver's location
final distance = Geolocator.distanceBetween( 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) // Calculate duration assuming an average speed of 25 km/h (adjust as needed)
int durationToPassenger = (distance * 25 * (1000 / 3600)).round(); int durationToPassenger = (distance * 25 * (1000 / 3600)).round();
Log.print('distance: ${distance}'); Log.print('distance: $distance');
Log.print('durationToPassenger: ${durationToPassenger}'); Log.print('durationToPassenger: $durationToPassenger');
// Update the UI with the distance and duration for each car // Update the UI with the distance and duration for each car
update(); update();
@@ -3499,7 +3502,7 @@ class MapPassengerController extends GetxController {
latitude: double.parse(carLocation['latitude']), latitude: double.parse(carLocation['latitude']),
longitude: double.parse(carLocation['longitude']), longitude: double.parse(carLocation['longitude']),
); );
Log.print('nearestCar: ${nearestCar}'); Log.print('nearestCar: $nearestCar');
// Update the UI with the nearest driver // Update the UI with the nearest driver
update(); update();
} }
@@ -4283,7 +4286,7 @@ class MapPassengerController extends GetxController {
totalCostPassenger = totalDriver1 + (totalDriver1 * kazan / 100); totalCostPassenger = totalDriver1 + (totalDriver1 * kazan / 100);
totalPassenger = costSpeed + (costSpeed * kazan / 100); totalPassenger = costSpeed + (costSpeed * kazan / 100);
if (isInUniversity) { if (isInUniversity) {
Log.print('isInUniversity: ${isInUniversity}'); Log.print('isInUniversity: $isInUniversity');
totalPassengerComfort = totalPassengerComfort =
20 + (costComfort + (costComfort * kazan / 100)).ceilToDouble(); 20 + (costComfort + (costComfort * kazan / 100)).ceilToDouble();
totalPassengerLady = totalPassengerLady =
@@ -4325,7 +4328,7 @@ class MapPassengerController extends GetxController {
totalME = totalCostPassenger - tax; totalME = totalCostPassenger - tax;
costForDriver = fuelPrice * (20 / 210) * distance; costForDriver = fuelPrice * (20 / 210) * distance;
} else { } else {
Log.print('isInUniversity: ${isInUniversity}'); Log.print('isInUniversity: $isInUniversity');
totalPassengerComfort = totalPassengerComfort =
(costComfort + (costComfort * kazan / 100)).ceilToDouble(); (costComfort + (costComfort * kazan / 100)).ceilToDouble();
totalPassengerLady = totalPassengerLady =

View File

@@ -4,8 +4,8 @@ import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/constant/colors.dart'; import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/constant/links.dart'; import 'package:SEFER/constant/links.dart';
import 'package:SEFER/controller/functions/crud.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/controller/payment/payment_controller.dart';
import 'package:SEFER/views/widgets/mysnakbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_contacts/contact.dart'; import 'package:flutter_contacts/contact.dart';
import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:flutter_contacts/flutter_contacts.dart';
@@ -13,6 +13,7 @@ import 'package:get/get.dart';
import 'package:share/share.dart'; import 'package:share/share.dart';
import '../../../main.dart'; import '../../../main.dart';
import '../../../print.dart';
import '../../../views/widgets/my_dialog.dart'; import '../../../views/widgets/my_dialog.dart';
import '../../functions/launch.dart'; import '../../functions/launch.dart';
import '../../notification/notification_captain_controller.dart'; import '../../notification/notification_captain_controller.dart';
@@ -117,23 +118,49 @@ Download the SEFER app now and enjoy your ride!
Future<void> pickContacts() async { Future<void> pickContacts() async {
try { try {
// Request contacts permission
if (await FlutterContacts.requestPermission(readonly: true)) { if (await FlutterContacts.requestPermission(readonly: true)) {
final List<Contact> fetchedContacts = // Fetch all contacts with full properties
await FlutterContacts.getContacts(withProperties: true); final List<Contact> allContacts = await FlutterContacts.getContacts(
contacts = fetchedContacts; withProperties: true,
withThumbnail: false,
withPhoto: true,
);
// Convert contacts to a list of maps // Check if contacts are available
contactMaps.value = fetchedContacts.map((contact) { if (allContacts.isNotEmpty) {
return { // Store the contacts
'name': contact.displayName, contacts = allContacts;
'phones': Log.print('contacts: $contacts');
contact.phones.map((phone) => phone.normalizedNumber).toList(),
'emails': contact.emails.map((email) => email.address).toList(),
};
}).toList();
update();
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, Get.snackbar('No contacts available'.tr,
'Please add contacts to your phone.'.tr); 'Please add contacts to your phone.'.tr);
} }
@@ -225,8 +252,10 @@ Download the SEFER app now and enjoy your ride!
} }
void sendInviteToPassenger() async { void sendInviteToPassenger() async {
if (invitePhoneController.text.isEmpty) { if (invitePhoneController.text.isEmpty ||
Get.snackbar('Error', 'Please enter an phone address'.tr); invitePhoneController.text.length < 11) {
mySnackeBarError('Please enter a correct phone'.tr);
return; return;
} }

View File

@@ -20,72 +20,58 @@ class LocaleController extends GetxController {
case "ar": case "ar":
locale = const Locale("ar"); locale = const Locale("ar");
appTheme = themeArabic; appTheme = themeArabic;
box.write(BoxName.lang, 'ar');
break; break;
case "en": case "en":
locale = const Locale("en"); locale = const Locale("en");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'en');
break; break;
case "tr": case "tr":
locale = const Locale("tr"); locale = const Locale("tr");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'tr');
break; break;
case "fr": case "fr":
locale = const Locale("fr"); locale = const Locale("fr");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'fr');
break; break;
case "it": case "it":
locale = const Locale("it"); locale = const Locale("it");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'it');
break; break;
case "de": case "de":
locale = const Locale("de"); locale = const Locale("de");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'de');
break; break;
case "el": case "el":
locale = const Locale("el"); locale = const Locale("el");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'el');
break; break;
case "es": case "es":
locale = const Locale("es"); locale = const Locale("es");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'es');
break; break;
case "fa": case "fa":
locale = const Locale("fa"); locale = const Locale("fa");
appTheme = themeEnglish; appTheme = themeArabic;
box.write(BoxName.lang, 'fa');
break; break;
case "zh": case "zh":
locale = const Locale("zh"); locale = const Locale("zh");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'zh');
break; break;
case "ru": case "ru":
locale = const Locale("ru"); locale = const Locale("ru");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'ru');
break; break;
case "hi": case "hi":
locale = const Locale("hi"); locale = const Locale("hi");
appTheme = themeEnglish; appTheme = themeEnglish;
box.write(BoxName.lang, 'hi');
break; break;
default: default:
locale = Locale(Get.deviceLocale!.languageCode); locale = Locale(Get.deviceLocale!.languageCode);
box.write(BoxName.lang, Get.deviceLocale!.languageCode);
appTheme = themeEnglish; appTheme = themeEnglish;
break; break;
} }
box.write(BoxName.lang, langcode); box.write(BoxName.lang, langcode);
// box.write(BoxName.lang, langcode);
Get.changeTheme(appTheme); Get.changeTheme(appTheme);
Get.updateLocale(locale); Get.updateLocale(locale);
restartApp(); restartApp();
@@ -94,62 +80,15 @@ class LocaleController extends GetxController {
@override @override
void onInit() { void onInit() {
String storedLang = box.read(BoxName.lang) ?? "ar"; String? storedLang = box.read(BoxName.lang);
switch (storedLang) { if (storedLang == null) {
case "ar": // Use device language if no language is stored
language = const Locale("ar"); storedLang = Get.deviceLocale!.languageCode;
appTheme = themeArabic; box.write(BoxName.lang, storedLang);
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;
} }
changeLang(storedLang);
super.onInit(); super.onInit();
} }
} }

View File

@@ -52,13 +52,18 @@ class MyTranslation extends Translations {
"Pick or Tap to confirm": "حدد أو انقر للتأكيد", "Pick or Tap to confirm": "حدد أو انقر للتأكيد",
"Select Order Type": "حدد نوع الطلب", "Select Order Type": "حدد نوع الطلب",
"Choose who this order is for": "اختر لمن هذا الطلب", "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 myself": "أريد أن أطلب لنفسي",
"I want to order for someone else": "أريد أن أطلب لشخص آخر", "I want to order for someone else": "أريد أن أطلب لشخص آخر",
"Cancel Trip from driver": "إلغاء الرحلة من السائق", "Cancel Trip from driver": "إلغاء الرحلة من السائق",
"Order Cancelled": "تم إلغاء الطلب",
"you canceled order": "لقد قمت بإلغاء الطلب",
"If you want order to another person": "إذا كنت تريد الطلب لشخص آخر", "If you want order to another person": "إذا كنت تريد الطلب لشخص آخر",
"Ok I will go now.": "حسنًا، سأذهب الآن.", "Ok I will go now.": "حسنًا، سأذهب الآن.",
"Hi, I will go now": "مرحبًا، سأذهب الآن.", "Hi, I will go now": "مرحبًا، سأذهب الآن.",
"upgrade price": "رفع السعر", "upgrade price": "رفع السعر",
'Please enter a correct phone': 'يرجى إدخال رقم هاتف صحيح',
'airport': 'مطار', 'airport': 'مطار',
"Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.": "Best choice for a comfortable car with a flexible route and stop points. This airport offers visa entry at this price.":
"أفضل اختيار لسيارة مريحة مع طريق ونقاط توقف مرنة. يقدم هذا المطار تأشيرة دخول بهذا السعر.", "أفضل اختيار لسيارة مريحة مع طريق ونقاط توقف مرنة. يقدم هذا المطار تأشيرة دخول بهذا السعر.",

View File

@@ -699,7 +699,8 @@ class PaymentController extends GetxController {
); );
// if (response!.success == true && response.responseCode == '200') { // 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}'); // Log.print('transactionID wewer: ${response.transactionID}');
Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor); Toast.show(context, 'Payment Successful'.tr, AppColor.greenColor);
method(); method();

View File

@@ -45,18 +45,6 @@ void main() async {
// if (Platform.isAndroid) { // if (Platform.isAndroid) {
NotificationController notificationController = NotificationController notificationController =
Get.put(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(); // await NotificationController().initNotifications();
// } // }
@@ -100,13 +88,18 @@ void main() async {
userTokenExpiration: 200, userTokenExpiration: 200,
iFrameID: 837992, iFrameID: 837992,
); );
// Get device information await notificationController.initNotifications();
// List<Map<String, dynamic>> deviceDataList =
// await DeviceInfoPlus.getDeviceInfo();
//
// // Print all device data
// DeviceInfoPlus.printDeviceInfo();
// 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.scheduleNotificationsForSevenDays(
randomMessage.split(':')[0],
randomMessage.split(':')[1],
"tone1",
);
runApp(const MyApp()); runApp(const MyApp());
} }

View File

@@ -7,6 +7,7 @@ import '../../../constant/box_name.dart';
import '../../../constant/colors.dart'; import '../../../constant/colors.dart';
import '../../../controller/home/profile/invit_controller.dart'; import '../../../controller/home/profile/invit_controller.dart';
import '../../../main.dart'; import '../../../main.dart';
import '../../../print.dart';
class ShareAppPage extends StatelessWidget { class ShareAppPage extends StatelessWidget {
final InviteController controller = Get.put(InviteController()); final InviteController controller = Get.put(InviteController());
@@ -81,6 +82,40 @@ class ShareAppPage extends StatelessWidget {
); );
} }
// Widget _buildPhoneInput() {
// return Container(
// decoration: BoxDecoration(
// color: CupertinoColors.systemGrey6,
// borderRadius: BorderRadius.circular(8),
// ),
// child: Row(
// children: [
// Expanded(
// child: CupertinoTextField.borderless(
// controller: controller.invitePhoneController,
// placeholder: 'Enter phone'.tr,
// padding: const EdgeInsets.all(12),
// keyboardType: TextInputType.phone,
// ),
// ),
// CupertinoButton(
// child: const Icon(CupertinoIcons.person_badge_plus,
// color: AppColor.blueColor),
// onPressed: () async {
// await controller.pickContacts();
// if (controller.contacts.isNotEmpty) {
// if (box.read(BoxName.isSavedPhones) == null) {
// controller.savePhoneToServer();
// box.write(BoxName.isSavedPhones, true);
// }
// _showContactsDialog(Get.context!);
// }
// },
// ),
// ],
// ),
// );
// }
Widget _buildPhoneInput() { Widget _buildPhoneInput() {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -102,12 +137,15 @@ class ShareAppPage extends StatelessWidget {
color: AppColor.blueColor), color: AppColor.blueColor),
onPressed: () async { onPressed: () async {
await controller.pickContacts(); await controller.pickContacts();
Log.print('contacts: ${controller.contacts}');
if (controller.contacts.isNotEmpty) { if (controller.contacts.isNotEmpty) {
if (box.read(BoxName.isSavedPhones) == null) { _showContactsDialog(Get
controller.savePhoneToServer(); .context!); // Show contacts dialog after loading contacts
box.write(BoxName.isSavedPhones, true); } else {
} Get.snackbar(
_showContactsDialog(Get.context!); 'No contacts available'.tr,
'Please add contacts to your phone.'.tr,
);
} }
}, },
), ),
@@ -326,48 +364,38 @@ class ShareAppPage extends StatelessWidget {
} }
void _showContactsDialog(BuildContext context) { void _showContactsDialog(BuildContext context) {
showCupertinoModalPopup( Get.defaultDialog(
context: context, title: 'Choose from contact'.tr,
builder: (BuildContext context) => Container( content: SizedBox(
height: 400, height: 400,
decoration: BoxDecoration( width: 400,
color: CupertinoColors.systemBackground,
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
boxShadow: [
BoxShadow(
color: CupertinoColors.black.withOpacity(0.2),
offset: const Offset(0, -4),
blurRadius: 10,
),
],
),
child: Column( child: Column(
children: [ children: [
// Header with cancel and title // Header with cancel and title
Container( // Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), // padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: const BoxDecoration( // decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)), // borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
color: CupertinoColors.systemGrey6, // color: CupertinoColors.systemGrey6,
), // ),
child: Row( // child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ // children: [
CupertinoButton( // CupertinoButton(
padding: EdgeInsets.zero, // padding: EdgeInsets.zero,
child: Text( // child: Text(
'Cancel'.tr, // 'Cancel'.tr,
style: const TextStyle(color: CupertinoColors.systemBlue), // style: const TextStyle(color: CupertinoColors.systemBlue),
), // ),
onPressed: () => Navigator.pop(context), // onPressed: () => Navigator.pop(context),
), // ),
Container( // Container(
child: Text('Choose from contact'.tr, // child: Text('Choose from contact'.tr,
style: AppStyle.title)), // style: AppStyle.title)),
const SizedBox(width: 60), // Balance for Cancel button // const SizedBox(width: 60), // Balance for Cancel button
], // ],
), // ),
), // ),
// Contact list // Contact list
Expanded( Expanded(
@@ -433,5 +461,112 @@ class ShareAppPage extends StatelessWidget {
), ),
), ),
); );
// showCupertinoModalPopup(
// context: context,
// builder: (BuildContext context) => Container(
// height: 400,
// decoration: BoxDecoration(
// color: CupertinoColors.systemBackground,
// borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
// boxShadow: [
// BoxShadow(
// color: CupertinoColors.black.withOpacity(0.2),
// offset: const Offset(0, -4),
// blurRadius: 10,
// ),
// ],
// ),
// child: Column(
// children: [
// // Header with cancel and title
// Container(
// padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
// decoration: const BoxDecoration(
// borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
// color: CupertinoColors.systemGrey6,
// ),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// CupertinoButton(
// padding: EdgeInsets.zero,
// child: Text(
// 'Cancel'.tr,
// style: const TextStyle(color: CupertinoColors.systemBlue),
// ),
// onPressed: () => Navigator.pop(context),
// ),
// Container(
// child: Text('Choose from contact'.tr,
// style: AppStyle.title)),
// const SizedBox(width: 60), // Balance for Cancel button
// ],
// ),
// ),
// // Contact list
// Expanded(
// child: ListView.builder(
// itemCount: controller.contactMaps.length,
// itemBuilder: (context, index) {
// final contact = controller.contactMaps[index];
// return CupertinoButton(
// padding: EdgeInsets.zero,
// onPressed: () {
// controller.selectPhone(contact['phones'].toString());
// },
// child: Container(
// padding: const EdgeInsets.symmetric(
// horizontal: 16, vertical: 12),
// decoration: BoxDecoration(
// color: CupertinoColors.systemBackground,
// border: Border(
// bottom: BorderSide(
// color: CupertinoColors.separator.withOpacity(0.5),
// ),
// ),
// ),
// child: Row(
// children: [
// // Display contact name and phone number
// Expanded(
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// contact['name'],
// style: const TextStyle(
// color: CupertinoColors.label,
// fontSize: 17,
// fontWeight: FontWeight.w500,
// ),
// ),
// Text(
// controller.formatPhoneNumber(
// contact['phones'][0].toString()),
// style: const TextStyle(
// color: CupertinoColors.secondaryLabel,
// fontSize: 15,
// ),
// ),
// ],
// ),
// ),
// // Chevron icon for selection
// const Icon(
// CupertinoIcons.chevron_forward,
// color: CupertinoColors.systemGrey2,
// ),
// ],
// ),
// ),
// );
// },
// ),
// ),
// ],
// ),
// ),
// );
} }
} }

View File

@@ -97,15 +97,7 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
// borderRadius: BorderRadius.circular(15)), // borderRadius: BorderRadius.circular(15)),
// child: IconButton( // child: IconButton(
// onPressed: () async { // onPressed: () async {
// final random = Random(); // Get.to(SmsSignupEgypt());
// final randomMessage =
// messages[random.nextInt(messages.length)];
// NotificationController().showNotification(
// randomMessage.split(':')[0],
// randomMessage.split(':')[1],
// "ding",
// );
// print(box.read(BoxName.countryCode).toString());
// }, // },
// icon: const Icon( // icon: const Icon(
// Icons.voice_chat, // Icons.voice_chat,

View File

@@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
SnackbarController mySnackeBarError(String message) {
return Get.snackbar(
'Error'.tr,
message,
backgroundColor: AppColor.redColor.withOpacity(0.9),
colorText: AppColor.secondaryColor,
icon: const Icon(Icons.error, color: AppColor.secondaryColor),
shouldIconPulse: true,
snackPosition: SnackPosition.TOP,
margin: const EdgeInsets.all(10),
borderRadius: 10,
animationDuration: const Duration(milliseconds: 500),
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
titleText: Text(
'Error'.tr,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 16,
),
),
messageText: Text(
message,
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 14,
),
),
);
}
SnackbarController mySnackbarSuccess(String message) {
return Get.snackbar(
'Success'.tr,
message,
backgroundColor: AppColor.greenColor
.withOpacity(0.9), // Assuming green color for success
colorText: AppColor.secondaryColor,
icon: const Icon(Icons.check_circle, color: AppColor.secondaryColor),
shouldIconPulse: true,
snackPosition: SnackPosition.TOP,
margin: const EdgeInsets.all(10),
borderRadius: 10,
animationDuration: const Duration(milliseconds: 500),
forwardAnimationCurve: Curves.easeOutBack,
reverseAnimationCurve: Curves.easeInBack,
titleText: Text(
'Success'.tr,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white,
fontSize: 16,
),
),
messageText: Text(
message,
style: TextStyle(
color: Colors.white.withOpacity(0.9),
fontSize: 14,
),
),
);
}