This commit is contained in:
Hamza-Ayed
2024-11-20 20:24:49 +02:00
parent f796f4bc48
commit 231405ce9f
14 changed files with 725 additions and 351 deletions

View File

@@ -171,6 +171,7 @@ class AppLink {
//-----------------mishwari------------------
static String addMishwari = "$ride/mishwari/add.php";
static String cancelMishwari = "$ride/mishwari/cancel.php";
static String getMishwari = "$ride/mishwari/get.php";
//-----------------DriverOrder------------------

View File

@@ -113,6 +113,104 @@ class NotificationController extends GetxController {
print('Notifications scheduled successfully for the next 7 days');
}
void scheduleNotificationsForTimeSelected(
String title, String message, String tone, DateTime timeSelected) async {
final AndroidNotificationDetails android = AndroidNotificationDetails(
'high_importance_channel',
'High Importance Notifications',
importance: Importance.max,
priority: Priority.high,
sound: RawResourceAndroidNotificationSound(tone),
);
const DarwinNotificationDetails ios = DarwinNotificationDetails(
sound: 'default',
presentAlert: true,
presentBadge: true,
presentSound: true,
);
final NotificationDetails details =
NotificationDetails(android: android, iOS: ios);
// Check for the exact alarm permission on Android 12 and above
if (Platform.isAndroid) {
if (await Permission.scheduleExactAlarm.isDenied) {
if (await Permission.scheduleExactAlarm.request().isGranted) {
print('SCHEDULE_EXACT_ALARM permission granted');
} else {
print('SCHEDULE_EXACT_ALARM permission denied');
return;
}
}
}
// Schedule notifications for 10 and 30 minutes before the timeSelected
await _scheduleNotificationForTimeVIP(
timeSelected.subtract(const Duration(minutes: 10)), // 10 minutes before
title,
message,
details,
1, // Unique ID for 10-minute before notification
);
await _scheduleNotificationForTimeVIP(
timeSelected.subtract(const Duration(minutes: 30)), // 30 minutes before
title,
message,
details,
2, // Unique ID for 30-minute before notification
);
print('Notifications scheduled successfully for the time selected');
}
Future<void> _scheduleNotificationForTimeVIP(
DateTime scheduledDate,
String title,
String message,
NotificationDetails details,
int notificationId,
) async {
// Initialize and set Cairo timezone
tz.initializeTimeZones();
var cairoLocation = tz.getLocation('Africa/Cairo');
final now = tz.TZDateTime.now(cairoLocation);
// Convert to Cairo time
tz.TZDateTime scheduledTZDateTime =
tz.TZDateTime.from(scheduledDate, cairoLocation);
// Check if 10 minutes before the scheduled time is in the past
if (scheduledTZDateTime
.subtract(const Duration(minutes: 10))
.isBefore(now)) {
// If the 10 minutes before the scheduled time is in the past, don't schedule
print(
'Scheduled time minus 10 minutes is in the past. Skipping notification.');
return; // Skip this notification
}
print('Current time (Cairo): $now');
print('Scheduling notification for: $scheduledTZDateTime');
await _flutterLocalNotificationsPlugin.zonedSchedule(
notificationId, // Unique ID for each notification
title,
message,
scheduledTZDateTime,
details,
androidScheduleMode: AndroidScheduleMode.exact,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
matchDateTimeComponents:
null, // Don't repeat automatically; we handle manually
);
print('Notification scheduled successfully for: $scheduledTZDateTime');
}
Future<void> _scheduleNotificationForTime(
int dayOffset,
int hour,
@@ -138,7 +236,7 @@ class NotificationController extends GetxController {
// If the scheduled time is in the past, move it to the next day
if (scheduledDate.isBefore(now)) {
scheduledDate = scheduledDate.add(Duration(days: 1));
scheduledDate = scheduledDate.add(const Duration(days: 1));
}
print('Current time (Cairo): $now');

View File

@@ -5,6 +5,7 @@ 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:SEFER/views/widgets/mysnakbar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_confetti/flutter_confetti.dart';
import 'package:vector_math/vector_math.dart' show radians, degrees;
@@ -42,6 +43,7 @@ import '../functions/crud.dart';
import '../functions/launch.dart';
import '../functions/secure_storage.dart';
import '../payment/payment_controller.dart';
import 'vip_waitting_page.dart';
class MapPassengerController extends GetxController {
bool isLoading = true;
@@ -3069,20 +3071,41 @@ class MapPassengerController extends GetxController {
}
Future getPlaces() async {
var languageCode;
// Check if `placeDestinationController.text` contains English characters
if (RegExp(r'[a-zA-Z]').hasMatch(placeDestinationController.text)) {
languageCode = 'en';
} else {
languageCode = 'ar';
}
var url =
// '${AppLink.googleMapsLink}place/nearbysearch/json?location=${mylocation.longitude}&radius=25000&language=ar&keyword=&key=${placeController.text}${AK.mapAPIKEY}';
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeDestinationController.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=50000&language=ar&key=${AK.mapAPIKEY.toString()}';
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeDestinationController.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
print(url);
var response = await CRUD().getGoogleApi(link: url, payload: {});
Log.print('response: ${response}');
placesDestination = response['results'];
update();
}
Future getPlacesStart() async {
var languageCode = wayPoint0Controller.text;
// Regular expression to check for English alphabet characters
final englishRegex = RegExp(r'[a-zA-Z]');
// Check if text contains English characters
if (englishRegex.hasMatch(languageCode)) {
languageCode = 'en';
} else {
languageCode = 'ar';
}
var url =
// '${AppLink.googleMapsLink}place/nearbysearch/json?location=${mylocation.longitude}&radius=25000&language=ar&keyword=&key=${placeController.text}${AK.mapAPIKEY}';
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeStartController.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=50000&language=ar&key=${AK.mapAPIKEY.toString()}';
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeStartController.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
var response = await CRUD().getGoogleApi(link: url, payload: {});
@@ -3091,15 +3114,45 @@ class MapPassengerController extends GetxController {
}
Future getPlacesListsWayPoint(int index) async {
var languageCode = wayPoint0Controller.text;
// Regular expression to check for English alphabet characters
final englishRegex = RegExp(r'[a-zA-Z]');
// Check if text contains English characters
if (englishRegex.hasMatch(languageCode)) {
languageCode = 'en';
} else {
languageCode = 'ar';
}
var url =
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${wayPoint0Controller.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=50000&language=ar&key=${AK.mapAPIKEY.toString()}';
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${wayPoint0Controller.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=250000&language=$languageCode&key=${AK.mapAPIKEY.toString()}';
var response = await CRUD().getGoogleApi(link: url, payload: {});
try {
var response = await CRUD().getGoogleApi(link: url, payload: {});
wayPoint0 = response['results'];
placeListResponseAll[index] = response['results'];
update();
if (response != null && response['results'] != null) {
wayPoint0 = response['results'];
placeListResponseAll[index] = response['results'];
update();
} else {
print('Error: Invalid response from Google Places API');
}
} catch (e) {
print('Error fetching places: $e');
}
}
// Future getPlacesListsWayPoint(int index) async {
// var url =
// '${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${wayPoint0Controller.text}&location=${passengerLocation.latitude},${passengerLocation.longitude}&radius=80000&language=${}&key=${AK.mapAPIKEY.toString()}';
// var response = await CRUD().getGoogleApi(link: url, payload: {});
// wayPoint0 = response['results'];
// placeListResponseAll[index] = response['results'];
// update();
// }
LatLng fromString(String location) {
List<String> parts = location.split(',');
@@ -3677,7 +3730,7 @@ class MapPassengerController extends GetxController {
isLoading = false;
update();
var url =
('${AppLink.googleMapsLink}directions/json?&language=ar&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');
('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang) ?? 'ar'}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}');
var response = await CRUD().getGoogleApi(link: url, payload: {});
data = response['routes'][0]['legs'];
@@ -4488,15 +4541,51 @@ class MapPassengerController extends GetxController {
}
List driversForMishwari = [];
Future selectDriverAndCarForMishwariTrip() async {
var res = await CRUD()
.get(link: AppLink.selectDriverAndCarForMishwariTrip, payload: {});
if (res != 'failure') {
var d = jsonDecode(res);
driversForMishwari = d['message'];
update();
} else {
return 'No driver available now try later time\nthanks for using our app'
// Calculate the bounds for 20km
double latitudeOffset = 0.1795; // 20km range in latitude
double longitudeOffset = 0.2074; // 20km range in longitude
// Calculate bounding box based on passenger's location
double southwestLat = passengerLocation.latitude - latitudeOffset;
double northeastLat = passengerLocation.latitude + latitudeOffset;
double southwestLon = passengerLocation.longitude - longitudeOffset;
double northeastLon = passengerLocation.longitude + longitudeOffset;
// Create the payload with calculated bounds
var payload = {
'southwestLat': southwestLat.toString(),
'northeastLat': northeastLat.toString(),
'southwestLon': southwestLon.toString(),
'northeastLon': northeastLon.toString(),
};
try {
// Fetch data from the API
var res = await CRUD().get(
link: AppLink.selectDriverAndCarForMishwariTrip, payload: payload);
if (res != 'failure') {
// Check if response is valid JSON
try {
var d = jsonDecode(res);
driversForMishwari = d['message'];
Log.print('driversForMishwari: ${driversForMishwari}');
update();
} catch (e) {
// Handle invalid JSON format
print("Error decoding JSON: $e");
return 'Server returned invalid data. Please try again later.';
}
} else {
return 'No driver available now, try again later. Thanks for using our app.'
.tr;
}
} catch (e) {
// Handle network or other exceptions
print("Error fetching data: $e");
return 'There was an issue connecting to the server. Please try again later.'
.tr;
}
}
@@ -4519,22 +4608,23 @@ class MapPassengerController extends GetxController {
// changeCashConfirmPageShown();
}
var driverIdVip = '';
Future<void> saveTripData(
Map<String, dynamic> driver, DateTime tripDateTime) async {
try {
// Prepare trip data
Map<String, dynamic> tripData = {
'id': driver['id'].toString(), // Ensure the id is a string
'id': driver['driver_id'].toString(), // Ensure the id is a string
'phone': driver['phone'],
'gender': driver['gender'],
'name': driver['NAME'],
'name_english': driver['name_english'],
'address': driver['address'],
'religion': driver['religion'],
'religion': driver['religion'] ?? 'UnKnown',
'age': driver['age'].toString(), // Convert age to String
'education': driver['education'],
'license_type': driver['license_type'],
'national_number': driver['national_number'],
'education': driver['education'] ?? 'UnKnown',
'license_type': driver['license_type'] ?? 'UnKnown',
'national_number': driver['national_number'] ?? 'UnKnown',
'car_plate': driver['car_plate'],
'make': driver['make'],
'model': driver['model'],
@@ -4546,12 +4636,12 @@ class MapPassengerController extends GetxController {
'token': driver['token'],
'rating': driver['rating'].toString(), // Convert rating to String
'countRide':
driver['countRide'].toString(), // Convert countRide to String
driver['ride_count'].toString(), // Convert countRide to String
'passengerId': box.read(BoxName.passengerID),
'timeSelected': tripDateTime.toIso8601String(),
'status': 'pending',
};
// Log.print('tripData: $tripData');
Log.print('tripData: $tripData');
// Send data to server
var response =
@@ -4560,33 +4650,52 @@ class MapPassengerController extends GetxController {
if (response != 'failure') {
// Trip saved successfully
Get.snackbar('Success'.tr, 'Trip booked successfully'.tr);
// Get.snackbar('Success'.tr, 'Trip booked successfully'.tr);
var id = response['message'].toString();
if (AppLink.endPoint != AppLink.seferCairoServer) {
await CRUD().post(
link: "${AppLink.endPoint}/ride/mishwari/add.php",
payload: tripData);
}
driverIdVip = driver['driver_id'];
DateTime timeSelected = DateTime.parse(tripDateTime.toIso8601String());
Get.find<NotificationController>().scheduleNotificationsForTimeSelected(
"Your trip is scheduled".tr,
"Don't forget your ride!".tr,
"tone1",
timeSelected);
// Optionally, set up local notification or send a push notification
// await setLocalNotification(tripDateTime);
await FirebaseMessagesController().sendNotificationToDriverMAP(
'OrderVIP',
rideId.toString(),
driver['token'].toString(),
[
id,
driver['id'],
passengerLocation.latitude.toString(),
passengerLocation.longitude.toString(),
box.read(BoxName.name).toString(),
box.read(BoxName.passengerID).toString(),
box.read(BoxName.phone).toString(),
box.read(BoxName.email).toString(),
box.read(BoxName.passengerPhotoUrl).toString(),
box.read(BoxName.tokenFCM).toString(),
driver['token'].toString(),
],
'order.wav');
// await FirebaseMessagesController().sendNotificationToDriverMAP(
// 'OrderVIP',
// rideId.toString(),
// driver['token'].toString(),
// [
// id,
// driver['id'],
// passengerLocation.latitude.toString(),
// passengerLocation.longitude.toString(),
// box.read(BoxName.name).toString(),
// box.read(BoxName.passengerID).toString(),
// box.read(BoxName.phone).toString(),
// box.read(BoxName.email).toString(),
// box.read(BoxName.passengerPhotoUrl).toString(),
// box.read(BoxName.tokenFCM).toString(),
// driver['token'].toString(),
// ],
// 'order.wav');
if (response['message'] == "Trip updated successfully") {
mySnackbarSuccess("Trip updated successfully".tr);
// FirebaseMessagesController().sendNotificationToDriverMAP(
// 'Order VIP Canceld'.tr,
// 'Passenger cancel order'.tr,
// token,
// [],
// 'cancel.wav',
// );
}
Get.to(() => const VipWaittingPage());
} else {
throw Exception('Failed to save trip');
}
@@ -4598,6 +4707,22 @@ class MapPassengerController extends GetxController {
}
}
cancelVip(String token, tripId) async {
// FirebaseMessagesController().sendNotificationToDriverMAP(
// 'Order VIP Canceld'.tr,
// 'Passenger cancel order'.tr,
// token,
// [],
// 'cancel.wav',
// );
var res = await CRUD()
.post(link: AppLink.cancelMishwari, payload: {'id': tripId});
if (res != 'failur') {
Get.back();
mySnackbarSuccess('You canceled VIP trip'.tr);
}
}
initilizeGetStorage() async {
if (box.read(BoxName.addWork) == null) {
box.write(BoxName.addWork, 'addWork');

View File

@@ -0,0 +1,190 @@
import 'dart:convert';
import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/controller/home/map_passenger_controller.dart';
import 'package:SEFER/views/widgets/elevated_btn.dart';
import 'package:SEFER/views/widgets/mycircular.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../constant/links.dart';
import '../functions/crud.dart';
class VipWaittingPage extends StatelessWidget {
const VipWaittingPage({super.key});
@override
Widget build(BuildContext context) {
Get.put(VipOrderController());
return Scaffold(
appBar: AppBar(
title: Text("Waiting VIP".tr),
),
body: GetBuilder<VipOrderController>(builder: (vipOrderController) {
var data = vipOrderController.tripData[0];
// Function to get the localized status string
String getLocalizedStatus(String status) {
switch (status) {
case 'pending':
return 'pending'.tr;
case 'accepted':
return 'accepted'.tr;
case 'rejected':
return 'rejected'.tr;
default:
return 'unknown'.tr; // Fallback for unexpected statuses
}
}
// Function to get the appropriate status color
Color getStatusColor(String status) {
switch (status) {
case 'pending':
return Colors.yellow;
case 'accepted':
return Colors.green;
case 'rejected':
return Colors.red;
default:
return Colors.grey; // Default color for unknown statuses
}
}
return vipOrderController.isLoading
? const MyCircularProgressIndicator()
: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${'Driver Name:'.tr} ${data['name']}",
style: AppStyle.title,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${'Car Plate:'.tr} ${data['car_plate']}",
style: AppStyle.title,
),
Text(
"${'Car Make:'.tr} ${data['make']}",
style: AppStyle.title,
),
Text(
"${'Car Model:'.tr} ${data['model']}",
style: AppStyle.title,
),
Text(
"${"Car Color:".tr} ${data['color']}",
style: AppStyle.title,
),
],
),
SizedBox(
width: 100,
height: 100,
child: Icon(Fontisto.car,
size: 80,
color: Color(int.parse(data['color_hex']
.replaceFirst('#', '0xff'))))),
],
),
// Text(
// "${'Driver Phone:'.tr} ${data['phone']}",
// style: AppStyle.title,
// ),
const SizedBox(height: 12),
const Divider(),
const SizedBox(height: 12),
Container(
color: getStatusColor(
data['status']), // Correctly assigns a Color
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"${'Trip Status:'.tr} ${getLocalizedStatus(data['status'])}", // Uses the String function
style: const TextStyle(
fontSize: 16,
),
),
),
),
Text(
"${'Scheduled Time:'.tr} ${DateFormat('yyyy-MM-dd hh:mm a').format(DateTime.parse(data['timeSelected']))}",
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 12),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyElevatedButton(
title: "Cancel Trip".tr,
kolor: AppColor.redColor,
onPressed: () {
Get.find<MapPassengerController>().cancelVip(
data['token'].toString(),
data['id'].toString(),
);
},
),
// MyElevatedButton(
// title: "Accept Trip".tr,
// kolor: AppColor.greenColor,
// onPressed: () {
// // Add your cancel trip logic here
// },
// ),
],
),
],
),
),
);
}),
);
}
}
class VipOrderController extends GetxController {
bool isLoading = false;
final arguments = Get.arguments;
late String body;
List tripData = [];
fetchOrder() async {
isLoading = true;
update();
var res = await CRUD().get(link: AppLink.getMishwari, payload: {
'driverId': Get.find<MapPassengerController>().driverIdVip.toString(),
});
isLoading = false;
update();
if (res != 'failure') {
tripData = jsonDecode(res)['message'];
update();
}
}
@override
void onInit() async {
fetchOrder();
super.onInit();
}
}

View File

@@ -4,6 +4,32 @@ class MyTranslation extends Translations {
@override
Map<String, Map<String, String>> get keys => {
"ar": {
"Driver Name:": "اسم السائق:",
"Car Plate:": "رقم اللوحة:",
"Order Cancelled": "تم إلغاء الطلب",
'You canceled VIP trip': "ألغيت الرحلة",
"Passenger cancelled order": "الراكب قام بإلغاء الطلب",
"Your trip is scheduled": "رحلتك مجدولة",
"Don't forget your ride!": "لا تنسَ رحلتك!",
"Trip updated successfully": "تم تحديث الرحلة بنجاح",
"Car Make:": "ماركة السيارة:",
"Car Model:": "طراز السيارة:", "Car Color:": "لون السيارة:",
"Driver Phone:": "رقم هاتف السائق:",
'Pre-booking': 'احجز مسبقًا', "Waiting VIP": "انتظار VIP",
"Driver List": "قائمة السائقين", "Confirm Trip": "تأكيد الرحلة",
"Select date and time of trip": "حدد تاريخ ووقت الرحلة",
"Date and Time Picker": "اختيار التاريخ والوقت",
"Trip Status:": "حالة الرحلة:", "pending": "قيد الانتظار",
"accepted": "تم القبول",
"rejected": "تم الرفض",
"Scheduled Time:": "الوقت المحدد:",
"No drivers available": "لا يوجد سائقين متاحين",
"Please try again in a few moments":
"يرجى المحاولة مرة أخرى بعد قليل",
"Unknown Driver": "سائق غير معروف",
"rides": "الرحلات",
"The reason is": "السبب هو",
"User does not have a wallet #1652": "المستخدم ليس لديه محفظة ",
"Price of trip": "سعر الرحلة",
"For Speed and Delivery trips, the price is calculated dynamically. For Comfort trips, the price is based on time and distance":
"بالنسبة لرحلات السرعة والتوصيل، يتم حساب السعر ديناميكياً. بالنسبة لرحلات الراحة، يتم حساب السعر بناءً على الوقت والمسافة",

View File

@@ -19,6 +19,7 @@ import '../../constant/colors.dart';
import '../../constant/info.dart';
import '../../constant/links.dart';
import '../../main.dart';
import '../../print.dart';
import '../functions/crud.dart';
import '../functions/toast.dart';
import 'paymob/paymob_wallet.dart';
@@ -697,7 +698,7 @@ class PaymentController extends GetxController {
billingData: PaymobBillingDataWallet(),
onPayment: (PaymobResponseWallet response) {},
);
// Log.print('response.message!: ${response!.responseCode!}');
// if (response!.success == true && response.responseCode == '200') {
if (response!.responseCode.toString() == '200' &&
response.success == true) {

View File

@@ -190,7 +190,8 @@ class CarDetailsTypeToChoose extends StatelessWidget {
.totalPassengerRayehGai
.toStringAsFixed(
1)
: '50',
: 'Pre-booking'
.tr,
style:
AppStyle.title.copyWith(fontSize: 20),
),

View File

@@ -1,17 +1,11 @@
import 'dart:math';
import 'package:SEFER/views/auth/login_page.dart';
import 'package:SEFER/views/auth/sms_verfy_page.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../constant/box_name.dart';
import '../../../constant/colors.dart';
import '../../../constant/notification.dart';
import '../../../controller/firebase/local_notification.dart';
import '../../../controller/functions/crud.dart';
import '../../../controller/functions/tts.dart';
import '../../../controller/home/map_passenger_controller.dart';
import '../../../main.dart';
import '../../../controller/home/vip_waitting_page.dart';
GetBuilder<MapPassengerController> leftMainMenuIcons() {
final textToSpeechController = Get.put(TextToSpeechController());
@@ -88,135 +82,23 @@ GetBuilder<MapPassengerController> leftMainMenuIcons() {
const SizedBox(
width: 5,
),
// AnimatedContainer(
// duration: const Duration(microseconds: 200),
// width: controller.widthMapTypeAndTraffic,
// decoration: BoxDecoration(
// color: AppColor.secondaryColor,
// border: Border.all(),
// borderRadius: BorderRadius.circular(15)),
// child: IconButton(
// onPressed: () async {
// Get.to(SmsSignupEgypt());
// },
// icon: const Icon(
// Icons.voice_chat,
// size: 29,
// ),
// ),
// ),
// AnimatedContainer(
// duration: const Duration(microseconds: 200),
// width: controller.widthMapTypeAndTraffic,
// decoration: BoxDecoration(
// color: AppColor.secondaryColor,
// border: Border.all(),
// borderRadius: BorderRadius.circular(15)),
// child: IconButton(
// onPressed: () async {
// Get.to(SmsSignupEgypt());
// List<String> d = [
// "30.003028,31.2419628",
// "30.0955661,31.2665336",
// "160.00",
// "25.92",
// "1488",
// "16.93",
// "114243034311436865474",
// "113172279072358305645",
// "hamza ayed",
// "rlMbi4Hc8L1STMPE99iPKqK4Gddwv8r9qZOCadsz9qTEJZ6KLEE9ruTJI6N8dKfK4CXez5pme5WIs14-1QGo29s07fQOniZgIlJV5XFL3yqzPRSUmn3",
// "+201023248456",
// "1 min",
// "1 m",
// "false",
// "QwUMoyUtZ0J3oR6yXKUavrB_gBl9npUZe-qZtax-Raq4QBbdKv0AmtLKm0BfBd6N_592HBv4CVa41ii4122W3hr-BCUKKzJhzZcK8m0YjbWbtpvgJRD8uD_nuMk9",
// "0",
// "238",
// "false",
// "114243034311436865474",
// "1488",
// "startEnd",
// "30.049307749732176,31.274291574954987",
// "",
// "",
// "",
// "",
// "17.73",
// "0",
// "hamzaayedflutter@gmail.com",
// "الفسطاط، حي مصر القديمة، مصر",
// " الزاوية الحمراء، محافظة القاهرة، مصر",
// "Speed",
// "8",
// "5.00"
// ];
// FirebaseMessagesController()
// .sendNotificationToAnyWithoutData(
// 'Cancel'.tr,
// "How much longer will you be?".tr,
// 'fKBBB4_1R0q18-byySHUeG:APA91bHk2RmjjMt6eKr7KQnqh4CK02yW3H5E8g_beVcQFgiCG50j9KCtSU1O8PtvS_gA5xuJLhaorDV9AeslcyLFJFf302tICKMiKgsDP5pWkF5WXNw0-4NsoD-BnJxf0-Do9Vs1Zbpq',
// // d,
// 'ding.wav',
// );
// Get.to(SmsSignupEgypt());
// Log.print(
// 'getUpdatedRideForDriverApply: ${Get.find<MapPassengerController>().driverToken}');
// Get.find<MapPassengerController>()
// .firstTimeRunToGetCoupon('SEFER25', '1 WEEEK', '25%');
// },
// icon: const Icon(
// Icons.chat,
// size: 29,
// ),
// ),
// ),
// // AnimatedContainer(
// duration: const Duration(microseconds: 200),
// width: controller.widthMapTypeAndTraffic,
// decoration: BoxDecoration(
// color: AppColor.secondaryColor,
// border: Border.all(),
// borderRadius: BorderRadius.circular(15)),
// child: IconButton(
// onPressed: () async {
// await CRUD().allMethodForAI(
// 'name,fullName,address,idNumber,cardId,dob',
// AppLink.uploadEgypt,
// 'idFront');
//
// // await ImageController().choosImage(
// // 'https://api.sefer.live/sefer/uploadEgypt.php',
// // 'FrontId');
// AC credentials = AC();
// String apiKey = 'zjujl_qvo_fwjfgjlXrXlBl';
// String convertedStringN = credentials.c(
// credentials.c(credentials.c(apiKey, cs), cC), cn);
// String retrievedStringS = credentials.r(
// credentials.r(credentials.r(convertedStringN, cn), cC),
// cs);
// //
// if (retrievedStringS == apiKey) {
// print('convertedStringN --- $convertedStringN');
// print('retrievedStringS ---$retrievedStringS');
// print('same');
// }
//
// // await Get.find<PaymentController>()
// // .payWithPayMob(context, '1100', 'EGP');
// // Initiates a payment with a card using the FlutterPaymob instance
//
// },
// icon: const Icon(
// // Get.put(AudioRecorderController()).isRecording
// Icons.start,
// size: 29,
// ),
// ),
// ),
AnimatedContainer(
duration: const Duration(microseconds: 200),
width: controller.widthMapTypeAndTraffic,
decoration: BoxDecoration(
color: AppColor.secondaryColor,
border: Border.all(),
borderRadius: BorderRadius.circular(15)),
child: IconButton(
onPressed: () async {
Get.to(() => const VipWaittingPage());
},
icon: const Icon(
Icons.voice_chat,
size: 29,
),
),
),
],
);
})),

View File

@@ -8,6 +8,7 @@ import 'package:get/get.dart';
import '../../../constant/api_key.dart';
import '../../../constant/links.dart';
import '../../../print.dart';
class CupertinoDriverListWidget extends StatelessWidget {
MapPassengerController mapPassengerController =
@@ -16,170 +17,207 @@ class CupertinoDriverListWidget extends StatelessWidget {
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Driver List'.tr),
middle: Text('Driver List'.tr), // Ensure text is properly localized
),
child: SafeArea(
child: ListView.separated(
itemCount: mapPassengerController.driversForMishwari.length,
separatorBuilder: (context, index) => const Divider(height: 1),
itemBuilder: (context, index) {
var driver = mapPassengerController.driversForMishwari[index];
return Container(
decoration: AppStyle.boxDecoration1,
child: CupertinoListTile(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
leading: CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(
'${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
),
child: Builder(
builder: (context) {
return Image.network(
'${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
fit: BoxFit.cover,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) {
return child; // Image is loaded
} else {
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
(loadingProgress.expectedTotalBytes ?? 1)
: null,
),
);
}
},
errorBuilder: (BuildContext context, Object error,
StackTrace? stackTrace) {
return const Icon(
Icons.person, // Icon to show when image fails to load
size: 25, // Adjust the size as needed
color: AppColor.blueColor, // Color for the error icon
);
},
);
},
),
),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${driver['NAME'].toString().split(' ')[0]} ${driver['NAME'].toString().split(' ')[1]}',
style: const TextStyle(fontWeight: FontWeight.bold),
child: mapPassengerController.driversForMishwari.isEmpty
? Center(
child: Text(
'No drivers available at the moment. Please try again later.'
.tr,
style: const TextStyle(
fontSize: 18, // Adjust the size as needed
fontWeight: FontWeight.w600,
color: CupertinoColors.inactiveGray, // Customize color
),
textAlign: TextAlign.center, // Center-align the text
),
Text('${'Age'.tr}: ${driver['age'].toString()}'),
Row(
children: [
const Icon(CupertinoIcons.star_fill,
size: 16, color: CupertinoColors.systemYellow),
const SizedBox(width: 4),
Text(driver['rating']?.toStringAsFixed(1) ?? 'N/A'.tr),
const SizedBox(width: 8),
Text('${'Rides'.tr}: ${driver['countRide']}'),
],
),
],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
Text('${'Plate'.tr}: ${driver['car_plate']}'),
],
),
// Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Text('${'Education'.tr}: ${driver['education']}'),
// ],
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
// width: Get.width * .3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('${'Color'.tr}: ${driver['color']}'),
const SizedBox(width: 8),
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: driver['color_hex'].toString() == 'null'
? Colors.amber
: hexToColor(
driver['color_hex'].toString()),
borderRadius: BorderRadius.circular(4),
border: Border.all(),
),
),
],
)
: ListView.separated(
itemCount: mapPassengerController.driversForMishwari.length,
separatorBuilder: (context, index) =>
const Divider(height: 1),
itemBuilder: (context, index) {
var driver =
mapPassengerController.driversForMishwari[index];
return Container(
decoration: AppStyle.boxDecoration1,
child: CupertinoListTile(
padding: const EdgeInsets.symmetric(
vertical: 4, horizontal: 8),
leading: CircleAvatar(
radius: 25,
backgroundImage: NetworkImage(
'${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
),
child: Builder(
builder: (context) {
return Image.network(
'${AppLink.seferCairoServer}/portrate_captain_image/${driver['id']}.jpg',
fit: BoxFit.cover,
loadingBuilder: (BuildContext context,
Widget child,
ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) {
return child; // Image is loaded
} else {
return Center(
child: CircularProgressIndicator(
value: loadingProgress
.expectedTotalBytes !=
null
? loadingProgress
.cumulativeBytesLoaded /
(loadingProgress
.expectedTotalBytes ??
1)
: null,
),
);
}
},
errorBuilder: (BuildContext context,
Object error, StackTrace? stackTrace) {
return const Icon(
Icons
.person, // Icon to show when image fails to load
size: 25, // Adjust the size as needed
color: AppColor
.blueColor, // Color for the error icon
);
},
);
},
),
),
),
],
),
],
),
onTap: () {
// Handle driver selection
Get.defaultDialog(
title: '${'Selected driver'.tr}: ${driver['NAME']}',
content: Column(
children: [
Column(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
Text('${'Plate'.tr}: ${driver['car_plate']}'),
'${driver['NAME'].toString().split(' ')[0]} ${driver['NAME'].toString().split(' ')[1]}',
style:
const TextStyle(fontWeight: FontWeight.bold),
),
Text('${'Age'.tr}: ${driver['age'].toString()}'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('${'Color'.tr}: ${driver['color']}'),
const Icon(CupertinoIcons.star_fill,
size: 16,
color: CupertinoColors.systemYellow),
const SizedBox(width: 4),
Text(driver['rating']?.toStringAsFixed(1) ??
'N/A'.tr),
const SizedBox(width: 8),
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color:
driver['color_hex'].toString() == 'null'
? Colors.amber
: hexToColor(
driver['color_hex'].toString()),
borderRadius: BorderRadius.circular(4),
border: Border.all(),
Text('${'Rides'.tr}: ${driver['ride_count']}'),
],
),
],
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
Text('${'Plate'.tr}: ${driver['car_plate']}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
// width: Get.width * .3,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text('${'Color'.tr}: ${driver['color']}'),
const SizedBox(width: 8),
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: driver['color_hex']
.toString() ==
'null'
? Colors.amber
: hexToColor(driver['color_hex']
.toString()),
borderRadius:
BorderRadius.circular(4),
border: Border.all(),
),
),
],
),
),
],
),
],
),
],
),
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () {
Get.back();
showDateTimePickerDialog(driver);
}));
print('${'Selected driver'.tr}: ${driver['NAME']}');
// Get.back(); // Close the dialog
},
),
);
},
)),
onTap: () {
Log.print(' driver["id"]: ${driver['driver_id']}');
Get.find<MapPassengerController>().driverIdVip =
driver['driver_id'];
// Handle driver selection
Get.defaultDialog(
title:
'${'Selected driver'.tr}: ${driver['NAME']}',
content: Column(
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'${'Car'.tr}: ${driver['make']} ${driver['model']} (${driver['year']})'),
Text(
'${'Plate'.tr}: ${driver['car_plate']}'),
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Text(
'${'Color'.tr}: ${driver['color']}'),
const SizedBox(width: 8),
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: driver['color_hex']
.toString() ==
'null'
? Colors.amber
: hexToColor(
driver['color_hex']
.toString()),
borderRadius:
BorderRadius.circular(4),
border: Border.all(),
),
),
],
),
],
),
],
),
confirm: MyElevatedButton(
title: 'OK'.tr,
onPressed: () {
Get.back();
showDateTimePickerDialog(driver);
}));
print('${'Selected driver'.tr}: ${driver['NAME']}');
// Get.back(); // Close the dialog
},
),
);
},
)),
);
}
@@ -233,7 +271,7 @@ class CupertinoDriverListWidget extends StatelessWidget {
Get.defaultDialog(
barrierDismissible: false,
title: 'select date and time of trip'.tr,
title: "Select date and time of trip".tr,
content: SizedBox(
// height: 400, // Adjust height as needed
width: double.maxFinite,
@@ -253,6 +291,13 @@ class CupertinoDriverListWidget extends StatelessWidget {
await mapPassengerController.saveTripData(driver, selectedDateTime);
},
),
cancel: MyElevatedButton(
kolor: AppColor.redColor,
title: 'Cancel'.tr,
onPressed: () {
Get.back();
},
),
);
}
}
@@ -263,10 +308,10 @@ class DateTimePickerWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: const CupertinoNavigationBar(
navigationBar: CupertinoNavigationBar(
transitionBetweenRoutes: false,
automaticallyImplyLeading: false,
middle: Text('Date and Time Picker'),
middle: Text('Date and Time Picker'.tr),
),
child: SafeArea(
child: Column(

View File

@@ -2,10 +2,8 @@ import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:SEFER/constant/box_name.dart';
import 'package:SEFER/constant/colors.dart';
import 'package:SEFER/constant/style.dart';
import 'package:SEFER/controller/functions/toast.dart';
import 'package:SEFER/controller/payment/payment_controller.dart';
import 'package:SEFER/views/widgets/elevated_btn.dart';
import '../../../main.dart';
@@ -138,6 +136,8 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
child: Text('💰 Pay with Wallet'.tr),
onPressed: () {
if (controller.selectedAmount != 0) {
controller.isLoading = true;
controller.update();
controller.payWithPayMobWallet(
context,
controller.selectedAmount.toString(),
@@ -148,6 +148,8 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
await controller.getPassengerWallet();
},
);
controller.isLoading = false;
controller.update();
} else {
Toast.show(context, '⚠️ You need to choose an amount!'.tr,
AppColor.redColor);