25-6-23/1

This commit is contained in:
Hamza-Ayed
2025-06-23 02:24:42 +03:00
parent 5eba032887
commit 5050aab9b7
42 changed files with 2387 additions and 1783 deletions

View File

@@ -6,6 +6,10 @@ class BoxName {
static const String initializationVector = 'initializationVector';
static const String firstTimeLoadKey = 'firstTimeLoadKey';
static const String jwt = "jwt";
static const String rideId = "rideId";
static const String rideArgumentsFromBackground =
"rideArgumentsFromBackground";
static const String FCM_PRIVATE_KEY = "FCM_PRIVATE_KEY";
static const String hmac = "hmac";
static const String fingerPrint = "fingerPrint";
static const String payMobApikey = "payMobApikey";

View File

@@ -101,6 +101,10 @@ class AppLink {
static String getTripCountByCaptain = "$ride/rides/getTripCountByCaptain.php";
static String getRideOrderID = "$ride/rides/getRideOrderID.php";
static String getRideStatus = "$ride/rides/getRideStatus.php";
static String getOverLayStatus = "$ride/overLay/get.php";
static String getArgumentAfterAppliedFromBackground =
"$ride/overLay/getArgumentAfterAppliedFromBackground.php";
static String addOverLayStatus = "$ride/overLay/add.php";
static String getapiKey = "$ride/apiKey/get.php";
static String getapiKeySefer = "$ride/apiKey/get.php";
@@ -123,6 +127,12 @@ class AppLink {
////-----------------DriverPayment------------------
static String addDrivePayment = "$seferPaymentServer/ride/payment/add.php";
static String payWithPayMobCardDriver =
"$seferPaymentServer/ride/payMob/paymob_driver/payWithCard.php";
static String payWithWallet =
"$seferPaymentServer/ride/payMob/paymob_driver/payWithWallet.php";
static String paymetVerifyDriver =
"$seferPaymentServer/ride/payMob/paymob_driver/paymet_verfy.php";
static String updatePaymetToPaid =
"$seferPaymentServer/ride/payment/updatePaymetToPaid.php";

View File

@@ -188,16 +188,16 @@ Download the Tripz app now and enjoy your ride!
(driverInvitationData[index]['driverInviterId']),
('500'),
);
await Get.find<CaptainWalletController>()
.addSeferWallet('giftInvitation', ('-1000'));
// await Get.find<CaptainWalletController>()
// .addSeferWallet('giftInvitation', ('-1000'));
NotificationCaptainController().addNotificationCaptain(
driverInvitationData[index]['driverInviterId'].toString(),
"You have got a gift for invitation".tr,
'${"You have 500".tr} ${'LE'}',
'${"You have 500".tr} ${'LE'.tr}',
false);
NotificationController().showNotification(
"You have got a gift for invitation".tr,
'${"You have 500".tr} ${'LE'}',
'${"You have 500".tr} ${'LE'.tr}',
'tone1',
'');
} else {
@@ -264,6 +264,7 @@ Download the Tripz app now and enjoy your ride!
link: AppLink.updatePassengerGift,
payload: {'id': driverInvitationDataToPassengers[index]['id']},
);
// Notify the inviter
NotificationCaptainController().addNotificationCaptain(
driverInvitationDataToPassengers[index]['passengerInviterId']

View File

@@ -98,7 +98,7 @@ class LoginDriverController extends GetxController {
final random = Random();
if (random.nextBool()) {
// await SecurityHelper.performSecurityChecks();
await SecurityHelper.performSecurityChecks();
} else {
await SecurityChecks.isDeviceRootedFromNative(Get.context!);
}
@@ -145,20 +145,21 @@ class LoginDriverController extends GetxController {
);
if (response0.statusCode == 200) {
final decodedResponse1 = jsonDecode(response0.body);
// Log.print('decodedResponse1: ${decodedResponse1}');
Log.print('decodedResponse1: ${decodedResponse1}');
final jwt = decodedResponse1['jwt'];
box.write(BoxName.jwt, X.c(X.c(X.c(jwt, cn), cC), cs));
// await box.write(BoxName.hmac, decodedResponse1['hmac']);
await AppInitializer().getAIKey(Driver.keyOfApp);
await AppInitializer().getAIKey(Driver.initializationVector);
await Future.delayed(Duration.zero);
await EncryptionHelper.initialize();
await AppInitializer().getAIKey(Driver.payMobApikey);
await AppInitializer().getAIKey(Driver.FCM_PRIVATE_KEY);
await AppInitializer().getAIKey(Driver.initializationVector);
await AppInitializer().getAIKey(Driver.keyOfApp);
// ✅ بعد التأكد أن كل المفاتيح موجودة
await EncryptionHelper.initialize();
await AppInitializer().getKey();
} else {}
} else {

View File

@@ -44,7 +44,7 @@ class AccessTokenManager {
_accessToken = client.credentials.accessToken;
_expiryDate = client.credentials.accessToken.expiry;
client.close();
Log.print('_accessToken!.data: ${_accessToken!.data}');
// Log.print('_accessToken!.data: ${_accessToken!.data}');
return _accessToken!.data;
} catch (e) {
throw Exception('Failed to obtain access token');

View File

@@ -14,6 +14,7 @@ import '../../constant/box_name.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
import '../../main.dart';
import '../../print.dart';
import '../../views/auth/captin/criminal_documents_page.dart';
import '../../views/home/Captin/home_captain/home_captin.dart';
import '../../views/home/Captin/orderCaptin/order_speed_request.dart';
@@ -180,6 +181,7 @@ class FirebaseMessagesController extends GetxController {
'Trip Cancelled. The cost of the trip will be added to your wallet.'
.tr, () {
box.write(BoxName.rideStatus, 'Cancel');
Log.print('rideStatus from 184 : ${box.read(BoxName.rideStatus)}');
Get.offAll(HomeCaptain());
});
// cancelTripDialog1();
@@ -341,6 +343,8 @@ class FirebaseMessagesController extends GetxController {
title: 'Ok'.tr,
onPressed: () {
box.write(BoxName.rideStatus, 'Cancel');
Log.print(
'rideStatus from 347 : ${box.read(BoxName.rideStatus)}');
Get.offAll(HomeCaptain());
}));
}
@@ -356,6 +360,8 @@ class FirebaseMessagesController extends GetxController {
title: 'Ok'.tr,
onPressed: () {
box.write(BoxName.rideStatus, 'Cancel');
Log.print(
'rideStatus from 364 : ${box.read(BoxName.rideStatus)}');
Get.offAll(HomeCaptain());
}));
}
@@ -405,7 +411,7 @@ class FirebaseMessagesController extends GetxController {
Future<void> onInit() async {
super.onInit();
try {
var encryptedKey = await storage.read(key: 'FCM_PRIVATE_KEY');
var encryptedKey = await storage.read(key: BoxName.FCM_PRIVATE_KEY);
// Log.print('encryptedKey: ${encryptedKey}');
if (encryptedKey != null) {
serviceAccountKeyJson =
@@ -707,33 +713,40 @@ class FirebaseMessagesController extends GetxController {
if (response.statusCode == 200) {
print(
'Notification sent successfully. Status code: ${response.statusCode}');
print('Response body: ${response.body}');
} else if (response.statusCode == 404) {
// Handle UNREGISTERED token
final responseBody = jsonDecode(response.body);
final errorCode = responseBody['error']['details']?[0]?['errorCode'];
if (errorCode == 'UNREGISTERED') {
print('Token is unregistered/invalid: $token');
// Remove token from your database
await removeInvalidToken(token);
return; // Don't retry for invalid tokens
}
} else {
print(
'Failed to send notification. Status code: ${response.statusCode}');
print('Response body: ${response.body}');
if (retryCount > 0) {
print('Retrying... Attempts remaining: $retryCount');
await Future.delayed(
const Duration(seconds: 2)); // Optional delay before retrying
return sendNotificationToPassengerTokenCALL(
title, body, token, data, tone,
await Future.delayed(const Duration(seconds: 2));
return sendNotificationToDriverMAP(title, body, token, data, tone,
retryCount: retryCount - 1);
}
}
} catch (e) {
print('Error sending notification: $e');
if (retryCount > 0) {
print('Retrying... Attempts remaining: $retryCount');
await Future.delayed(
const Duration(seconds: 2)); // Optional delay before retrying
return sendNotificationToPassengerTokenCALL(
title, body, token, data, tone,
retryCount: retryCount - 1);
}
// ... existing error handling ...
}
}
Future<void> removeInvalidToken(String token) async {
// Remove token from your database/storage
// This prevents future attempts to send to invalid tokens
print('Removing invalid token from database: $token');
// Your database cleanup logic here
}
}
class OverlayContent extends StatelessWidget {

View File

@@ -522,7 +522,7 @@ class NotificationController extends GetxController {
if (data is String) {
var orderData = jsonDecode(data);
if (orderData is List && orderData.length == 34) {
closeOverLay();
//closeOverLay();
Get.put(HomeCaptainController()).changeRideId();
Get.to(() => OrderRequestPage(), arguments: {'myListString': data});
} else {
@@ -537,7 +537,7 @@ class NotificationController extends GetxController {
if (data is String) {
var orderData = jsonDecode(data);
if (orderData is List && orderData.length == 34) {
closeOverLay();
//closeOverLay();
Get.put(HomeCaptainController()).changeRideId();
Get.to(() => OrderRequestPage(), arguments: {'myListString': data});
} else {
@@ -550,7 +550,7 @@ class NotificationController extends GetxController {
void _handleADSNotification() {
// var orderData = jsonDecode(data);
closeOverLay();
//closeOverLay();
Get.to(
() => const NotificationCaptain(),
);

View File

@@ -94,9 +94,9 @@ class CRUD {
'X-HMAC-Auth': hmac.toString(),
},
);
Log.print('response.request: ${response.request}');
Log.print('response.body: ${response.body}');
print(payload);
// Log.print('response.request: ${response.request}');
// Log.print('response.body: ${response.body}');
// print(payload);
if (response.statusCode == 200) {
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
@@ -128,11 +128,13 @@ class CRUD {
Future<dynamic> postWallet(
{required String link, Map<String, dynamic>? payload}) async {
var s = await LoginDriverController().getJwtWallet();
// Log.print('jwt: ${s}');
final hmac = box.read(BoxName.hmac);
Log.print('hmac: ${hmac}');
// Log.print('hmac: ${hmac}');
var url = Uri.parse(link);
// Log.print('url: ${url}');
try {
await LoginDriverController().getJWT();
// await LoginDriverController().getJWT();
var response = await http.post(
url,
@@ -143,9 +145,9 @@ class CRUD {
'X-HMAC-Auth': hmac.toString(),
},
);
print(response.request);
Log.print('response.body: ${response.body}');
print(payload);
// Log.print('response.request:${response.request}');
// Log.print('response.body: ${response.body}');
// Log.print('payload:$payload');
if (response.statusCode == 200) {
try {
var jsonData = jsonDecode(response.body);
@@ -201,9 +203,9 @@ class CRUD {
// 'Authorization': 'Bearer ${box.read(BoxName.jwt)}'
},
);
print(response.request);
Log.print('response.body: ${response.body}');
print(payload);
// print(response.request);
// Log.print('response.body: ${response.body}');
// print(payload);
if (response.statusCode == 200) {
try {
var jsonData = jsonDecode(response.body);
@@ -439,22 +441,46 @@ class CRUD {
}
}
sendEmail(
String link,
Map<String, String>? payload,
) async {
var headers = {
Future<void> sendEmail(String link, Map<String, String>? payload) async {
// التحقق من صلاحية التوكن
String rawJwt = box.read(BoxName.jwt);
String token = X
.r(X.r(X.r(rawJwt, cn), cC), cs)
.toString()
.split(AppInformation.addd)[0];
bool isTokenExpired = JwtDecoder.isExpired(token);
if (isTokenExpired) {
await LoginDriverController().getJWT();
rawJwt = box.read(BoxName.jwt); // تحديث التوكن بعد التجديد
token = X
.r(X.r(X.r(rawJwt, cn), cC), cs)
.toString()
.split(AppInformation.addd)[0];
}
// إعداد الهيدر
final headers = {
"Content-Type": "application/x-www-form-urlencoded",
'Authorization':
'Basic ${base64Encode(utf8.encode(AK.basicAuthCredentials))}',
"Authorization": "Bearer $token",
};
var request = http.Request('POST', Uri.parse(link));
request.bodyFields = payload!;
// إعداد الطلب
final request = http.Request('POST', Uri.parse(link));
request.bodyFields = payload ?? {};
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
// إرسال الطلب
final response = await request.send();
// التحقق من النتيجة
if (response.statusCode == 200) {
} else {}
print("✅ Email sent successfully.");
} else {
print("❌ Failed to send email. Status: ${response.statusCode}");
final responseBody = await response.stream.bytesToString();
print("Response body: $responseBody");
}
}
Future<dynamic> postFromDialogue({

View File

@@ -105,7 +105,7 @@ class AI extends GetxController {
NotificationController().showNotification(
"Code approved".tr, "Code approved".tr, 'tone2', '');
// Notification text with dynamic token
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.put(FirebaseMessagesController()).sendNotificationToDriverMAP(
'You have received a gift token!'.tr,
'for '.tr + box.read(BoxName.phoneDriver).toString(),
jsonDecode(res)['message'][0]['token'].toString(),

View File

@@ -133,8 +133,8 @@ class LocationController extends GetxController {
// ✅ إدخال للسيرفر كل دقيقة
_insertCounter++;
Log.print('_insertCounter: ${_insertCounter}');
if (_insertCounter >= 12) {
// Log.print('_insertCounter: ${_insertCounter}');
if (_insertCounter == 12) {
_insertCounter = 0;
await CRUD().post(
link: box.read(BoxName.serverChosen) + '/ride/location/add.php',

View File

@@ -247,15 +247,15 @@ class SecurityHelper {
await box.write('isTampered', isTampered); // Use await
await box.write('isJailBroken', isJailBroken); // Use await
debugPrint("Security Check Results:");
debugPrint("isNotTrust: $isNotTrust");
debugPrint("isJailBroken: $isJailBroken");
debugPrint("isRealDevice: $isRealDevice");
debugPrint("isOnExternalStorage: $isOnExternalStorage");
debugPrint("checkForIssues: $checkForIssues");
debugPrint("isDevMode: $isDevMode");
debugPrint("isTampered: $isTampered");
debugPrint("Bundle ID: $bundleId"); // Print the bundle ID
// debugPrint("Security Check Results:");
// debugPrint("isNotTrust: $isNotTrust");
// debugPrint("isJailBroken: $isJailBroken");
// debugPrint("isRealDevice: $isRealDevice");
// debugPrint("isOnExternalStorage: $isOnExternalStorage");
// debugPrint("checkForIssues: $checkForIssues");
// debugPrint("isDevMode: $isDevMode");
// debugPrint("isTampered: $isTampered");
// debugPrint("Bundle ID: $bundleId"); // Print the bundle ID
// Check for security risks and potentially show a warning
if (isJailBroken || isRealDevice == false || isTampered) {

View File

@@ -40,7 +40,6 @@ class AppInitializer {
Future<void> initializeApp() async {
if (box.read(BoxName.jwt) == null) {
Log.print('box.read(BoxName.jwt): ${box.read(BoxName.jwt)}');
await LoginDriverController().getJWT();
} else {
bool isTokenExpired = JwtDecoder.isExpired(X
@@ -55,15 +54,18 @@ class AppInitializer {
// await getKey();
}
getAIKey(String key1) async {
if (box.read(BoxName.firstTimeLoadKey) == null) {
var res =
await CRUD().get(link: AppLink.getapiKey, payload: {"keyName": key1});
if (res != 'failure') {
var d = jsonDecode(res)['message'];
await storage.write(key: key1, value: d[key1].toString());
await Future.delayed(Duration.zero);
} else {}
Future<void> getAIKey(String key1) async {
var res =
await CRUD().get(link: AppLink.getapiKey, payload: {"keyName": key1});
if (res != 'failure') {
var d = jsonDecode(res)['message'];
final rawValue = d[key1].toString();
// ✅ اكتبها في storage
await storage.write(key: key1, value: rawValue);
await Future.delayed(Duration.zero);
}
}

View File

@@ -12,8 +12,10 @@ import '../../../constant/links.dart';
import '../../../constant/style.dart';
import '../../../constant/table_names.dart';
import '../../../main.dart';
import '../../../print.dart';
import '../../../views/home/my_wallet/walet_captain.dart';
import '../../../views/widgets/elevated_btn.dart';
import '../../firebase/firbase_messge.dart';
import '../../functions/crud.dart';
import '../../functions/location_background_controller.dart';
import '../../functions/location_controller.dart';
@@ -264,7 +266,7 @@ class HomeCaptainController extends GetxController {
@override
void onInit() async {
// await locationBackController.requestLocationPermission();
Get.put(FirebaseMessagesController());
addToken();
await getlocation();
onButtonSelected();
@@ -429,6 +431,7 @@ class HomeCaptainController extends GetxController {
void changeToAppliedRide(String status) {
box.write(BoxName.rideStatus, status);
Log.print('rideStatus from homcaptain : ${box.read(BoxName.rideStatus)}');
update();
}

View File

@@ -25,6 +25,7 @@ import '../../firebase/firbase_messge.dart';
import '../../functions/crud.dart';
import '../../functions/encrypt_decrypt.dart';
import '../../functions/location_controller.dart';
import '../../functions/tts.dart';
class MapDriverController extends GetxController {
bool isLoading = true;
@@ -174,7 +175,7 @@ class MapDriverController extends GetxController {
cancelTripFromDriverAfterApplied() async {
if (formKeyCancel.currentState!.validate()) {
box.write(BoxName.statusDriverLocation, 'off');
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
"Cancel Trip from driver",
"Trip Cancelled from driver. We are looking for a new driver. Please wait."
.tr,
@@ -235,6 +236,8 @@ class MapDriverController extends GetxController {
'created_at': DateTime.now().toString(),
'driver_id': box.read(BoxName.driverID).toString(),
}, TableName.driverOrdersRefuse);
box.write(BoxName.rideStatus, 'Cancel');
Log.print('rideStatus from map 240 : ${box.read(BoxName.rideStatus)}');
Get.find<HomeCaptainController>().getRefusedOrderByCaptain();
Get.offAll(() => HomeCaptain());
}
@@ -242,6 +245,7 @@ class MapDriverController extends GetxController {
void startTimerToShowPassengerInfoWindowFromDriver() async {
if (box.read(BoxName.rideStatus) == 'Begin') {
Log.print('rideStatus from map 248 : ${box.read(BoxName.rideStatus)}');
isPassengerInfoWindow = false;
} else {
isPassengerInfoWindow = true;
@@ -298,6 +302,7 @@ class MapDriverController extends GetxController {
void driverGoToPassenger() async {
changeRideToBeginToPassenger();
box.write(BoxName.rideStatus, 'Applied');
Log.print('rideStatus from map 304 : ${box.read(BoxName.rideStatus)}');
update();
await CRUD().post(
link: "${AppLink.seferCairoServer}/ride/rides/update.php",
@@ -315,7 +320,7 @@ class MapDriverController extends GetxController {
}
// Get.find<HomeCaptainController>().changeToAppliedRide('Applied');
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'Driver Is Going To Passenger'.tr,
box.read(BoxName.nameDriver).toString(), //todo name driver
tokenPassenger,
@@ -392,6 +397,7 @@ class MapDriverController extends GetxController {
// todo ride details
// Get.find<HomeCaptainController>().changeToAppliedRide('Begin');
box.write(BoxName.rideStatus, 'Begin');
Log.print('rideStatus from map 399 : ${box.read(BoxName.rideStatus)}');
// Get.find<HomeCaptainController>().update();
update();
await CRUD().post(link: AppLink.updateRides, payload: {
@@ -418,7 +424,7 @@ class MapDriverController extends GetxController {
'status': 'Begin'
});
}
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'Trip is Begin'.tr,
box.read(BoxName.nameDriver).toString(),
tokenPassenger,
@@ -584,17 +590,29 @@ class MapDriverController extends GetxController {
}
}
void finishRideFromDriver() {
Future<void> finishRideFromDriver() async {
double distanceToDestination = Geolocator.distanceBetween(
latLngPassengerLocation.latitude,
latLngPassengerLocation.longitude,
latLngPassengerDestination.latitude,
latLngPassengerDestination.longitude,
Get.find<LocationController>().myLocation.latitude,
Get.find<LocationController>().myLocation.longitude,
);
final originalDistanceM = double.parse(distance.toString()) * 1000;
if (distanceToDestination > (double.parse(distance.toString()) / 3)) {
Log.print('distanceToDestination: ${distanceToDestination}');
// 2. احسب المسافة التي قطعها السائق حتى الآن
final movedDistanceM = originalDistanceM - distanceToDestination;
// 3. عتبة ثلث المسافة
final oneThirdDistanceM = originalDistanceM / 3;
// Logging للتتبع
Log.print('originalDistanceM: $originalDistanceM');
Log.print('distanceToDestinationM: $distanceToDestination');
Log.print('movedDistanceM: $movedDistanceM');
Log.print('oneThirdDistanceM: $oneThirdDistanceM');
// 4. إذا لم يقطع السائق ثلث المسافة، نعرض التأكيد
if (movedDistanceM < oneThirdDistanceM) {
MyDialog().getDialog(
'Are you sure to exit ride?'.tr,
'',
@@ -603,33 +621,39 @@ class MapDriverController extends GetxController {
finishRideFromDriver1();
},
);
} else {
} /////
else {
final textToSpeechController = Get.put(TextToSpeechController());
MyDialog().getDialog(
"You haven't moved sufficiently!".tr,
'',
() => Get.back(),
);
await textToSpeechController
.speakText("You haven't moved sufficiently!".tr);
}
}
String paymentToken = '';
Future<String> generateTokenDriver(String amount) async {
var res = await CRUD().post(link: AppLink.addPaymentTokenDriver, payload: {
var res =
await CRUD().postWallet(link: AppLink.addPaymentTokenDriver, payload: {
'driverID': box.read(BoxName.driverID).toString(),
'amount': amount.toString(),
});
var d = jsonDecode(res);
var d = (res);
return d['message'];
}
String paymentTokenPassenger = '';
Future<String> generateTokenPassenger(String amount) async {
var res =
await CRUD().post(link: AppLink.addPaymentTokenPassenger, payload: {
var res = await CRUD()
.postWallet(link: AppLink.addPaymentTokenPassenger, payload: {
'passengerId': passengerId,
'amount': amount.toString(),
});
var d = jsonDecode(res);
var d = (res);
return d['message'];
}
@@ -638,6 +662,7 @@ class MapDriverController extends GetxController {
isRideStarted = false;
isPriceWindow = false;
box.write(BoxName.rideStatus, 'Finished');
Log.print('rideStatus from map 664 : ${box.read(BoxName.rideStatus)}');
// Calculate totalCost more concisely
if (price < 20) {
@@ -699,7 +724,8 @@ class MapDriverController extends GetxController {
if (walletChecked == 'true') {
paymentToken = await generateTokenPassenger(
((-1) * double.parse(paymentAmount)).toString());
futures.add(CRUD().post(link: AppLink.addPassengersWallet, payload: {
futures
.add(CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
'passenger_id': (passengerId),
'balance': ((-1) * double.parse(paymentAmount)).toString(),
'token': paymentToken,
@@ -707,7 +733,7 @@ class MapDriverController extends GetxController {
}
paymentToken = await generateTokenDriver(paymentAmount.toString());
futures.add(CRUD().post(link: AppLink.addDrivePayment, payload: {
futures.add(CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'rideId': (rideId),
'amount': paymentAmount,
'payment_method':
@@ -720,7 +746,8 @@ class MapDriverController extends GetxController {
if (double.parse(passengerWalletBurc) < 0) {
final paymentToken1 = await generateTokenPassenger(
((-1) * double.parse(passengerWalletBurc)).toString());
futures.add(CRUD().post(link: AppLink.addPassengersWallet, payload: {
futures
.add(CRUD().postWallet(link: AppLink.addPassengersWallet, payload: {
'passenger_id': (passengerId),
'token': paymentToken1,
'balance': ((-1) * double.parse(passengerWalletBurc)).toString()
@@ -730,7 +757,8 @@ class MapDriverController extends GetxController {
double pointsSubtraction = double.parse(paymentAmount) * (-1) * 0.08;
final paymentToken2 =
await generateTokenDriver((pointsSubtraction).toStringAsFixed(0));
futures.add(CRUD().post(link: AppLink.addDriversWalletPoints, payload: {
futures
.add(CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
'paymentID': 'rideId${(rideId)}',
'amount': (pointsSubtraction).toStringAsFixed(0),
'paymentMethod': paymentMethod,
@@ -743,7 +771,7 @@ class MapDriverController extends GetxController {
Get.put(DriverBehaviorController()).sendSummaryToServer(driverId, rideId);
// Send notification (this likely depends on previous steps)
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
"Driver Finish Trip".tr,
'${'you will pay to Driver'.tr} $paymentAmount \$',
tokenPassenger,
@@ -862,7 +890,7 @@ class MapDriverController extends GetxController {
// 'driverID': box.read(BoxName.driverID).toString(),
// });
// Future.delayed(const Duration(milliseconds: 300));
// FirebaseMessagesController().sendNotificationToDriverMAP(
// Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
// "Driver Finish Trip".tr,
// '${'you will pay to Driver'.tr} $paymentAmount \$',
// tokenPassenger,
@@ -1362,7 +1390,8 @@ class MapDriverController extends GetxController {
void onInit() async {
mapAPIKEY = await storage.read(key: BoxName.mapAPIKEY);
// Get the passenger location from the arguments.
// await argumentLoading();
await argumentLoading();
Get.put(FirebaseMessagesController());
runGoogleMapDirectly();
addCustomCarIcon();
addCustomPassengerIcon();

View File

@@ -82,7 +82,7 @@ class CaptainWalletController extends GetxController {
//get new driver details
isNewTransfer = true;
update();
var res = await CRUD().getWallet(
var res = await CRUD().get(
link: AppLink.getDriverDetails,
payload: {'driver_phone': '+2${newDriverPhoneController.text}'});
isNewTransfer = false;
@@ -155,7 +155,7 @@ class CaptainWalletController extends GetxController {
'driverID': box.read(BoxName.driverID).toString(),
'amount': amount.toString(),
});
var d = jsonDecode(res);
var d = (res);
return d['message'];
}
@@ -168,14 +168,14 @@ class CaptainWalletController extends GetxController {
'amount': amount.toString(),
'payment_method': paymentMethod.toString(),
});
var d = jsonDecode(res);
var d = (res);
// paymentID = d['message'].toString();
return d['message'];
}
Future addDriverWallet(String paymentMethod, point, count) async {
paymentToken = await generateToken(count);
var paymentID = await getPaymentId(paymentMethod, point);
var paymentID = await getPaymentId(paymentMethod, point.toString());
await CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
'driverID': box.read(BoxName.driverID).toString(),
'paymentID': paymentID.toString(),
@@ -245,7 +245,8 @@ class CaptainWalletController extends GetxController {
'payment_method': paymentMethod.toString(),
'passengerID': paymentMethod,
});
await addSeferWallet(paymentMethod, (double.parse(point) * -1).toString());
await addSeferWallet(paymentMethod,
(double.parse(point) * -2).toString()); // deduct 2 from sefer wallet
}
Future addSeferWallet(String paymentMethod, String point) async {
@@ -290,7 +291,7 @@ class CaptainWalletController extends GetxController {
'paymentMethod': paymentMethod2.toString(),
});
if (res1 != 'failure') {
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'Transfer',
'${'You have transfer to your wallet from'.tr}'
'${box.read(BoxName.nameDriver)}',

View File

@@ -1,15 +1,12 @@
import 'dart:convert';
import 'package:local_auth/local_auth.dart';
import 'package:sefer_driver/constant/api_key.dart';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/main.dart';
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:secure_string_operations/secure_string_operations.dart';
import '../../../constant/char_map.dart';
import '../../../constant/links.dart';
import '../../../views/widgets/mydialoug.dart';
import '../../functions/crud.dart';
@@ -19,39 +16,8 @@ class PaymobPayout extends GetxController {
bool isLoading = false;
String dropdownValue = 'etisalat';
Future<String> getToken() async {
var headers = {
'Content-Type': 'application/x-www-form-urlencoded',
// 'Cookie':
// 'csrftoken=74iZJ8XYyuTm5WRq2W4tpWX5eqoJLZVK5QhuDrChWpDtzpgGA269bbCWuEcW85t4'
};
var payMobOutClientSecrret =
X.r(X.r(X.r(await getAIKey(KN.pmobsec), cn), cC), cs);
var payMobOutClientId =
X.r(X.r(X.r(await getAIKey(KN.pmobid), cn), cC), cs);
var body = {
'grant_type': 'password',
'username': AK.payMobOutUserName,
'password': AK.payMobOutPassword,
'client_id': payMobOutClientId,
'client_secret': payMobOutClientSecrret
};
var res = await http.post(
Uri.parse('https://payouts.paymobsolutions.com/api/secure/o/token/'),
headers: headers,
body: body,
);
String token = '';
if (res.statusCode == 200) {
var decode = jsonDecode(res.body);
token = decode['access_token'];
}
return token;
}
int payOutFee = 5;
payToDriverWallet(
String token, String amount, String issuer, String msisdn) async {
payToDriverWallet(String amount, String issuer, String msisdn) async {
bool isAvailable = await LocalAuthentication().isDeviceSupported();
if (isAvailable) {
// Authenticate the user
@@ -62,21 +28,18 @@ class PaymobPayout extends GetxController {
sensitiveTransaction: true,
));
if (didAuthenticate) {
var headers = {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
};
var body = json.encode({
"amount": amount, //"10.00",
"issuer": issuer, //"vodafone",
"msisdn": msisdn, // "01023456789"
});
var res = await http.post(
Uri.parse('https://payouts.paymobsolutions.com/api/secure/disburse/'),
headers: headers,
body: body,
);
var dec = jsonDecode(res.body);
var dec = await CRUD().postWallet(
link:
'wl.tripz-egypt.com/v1/main/ride/payMob/paymob_driver/paymob_payout.php',
payload: {
"issuer": issuer,
"method": "wallet",
"amount": amount, //9.0,
"full_name":
'${box.read(BoxName.nameDriver)} ${box.read(BoxName.lastNameDriver)}',
"msisdn": msisdn, //"01010101010",
"bank_transaction_type": "cash_transfer"
});
if (dec['disbursement_status'] == 'successful') {
var paymentToken = await Get.find<CaptainWalletController>()
.generateToken(
@@ -149,8 +112,8 @@ class PaymobPayout extends GetxController {
} else {}
}
payToDriverBankAccount(String token, String amount, String bankCardNumber,
String bankCode) async {
payToDriverBankAccount(
String amount, String bankCardNumber, String bankCode) async {
bool isAvailable = await LocalAuthentication().isDeviceSupported();
if (isAvailable) {
// Authenticate the user
@@ -161,12 +124,9 @@ class PaymobPayout extends GetxController {
sensitiveTransaction: true,
));
if (didAuthenticate) {
var headers = {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
};
var body = {
"issuer": "bank_card",
"method": "bank_card",
"amount": amount, //9.0,
"full_name":
'${box.read(BoxName.nameDriver)} ${box.read(BoxName.lastNameDriver)}',
@@ -174,12 +134,11 @@ class PaymobPayout extends GetxController {
"bank_code": bankCode, //"CIB",
"bank_transaction_type": "cash_transfer"
};
var res = await http.post(
Uri.parse('https://payouts.paymobsolutions.com/api/secure/disburse/'),
headers: headers,
body: body,
var dec = await CRUD().postWallet(
link:
'wl.tripz-egypt.com/v1/main/ride/payMob/paymob_driver/paymob_payout.php',
payload: body,
);
var dec = jsonDecode(res.body);
if (dec['disbursement_status'] == 'successful') {
var paymentToken = await Get.find<CaptainWalletController>()
.generateToken(
@@ -236,8 +195,7 @@ class PaymobPayout extends GetxController {
sensitiveTransaction: true,
));
if (didAuthenticate) {
String token = await getToken();
await payToDriverWallet(token, amount, issuer, msisdn);
await payToDriverWallet(amount, issuer, msisdn);
} else {
MyDialog().getDialog('Authentication failed'.tr, ''.tr, () {
Get.back();
@@ -263,8 +221,7 @@ class PaymobPayout extends GetxController {
sensitiveTransaction: true,
));
if (didAuthenticate) {
String token = await getToken();
await payToDriverBankAccount(token, amount, bankCardNumber, bankCode);
await payToDriverBankAccount(amount, bankCardNumber, bankCode);
} else {
MyDialog().getDialog('Authentication failed'.tr, ''.tr, () {
Get.back();

View File

@@ -65,6 +65,17 @@ class MyTranslation extends Translations {
"Order Applied": "تم تطبيق الطلب",
//firebase above
"payment_success": "تمت العملية بنجاح",
"transaction_id": "رقم العملية",
"amount_paid": "المبلغ المدفوع",
"bonus_added": "البونص المضاف",
"points": "نقطة",
"transaction_failed": "فشل العملية",
"connection_failed": "فشل الاتصال",
"server_error": "خطأ في الخادم",
"server_error_message": "حدث خطأ أثناء الاتصال بالخادم",
"cancel": "إلغاء", "Syria": "‏سوريا",
"Security Warning": "تحذير أمني",
"Potential security risks detected. The application will close in @seconds seconds.":
@@ -75,7 +86,28 @@ class MyTranslation extends Translations {
"Security Warning": "⚠️ تحذير أمني",
"Potential security risks detected. The application may not function correctly.":
"تم اكتشاف ثغرات أمنية على هذا الجهاز. للحفاظ على أمان بياناتك، سيتم حذف جميع البيانات وإغلاق التطبيق.",
"How to use Tripz": "كيفية استخدام Tripz",
"What are the order details we provide to you?":
"ما هي تفاصيل الطلب التي نوفرها لك؟",
"Tripz Wallet Features:\n\nTransfer money multiple times.\nTransfer to anyone.\nMake purchases.\nCharge your account.\nCharge a friend's Tripz account.\nStore your money with us and receive it in your bank as a monthly salary.":
"ميزات محفظة Tripz:\n\nتحويل الأموال عدة مرات.\nالتحويل إلى أي شخص.\nإجراء عمليات شراء.\nشحن حسابك.\nشحن حساب Tripz لصديق.\nقم بتخزين أموالك معنا واستلامها في بنكك كراتب شهري.",
"What is the feature of our wallet?": "ما هي مميزات محفظتنا؟",
"What is Types of Trips in Tripz?": "ما هي أنواع الرحلات في Tripz؟",
'''Types of Trips in Tripz:
Comfort: For cars newer than 2017 with air conditioning.
Lady: For girl drivers.
Speed: For fixed salary and endpoints.
Mashwari: For flexible trips where passengers choose the car and driver with prior arrangements.
Raih Gai: For same-day return trips longer than 50km.
''': """أنواع الرحلات في Tripz:
راحة: للسيارات الأحدث من 2017 مع تكييف الهواء.
للسائقات الإناث.
سبيد: براتب ثابت ونقاط نهاية محددة.
مشاوير: للرحلات المرنة حيث يختار الركاب السيارة والسائق باتفاق مسبق.
رحّي غاي: للرحلات ذات العودة في نفس اليوم التي تزيد عن 50 كم.
""",
"I will go now": "هروح دلوقتي",
"Yes": "أيوة",
"No,I want": "لا، أنا عاوز",

View File

@@ -67,7 +67,7 @@ class RateController extends GetxController {
'driverID': box.read(BoxName.driverID).toString(),
});
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'Wallet Added'.tr,
'Wallet Added${(remainingFee).toStringAsFixed(0)}'.tr,
Get.find<MapDriverController>().tokenPassenger,

View File

@@ -1,9 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/controller/payment/paymob/paymob_response.dart';
import 'package:sefer_driver/views/home/Captin/orderCaptin/order_request_page.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
@@ -15,103 +12,102 @@ import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
import 'constant/api_key.dart';
import 'constant/info.dart';
import 'constant/notification.dart';
import 'controller/firebase/firbase_messge.dart';
import 'controller/firebase/local_notification.dart';
import 'controller/functions/encrypt_decrypt.dart';
import 'controller/functions/location_controller.dart';
import 'controller/functions/secure_storage.dart';
import 'controller/local/local_controller.dart';
import 'controller/local/translations.dart';
import 'controller/payment/paymob/paymob_wallet.dart';
import 'firebase_options.dart';
import 'models/db_sql.dart';
import 'print.dart';
import 'splash_screen_page.dart';
import 'views/home/Captin/driver_map_page.dart';
import 'views/home/Captin/orderCaptin/order_over_lay.dart';
//--- Global Variables ---
final box = GetStorage();
const storage = FlutterSecureStorage();
final PaymobPayment paymobPayment = PaymobPayment();
final PaymobPaymentWallet paymobPaymentWallet = PaymobPaymentWallet();
DbSql sql = DbSql.instance;
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
const platform = MethodChannel('com.sefer_driver/app_control');
//--- Entry Points for Background/Terminated States ---
@pragma('vm:entry-point')
Future<void> backgroundMessageHandler(RemoteMessage message) async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await GetStorage.init();
if (!await FlutterOverlayWindow.isPermissionGranted()) {
// بإمكانك تجاهل الطلب في الخلفية والاكتفاء بالتنبيه
Log.print("Overlay permission not granted; showing only notification.");
}
if (Platform.isAndroid) {
if (message.notification != null && message.notification!.title != null) {
Log.print('message.notification!.title: ${message.notification!.title}');
if (message.notification?.title == 'طلب' ||
if (message.notification?.title == 'Order' ||
message.notification?.title == 'OrderSpeed') {
var myListString = message.data['DriverList'] ?? '[]';
Log.print('myListString: $myListString');
// Decode the JSON string to a list
List<dynamic> myList;
try {
myList = jsonDecode(myListString) as List<dynamic>;
Log.print('myList: ${myList}');
} catch (e) {
Log.print('Error decoding JSON: $e');
myList = [];
}
await Future.delayed(const Duration(seconds: 1));
bool isOverlayActive = await FlutterOverlayWindow.isActive();
if (isOverlayActive) {
await FlutterOverlayWindow.closeOverlay();
await FlutterOverlayWindow.shareData(myList);
} else {
await FlutterOverlayWindow.showOverlay(
enableDrag: true,
flag: OverlayFlag.focusPointer,
positionGravity: PositionGravity.auto,
height: 1400,
width: WindowSize.matchParent,
startPosition: const OverlayPosition(0, -30),
);
await FlutterOverlayWindow.shareData(myList);
}
await FlutterOverlayWindow.shareData(myList);
await FlutterOverlayWindow.showOverlay(
enableDrag: true,
flag: OverlayFlag.focusPointer,
// visibility: NotificationVisibility.visibilityPublic,
positionGravity: PositionGravity.auto,
height: 1300,
width: WindowSize.matchParent,
startPosition: const OverlayPosition(0, -40),
);
// It's better to manage notifications in one place if possible
// but this is fine if it works for you.
NotificationController().showNotification(
message.notification!.title.toString(),
message.notification!.body.toString(),
'order',
myListString,
);
await FlutterOverlayWindow.shareData(myList);
} else {
// Handle other types of notifications
FirebaseMessagesController().fireBaseTitles(message);
}
} else {
FirebaseMessagesController().fireBaseTitles(message);
}
}
}
@pragma('vm:entry-point')
void notificationTapBackground(NotificationResponse notificationResponse) {
// handle background notification taps here
print('Notification tapped in background!');
Log.print('Notification tapped in background!');
NotificationController().handleNotificationResponse(notificationResponse);
// You can add your logic here to handle the notification tap
}
@pragma('vm:entry-point')
void overlayMain() async {
WidgetsFlutterBinding.ensureInitialized();
await GetStorage.init();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(const MaterialApp(
debugShowCheckedModeBanner: false,
home: OrderOverlay(),
@@ -119,12 +115,12 @@ void overlayMain() async {
}
Future<void> closeOverLay() async {
// FlutterOverlayWindow.closeOverlay();
bool isOverlayActive = await FlutterOverlayWindow.isActive();
if (isOverlayActive) {
await FlutterOverlayWindow.closeOverlay();
}
}
//--- Main Application ---
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -136,21 +132,29 @@ void main() async {
DeviceOrientation.portraitDown,
]);
runApp(MyApp());
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
_initApp();
}
@override
void dispose() {
super.dispose();
}
Future<void> _initApp() async {
try {
await Firebase.initializeApp(
@@ -159,62 +163,23 @@ class _MyAppState extends State<MyApp> {
await initializer.initializeApp();
await EncryptionHelper.initialize();
if (Platform.isAndroid || Platform.isIOS) {
Get.put(
NotificationController()); // Initialize NotificationController here
await FirebaseMessaging.instance.requestPermission();
FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
await NotificationController().initNotifications();
Get.put(NotificationController());
Get.put(FirebaseMessagesController());
// Generate a random index to pick a message
final random = Random();
final randomMessage =
driverMessages[random.nextInt(driverMessages.length)];
// Schedule the notification with the random message
NotificationController().scheduleNotificationsForSevenDays(
randomMessage.split(':')[0],
randomMessage.split(':')[1],
"ding",
);
await FirebaseMessaging.instance.requestPermission();
FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
await NotificationController().initNotifications();
await Future.wait([
FirebaseMessagesController().getNotificationSettings(),
FirebaseMessagesController().getToken(),
]);
// You can add your other initializations here
// For example:
// PermissionStatus status1 = await Permission.location.status;
// if (status1.isGranted) {
// await LocationController().startLocationUpdates();
// }
}
String? key = (await storage.read(key: BoxName.payMobApikey));
if (key != null) {
String? apiKey = (key);
if (apiKey != null) {
PaymobPayment.instance.initialize(
// Use .instance
apiKey: apiKey,
integrationID: int.parse(AK.integrationIdPayMob),
userTokenExpiration: 200,
iFrameID: 837992,
);
PaymobPaymentWallet.instance.initialize(
// Use .instance
apiKey: apiKey,
integrationID: int.parse(AK.integrationIdPayMobWallet),
userTokenExpiration: 200,
iFrameID: 837992,
);
}
}
// Your other startup logic...
} catch (e) {
print("Error initializing app: $e");
// Handle initialization errors appropriately. Maybe show an error message to the user.
Log.print("Error during _initApp: $e");
}
}
//--- Build Method ---
@override
Widget build(BuildContext context) {
LocaleController localController = Get.put(LocaleController());
@@ -231,105 +196,11 @@ class _MyAppState extends State<MyApp> {
GetPage(
name: '/order-page',
page: () => OrderRequestPage(),
arguments: box.read(BoxName.rideArguments),
),
GetPage(
name: '/passenger-location-map',
page: () => PassengerLocationMapPage()),
],
);
}
}
// void main() async {
// WidgetsFlutterBinding.ensureInitialized();
// await WakelockPlus.enable();
//
// await GetStorage.init();
//
// final AppInitializer initializer = AppInitializer();
//
// await initializer.initializeApp();
// await Future.delayed(Duration.zero);
// await EncryptionHelper.initialize();
//
// Stripe.publishableKey = AK.publishableKeyStripe;
//
// PermissionStatus status1 = await Permission.location.status;
// // if (status1.isGranted) {
// await LocationController().startLocationUpdates();
// // }
//
// if (Platform.isAndroid || Platform.isIOS) {
// NotificationController notificationController =
// Get.put(NotificationController());
// await Firebase.initializeApp(
// options: DefaultFirebaseOptions.currentPlatform,
// );
// await FirebaseMessagesController().requestFirebaseMessagingPermission();
//
// FirebaseMessaging.onBackgroundMessage(backgroundMessageHandler);
//
// await notificationController.initNotifications();
//
// // Generate a random index to pick a message
// final random = Random();
// final randomMessage = driverMessages[random.nextInt(driverMessages.length)];
//
// // Schedule the notification with the random message
// notificationController.scheduleNotificationsForSevenDays(
// randomMessage.split(':')[0],
// randomMessage.split(':')[1],
// "ding",
// );
//
// await Future.wait([
// FirebaseMessagesController().getNotificationSettings(),
// FirebaseMessagesController().getToken(),
// ]);
// // await FacebookAuth.instance.init();
// SystemChrome.setPreferredOrientations([
// DeviceOrientation.portraitUp,
// DeviceOrientation.portraitDown,
// ]);
// }
//
// String? key = (await storage.read(key: BoxName.payMobApikey));
//
// String? apiKey = EncryptionHelper.instance.decryptData(key!);
// PaymobPayment.instance.initialize(
// apiKey: apiKey,
// integrationID: int.parse(AK.integrationIdPayMob),
// userTokenExpiration: 200,
// iFrameID: 837992,
// );
//
// PaymobPaymentWallet.instance.initialize(
// apiKey: apiKey,
// integrationID: int.parse(AK.integrationIdPayMobWallet),
// userTokenExpiration: 200,
// iFrameID: 837992,
// );
// runApp(MyApp());
// }
//
// class MyApp extends StatelessWidget {
// @override
// Widget build(BuildContext context) {
// LocaleController localController = Get.put(LocaleController());
// return GetMaterialApp(
// navigatorKey: navigatorKey,
// title: AppInformation.appName,
// translations: MyTranslation(),
// debugShowCheckedModeBanner: false,
// locale: localController.language,
// theme: localController.appTheme,
// initialRoute: '/',
// getPages: [
// GetPage(name: '/', page: () => SplashScreen()),
// GetPage(
// name: '/order-page',
// page: () => OrderRequestPage(),
// arguments: box.read(BoxName.rideArguments),
// ),
// ],
// );
// }
// }

View File

@@ -1,16 +1,18 @@
// lib/models/order_data.dart
// lib/models/model/order_data.dart
class OrderData {
final String customerName;
final double tripDistanceKm; // المسافة الكلية للرحلة بالكيلومتر
final String customerToken;
final double tripDistanceKm; // The total trip distance in kilometers
final String price;
final String startLocationAddress;
final String endLocationAddress;
final double distanceToPassengerKm; // المسافة إلى الراكب بالكيلومتر
final int tripDurationMinutes; // مدة الرحلة الكلية بالدقائق (مقربة لأعلى)
final double
distanceToPassengerKm; // The distance to the passenger in kilometers
final int tripDurationMinutes; // Total trip duration in minutes (rounded up)
final int
durationToPassengerMinutes; // المدة إلى الراكب بالدقائق (مقربة لأعلى)
durationToPassengerMinutes; // Duration to reach the passenger in minutes (rounded up)
final String rideType;
final String orderId;
@@ -22,6 +24,7 @@ class OrderData {
OrderData({
required this.customerName,
required this.customerToken,
required this.tripDistanceKm,
required this.price,
required this.startLocationAddress,
@@ -37,26 +40,57 @@ class OrderData {
this.rawEndCoordinates,
});
// دالة مساعدة لتحويل الثواني إلى دقائق وتقريبها لأعلى
// --- NEW: Factory constructor to create an instance from a Map ---
// This is the missing method that was causing the error.
factory OrderData.fromMap(Map<String, dynamic> map) {
return OrderData(
// For strings, provide a default value in case the map key is null
customerName: map['customerName']?.toString() ?? 'Unknown Customer',
customerToken: map['customerToken']?.toString() ?? 'Unknown token',
// For numbers, cast from 'num' to handle both int and double, with a default value
tripDistanceKm: (map['tripDistanceKm'] as num?)?.toDouble() ?? 0.0,
price: map['price']?.toString() ?? '0',
startLocationAddress:
map['startLocationAddress']?.toString() ?? 'Unknown Address',
endLocationAddress:
map['endLocationAddress']?.toString() ?? 'Unknown Address',
distanceToPassengerKm:
(map['distanceToPassengerKm'] as num?)?.toDouble() ?? 0.0,
tripDurationMinutes: (map['tripDurationMinutes'] as num?)?.toInt() ?? 0,
durationToPassengerMinutes:
(map['durationToPassengerMinutes'] as num?)?.toInt() ?? 0,
rideType: map['rideType']?.toString() ?? 'Unknown',
orderId: map['orderId']?.toString() ?? 'N/A',
passengerId: map['passengerId']?.toString() ?? 'N/A',
passengerRate: map['passengerRate']?.toString() ?? 'N/A',
// For nullable strings, direct access is fine as it returns null if the key doesn't exist
rawStartCoordinates: map['rawStartCoordinates'],
rawEndCoordinates: map['rawEndCoordinates'],
);
}
// A helper function to convert seconds to rounded-up minutes
static int _secondsToRoundedUpMinutes(String secondsString) {
final seconds = double.tryParse(secondsString) ?? 0.0;
if (seconds <= 0) return 0;
return (seconds / 60)
.ceil(); // .ceil() لتقريب الكسر لأعلى (مثلاً 0.1 دقيقة تصبح 1 دقيقة)
.ceil(); // .ceil() rounds up (e.g., 0.1 minutes becomes 1 minute)
}
// Your existing factory for creating an instance from a List
factory OrderData.fromList(List<dynamic> list) {
// بناءً على testList والافتراضات الجديدة:
// list[4]: durationToRide (مدة الرحلة الكلية بالثواني)
// list[5]: distance (المسافة الكلية للرحلة بالكيلومتر)
// list[12]: distanceByPassenger (المسافة إلى الراكب بالمتر)
// list[15]: durationToPassenger (المدة إلى الراكب بالثواني)
double distanceToPassengerMeters =
list.length > 12 ? (double.tryParse(list[12].toString()) ?? 0.0) : 0.0;
return OrderData(
customerName: list.length > 8 ? list[8].toString() : 'Unknown Customer',
customerToken: list.length > 9 ? list[9].toString() : 'Unknown token',
tripDistanceKm:
list.length > 5 ? (double.tryParse(list[5].toString()) ?? 0.0) : 0.0,
price: list.length > 2 ? list[2].toString().split('.')[0] : '0',
@@ -66,7 +100,7 @@ class OrderData {
list.length > 30 ? list[30].toString() : 'Unknown Address',
distanceToPassengerKm:
distanceToPassengerMeters / 1000.0, // تحويل من متر إلى كيلومتر
distanceToPassengerMeters / 1000.0, // Convert meters to kilometers
tripDurationMinutes:
list.length > 4 ? _secondsToRoundedUpMinutes(list[4].toString()) : 0,
@@ -102,6 +136,7 @@ class OrderData {
}
}
// Getter to parse start coordinates
Map<String, double?>? get startCoordinates {
if (rawStartCoordinates == null) return null;
final parts = rawStartCoordinates!.split(',');
@@ -114,6 +149,7 @@ class OrderData {
return null;
}
// Getter to parse end coordinates
Map<String, double?>? get endCoordinates {
if (rawEndCoordinates == null) return null;
final parts = rawEndCoordinates!.split(',');
@@ -126,6 +162,8 @@ class OrderData {
return null;
}
// Your existing method to convert the object TO a Map.
// This is used to pass the data from the overlay to the main app.
Map<String, dynamic> toMap() {
return {
'customerName': customerName,

View File

@@ -0,0 +1,13 @@
import 'package:flutter/services.dart';
class OverlayMethodChannel {
static const _channel = MethodChannel('com.sefer_driver/app_control');
static Future<void> bringToForeground() async {
try {
await _channel.invokeMethod('bringToForeground');
} on PlatformException catch (e) {
print('Error bringing app to foreground: $e');
}
}
}

View File

@@ -104,13 +104,14 @@ class CountryPickerFromSetting extends StatelessWidget {
final List<String> countryOptions = [
'Jordan',
'USA',
"Syria",
'Egypt',
'Turkey',
'Saudi Arabia',
'Qatar',
'Bahrain',
'Kuwait',
'USA',
];
CountryPickerFromSetting({Key? key}) : super(key: key);

View File

@@ -28,7 +28,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Step-by-step instructions on how to request a ride through the Sefer app.'
'Step-by-step instructions on how to request a ride through the Tripz app.'
.tr,
style: AppStyle.title,
),
@@ -43,7 +43,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Sefer offers a variety of vehicle options to suit your needs, including economy, comfort, and luxury. Choose the option that best fits your budget and passenger count.'
'Tripz offers a variety of vehicle options to suit your needs, including economy, comfort, and luxury. Choose the option that best fits your budget and passenger count.'
.tr,
style: AppStyle.title,
),
@@ -58,7 +58,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Sefer offers multiple payment methods for your convenience. Choose between cash payment or credit/debit card payment during ride confirmation.'
'Tripz offers multiple payment methods for your convenience. Choose between cash payment or credit/debit card payment during ride confirmation.'
.tr,
style: AppStyle.title,
),
@@ -73,7 +73,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Yes, you can cancel your ride under certain conditions (e.g., before driver is assigned). See the Sefer cancellation policy for details.'
'Yes, you can cancel your ride under certain conditions (e.g., before driver is assigned). See the Tripz cancellation policy for details.'
.tr,
style: AppStyle.title,
),
@@ -98,7 +98,7 @@ class FrequentlyQuestionsPage extends StatelessWidget {
});
},
child: Text(
'Visit our website or contact Sefer support for information on driver registration and requirements.'
'Visit our website or contact Tripz support for information on driver registration and requirements.'
.tr,
style: AppStyle.title,
),
@@ -115,22 +115,22 @@ class FrequentlyQuestionsPage extends StatelessWidget {
),
children: [
Text(
'Sefer provides in-app chat functionality to allow you to communicate with your driver or passenger during your ride.'
'Tripz provides in-app chat functionality to allow you to communicate with your driver or passenger during your ride.'
.tr,
style: AppStyle.title,
),
],
),
// Question 8: What safety measures does Sefer offer?
// Question 8: What safety measures does Tripz offer?
ExpansionTile(
title: Text(
'What safety measures does Sefer offer?'.tr,
'What safety measures does Tripz offer?'.tr,
style: AppStyle.title,
),
children: [
Text(
'Sefer prioritizes your safety. We offer features like driver verification, in-app trip tracking, and emergency contact options.'
'Tripz prioritizes your safety. We offer features like driver verification, in-app trip tracking, and emergency contact options.'
.tr,
style: AppStyle.title,
),

View File

@@ -120,7 +120,7 @@ class SettingsCaptain extends StatelessWidget {
CupertinoListTile(
leading: const Icon(CupertinoIcons.hand_raised_fill),
title:
Text("How to use SEFER".tr, style: AppStyle.headTitle2),
Text("How to use Tripz".tr, style: AppStyle.headTitle2),
trailing: const CupertinoListTileChevron(),
onTap: () => Get.to(() => const UsingAppPage()),
),

View File

@@ -10,7 +10,7 @@ class UsingAppPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MyScafolld(
title: "How to use SEFER".tr,
title: "How to use Tripz".tr,
body: [
SizedBox(
child: Padding(
@@ -22,12 +22,13 @@ class UsingAppPage extends StatelessWidget {
MyDialogContent().getDialog(
"What are the order details we provide to you?".tr,
Image.network(
'https://api.sefer.live/sefer/imageForUsingApp/order_page.jpg',
'https://api.tripz-egypt.com/tripz/imageForUsingApp/order_page.jpg',
height: 300,
width: 300,
fit: BoxFit.cover,
),
() {});
), () {
Get.back();
});
},
child: Container(
decoration: AppStyle.boxDecoration1,
@@ -47,16 +48,17 @@ class UsingAppPage extends StatelessWidget {
onTap: () {
MyDialog().getDialog(
"What are the order details we provide to you?".tr,
'''Sefer Wallet Features:
'''Tripz Wallet Features:
Transfer money multiple times.
Transfer to anyone.
Make purchases.
Charge your account.
Charge a friend's Sefer account.
Charge a friend's Tripz account.
Store your money with us and receive it in your bank as a monthly salary.'''
.tr,
() {});
.tr, () {
Get.back();
});
},
child: Container(
decoration: AppStyle.boxDecoration1,
@@ -75,8 +77,8 @@ Store your money with us and receive it in your bank as a monthly salary.'''
InkWell(
onTap: () {
MyDialog().getDialog(
"What are the order details we provide to you?".tr,
'''Types of Trips in Sefer:
"What is Types of Trips in Tripz?".tr,
'''Types of Trips in Tripz:
Comfort: For cars newer than 2017 with air conditioning.
Lady: For girl drivers.
@@ -84,15 +86,16 @@ Speed: For fixed salary and endpoints.
Mashwari: For flexible trips where passengers choose the car and driver with prior arrangements.
Raih Gai: For same-day return trips longer than 50km.
'''
.tr,
() {});
.tr, () {
Get.back();
});
},
child: Container(
decoration: AppStyle.boxDecoration1,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"What is Types of Trips in Sefer?".tr,
"What is Types of Trips in Tripz?".tr,
style: AppStyle.title,
),
),

View File

@@ -21,16 +21,20 @@ class PassengerLocationMapPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// if (!mapDriverController.initialized) {
// // Call a method to initialize the controller
// mapDriverController.initialized;
// } else {
// Get.put(MapDriverController()).argumentLoading();
// Get.put(MapDriverController())
// .startTimerToShowPassengerInfoWindowFromDriver();
// }
if (Get.arguments != null && Get.arguments is Map<String, dynamic>) {
// نستخدم addPostFrameCallback لضمان أن هذا الكود يعمل بعد اكتمال بناء الإطار الأول
// هذا يعطي GetX وقته لتجهيز كل شيء
WidgetsBinding.instance.addPostFrameCallback((_) {
// نستدعي دالة التهيئة الجديدة ونمرر لها البيانات
mapDriverController.argumentLoading();
});
} else {
// في حال عدم وجود arguments، يجب التعامل مع هذا الخطأ
WidgetsBinding.instance.addPostFrameCallback((_) {
Get.snackbar("Error", "No order data found.");
Get.back();
});
}
mapDriverController.argumentLoading();
mapDriverController.startTimerToShowPassengerInfoWindowFromDriver();

View File

@@ -19,6 +19,7 @@ import '../../../../controller/functions/location_controller.dart';
import '../../../../controller/functions/overlay_permisssion.dart';
import '../../../../controller/functions/package_info.dart';
import '../../../../controller/home/captin/home_captain_controller.dart';
import '../../../../print.dart';
import '../../../widgets/circle_container.dart';
import '../driver_map_page.dart';
import 'widget/connect.dart';
@@ -482,6 +483,8 @@ class HomeCaptain extends StatelessWidget {
),
GetBuilder<HomeCaptainController>(
builder: (homeCaptainController) {
Log.print(
'rideStatus from home 486 : ${box.read(BoxName.rideStatus)}');
return box.read(BoxName.rideStatus) == 'Applied' ||
box.read(BoxName.rideStatus) == 'Begin'
? Positioned(
@@ -520,7 +523,7 @@ class HomeCaptain extends StatelessWidget {
};
},
icon: const Icon(
Icons.rice_bowl,
Icons.directions_rounded,
size: 29,
color: AppColor.blueColor,
),

View File

@@ -1,13 +1,21 @@
import 'package:sefer_driver/constant/box_name.dart';
import 'package:sefer_driver/controller/firebase/local_notification.dart';
import 'package:sefer_driver/main.dart';
import 'package:sefer_driver/print.dart';
import 'package:sefer_driver/views/home/Captin/driver_map_page.dart';
import 'package:sefer_driver/views/home/Captin/orderCaptin/vip_order_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_font_icons/flutter_font_icons.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/controller/home/captin/home_captain_controller.dart';
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import '../../../../../constant/colors.dart';
import '../../../../../constant/links.dart';
import '../../../../../controller/firebase/firbase_messge.dart';
import '../../../../../controller/functions/crud.dart';
import '../../../../../controller/home/captin/order_request_controller.dart';
import '../../../../Rate/ride_calculate_driver.dart';
GetBuilder<HomeCaptainController> leftMainMenuCaptainIcons() {
@@ -17,6 +25,46 @@ GetBuilder<HomeCaptainController> leftMainMenuCaptainIcons() {
left: 6,
child: Column(
children: [
AnimatedContainer(
duration: const Duration(microseconds: 200),
width: controller.widthMapTypeAndTraffic,
decoration: BoxDecoration(
color: AppColor.secondaryColor,
border: Border.all(color: AppColor.blueColor),
borderRadius: BorderRadius.circular(15)),
child: Builder(builder: (context) {
return IconButton(
onPressed: () async {
await checkForPendingOrderFromServer();
box.read(BoxName.rideArgumentsFromBackground) != 'failure'
? Get.to(() => PassengerLocationMapPage(),
arguments:
box.read(BoxName.rideArgumentsFromBackground))
: MyDialog().getDialog(
'Ride info'.tr,
'you dont have accepted ride'.tr,
() {
Get.back();
},
);
// Log.print(
// 'box.read(BoxName.rideArgumentsFromBackground): ${box.read(BoxName.rideArgumentsFromBackground)}');
},
icon: Icon(
Icons.directions_car_rounded,
size: 29,
color:
box.read(BoxName.rideArgumentsFromBackground) == 'failure'
? AppColor.redColor
: AppColor.greenColor,
),
);
}),
),
const SizedBox(
height: 5,
),
AnimatedContainer(
duration: const Duration(microseconds: 200),
width: controller.widthMapTypeAndTraffic,
@@ -89,7 +137,10 @@ GetBuilder<HomeCaptainController> leftMainMenuCaptainIcons() {
}),
)
: const SizedBox(),
// : const SizedBox(),
// const SizedBox(
// height: 5,
// ),
// AnimatedContainer(
// duration: const Duration(microseconds: 200),
// width: controller.widthMapTypeAndTraffic,
@@ -100,53 +151,7 @@ GetBuilder<HomeCaptainController> leftMainMenuCaptainIcons() {
// child: Builder(builder: (context) {
// return IconButton(
// onPressed: () async {
// final List<dynamic> testList = const [
// "32.1117875,36.0669891",
// "32.1364001,36.0707479",
// "24.84",
// "7.56",
// "436",
// "4.38",
// "109270481246447459618",
// "113172279072358305645",
// "hamza",
// "e4QWqe7K607luM7qUMOPCL:APA91bFjX4XBM4I5COJl9fyxCTKJ1ZQpT3vzY7iEbOTuT4uo0-OSCAt5zgVhlhw4aC33s-VhyucDnP1tQGFd9svaazQ8A_SKgolPk3owzug8dCsiXoPeJ0k",
// "+201010101010",
// "6",
// "43",
// "true",
// "c2tXiuBJQCSg4CU4IfqYOL:APA91bFA0f8R3QMnPQnPEEdNyjY-jcoKt4nLBHxcLLsmDSuJn5yd4jSvwq7qDIZpkkPkjfjdwdKsGL0-G0aHpPyjfiBvbCwFmlRMCUKftNMNT7MJx2Bp16Y",
// "6",
// "1188",
// "false",
// "109270481246447459618",
// "436",
// "startEnd",
// "32.12404505187645,36.06566168367863",
// "",
// "",
// "",
// "",
// "5.42",
// "0",
// "hamzaayedflutter@gmail.com",
// "4368+PPP، السخنة، الأردن",
// "43PC+C4G، السخنة، الأردن",
// "Speed",
// "8",
// "5.00"
// ];
// await FlutterOverlayWindow.shareData(testList);
// await FlutterOverlayWindow.showOverlay(
// enableDrag: true,
// flag: OverlayFlag.focusPointer,
// // visibility: NotificationVisibility.visibilityPublic,
// positionGravity: PositionGravity.auto,
// height: 1300,
// width: WindowSize.matchParent,
// startPosition: const OverlayPosition(0, -90),
// );
// debugPrint('Overlay opened: ');
// Log.print('phoneDriver: ${box.read(BoxName.phoneDriver)}');
// },
// icon: const Icon(
// FontAwesome5.grin_tears,
@@ -165,3 +170,142 @@ GetBuilder<HomeCaptainController> leftMainMenuCaptainIcons() {
),
);
}
void _log(String message) => print(message);
Future<void> checkForPendingOrderFromServer() async {
bool _isProcessingOrder = false;
if (_isProcessingOrder) return;
final driverId = box.read(BoxName.driverID)?.toString();
if (driverId == null) return; // Can't check without a driver ID
_isProcessingOrder = true; // Lock
try {
// You need to create this CRUD method
var response = await CRUD().post(
link: AppLink.getArgumentAfterAppliedFromBackground,
payload: {'driver_id': driverId},
);
// Assuming the server returns order data if found, or 'failure'/'none' if not
if (response != 'failure') {
Log.print('response: ${response}');
_log("MAIN_APP_LOG: Pending order DETECTED from server!");
final Map<String, dynamic> orderInfoFromServer = response['message'];
final Map<String, dynamic> rideArguments =
_transformServerDataToAppArguments(orderInfoFromServer);
// 2. Build the new arguments map, matching your Flutter structure
_log("MAIN_APP_LOG: Constructed rideArguments map successfully.");
/////////////
final customerToken = (response)['message']['token_passenger'];
final orderId = (response)['message']['ride_id'].toString();
Log.print('orderId: ${orderId}');
box.write(BoxName.rideArgumentsFromBackground, rideArguments);
box.write(BoxName.statusDriverLocation, 'on');
box.write(BoxName.rideStatus, 'Apply');
Get.put(OrderRequestController()).changeApplied();
// MyDialog().getDialog(orderId.toString(), customerToken, () {});
// Now proceed with the UI flow
_sendAcceptanceNotification(customerToken, orderId.toString());
// await _bringAppToForegroundAndNavigate(orderId);
} else {
_log("MAIN_APP_LOG: No pending orders found on server.");
box.write(BoxName.rideArgumentsFromBackground, 'failure');
}
} catch (e) {
_log("Error while polling server: $e");
} finally {
_isProcessingOrder = false; // Release lock
}
}
Map<String, dynamic> _transformServerDataToAppArguments(
Map<String, dynamic> serverData) {
_log("Transforming server data to match app's argument structure.");
// Helper function to safely get and convert values to String
String _getString(String key, [String defaultValue = 'unknown']) {
// serverData[key] might be an int, double, or string. .toString() handles all.
// If it's null, use the default value.
return serverData[key]?.toString() ?? defaultValue;
}
return {
'passengerLocation': _getString('passenger_location'),
'passengerDestination': _getString('passenger_destination'),
'Duration': _getString('duration'),
'totalCost': _getString('total_cost'),
'Distance': _getString('distance'),
'name': _getString('name'),
'phone': _getString('phone'),
'email': _getString('email'),
'tokenPassenger': _getString('token_passenger'),
'direction': _getString('direction_url'),
'DurationToPassenger': _getString('duration_to_passenger'),
'rideId': _getString('ride_id'),
'passengerId': _getString('passenger_id'),
'driverId': _getString('driver_id'),
'durationOfRideValue': _getString('duration_of_ride'),
'paymentAmount': _getString('payment_amount'),
'paymentMethod': _getString('payment_method'),
'passengerWalletBurc': _getString('passenger_wallet_burc'),
'timeOfOrder': _getString('time_of_order'),
'totalPassenger': _getString('total_passenger'),
'carType': _getString('car_type'),
'kazan': _getString('kazan'),
'startNameLocation': _getString('start_name_location'),
'endNameLocation': _getString('end_name_location'),
// --- Special Handling ---
// Steps (handle null values by providing an empty string)
'step0': _getString('step0'),
'step1': _getString('step1'),
'step2': _getString('step2'),
'step3': _getString('step3'),
'step4': _getString('step4'),
// Boolean conversion (1/0 from server to 'true'/'false' string for the app)
'WalletChecked': (serverData['wallet_checked'] == 1).toString(),
// Logic-based conversion for isHaveSteps
// Your app's `rideArguments` expects 'startEnd', so we provide that if has_steps is 1.
// You might need to adjust this logic if 'haveSteps' is also a possibility.
'isHaveSteps': (serverData['has_steps'] == 1)
? 'startEnd'
: 'noSteps', // Providing a default
};
}
void _sendAcceptanceNotification(String? customerToken, rideId) {
try {
if (customerToken == null) return;
final FirebaseMessagesController _firebaseMessagesController =
Get.put(FirebaseMessagesController());
_log("Attempting to send acceptance notification to passenger...");
List<String> bodyToPassenger = [
box.read(BoxName.driverID).toString(),
box.read(BoxName.nameDriver).toString(),
box.read(BoxName.tokenDriver).toString(),
rideId.toString()
];
// Safely check for customer token
final String? token = customerToken;
if (token != null && token.isNotEmpty) {
_firebaseMessagesController.sendNotificationToDriverMAP('Accepted Ride',
'your ride is applied'.tr, token, bodyToPassenger, 'start.wav');
_log("Acceptance notification task was fired.");
} else {
_log("Could not send notification: Customer token is missing or empty.");
}
} catch (e) {
_log("Error while firing notification task: $e");
}
}

View File

@@ -51,7 +51,7 @@ import 'package:get/get.dart';
// child: Padding(
// padding: const EdgeInsets.all(14),
// child: Text(
// "We have maintenance offers for your car. You can use them after completing 600 trips to get a 20% discount on car repairs. Enjoy using our SEFER app and be part of our SEFER family."
// "We have maintenance offers for your car. You can use them after completing 600 trips to get a 20% discount on car repairs. Enjoy using our Tripz app and be part of our Tripz family."
// .tr,
// style: AppStyle.title,
// ),
@@ -186,7 +186,7 @@ class MaintainCenterPage extends StatelessWidget {
),
const SizedBox(height: 8),
Text(
"We have maintenance offers for your car. You can use them after completing 600 trips to get a 20% discount on car repairs. Enjoy using our SEFER app and be part of our SEFER family."
"We have maintenance offers for your car. You can use them after completing 600 trips to get a 20% discount on car repairs. Enjoy using our Tripz app and be part of our Tripz family."
.tr,
style: Theme.of(context)
.textTheme

View File

@@ -13,8 +13,11 @@ import 'package:sefer_driver/controller/firebase/firbase_messge.dart';
import 'package:sefer_driver/controller/home/captin/map_driver_controller.dart';
import 'package:sefer_driver/views/widgets/elevated_btn.dart';
import '../../../../constant/box_name.dart';
import '../../../../constant/style.dart';
import '../../../../controller/functions/launch.dart';
import '../../../../main.dart';
import '../../../../print.dart';
class PassengerInfoWindow extends StatelessWidget {
const PassengerInfoWindow({super.key});
@@ -179,7 +182,7 @@ class PassengerInfoWindow extends StatelessWidget {
if (await controller
.calculateDistanceBetweenDriverAndPassengerLocation() <
140) {
FirebaseMessagesController()
Get.find<FirebaseMessagesController>()
.sendNotificationToDriverMAP(
'Hi ,I Arrive your site',
'I Arrive at your site'.tr,
@@ -245,7 +248,7 @@ class PassengerInfoWindow extends StatelessWidget {
MyDialog().getDialog(
'Are you sure to cancel?'.tr, '',
() async {
FirebaseMessagesController()
Get.find<FirebaseMessagesController>()
.sendNotificationToDriverMAP(
'Driver Cancelled Your Trip',
'You will need to pay the cost to the driver, or it will be deducted from your next trip'
@@ -254,6 +257,9 @@ class PassengerInfoWindow extends StatelessWidget {
[],
'cancel.wav',
);
Log.print(
'rideStatus from passenge info 261 : ${box.read(BoxName.rideStatus)}');
box.write(BoxName.rideStatus, 'Cancel');
await controller
.addWaitingTimeCostFromPassengerToDriverWallet();
controller.isdriverWaitTimeEnd = false;
@@ -296,7 +302,7 @@ class PassengerInfoWindow extends StatelessWidget {
_buildMessageTile(
text: "Where are you, sir?".tr,
onTap: () {
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'message From Driver',
"Where are you, sir?".tr,
controller.tokenPassenger,
@@ -309,7 +315,7 @@ class PassengerInfoWindow extends StatelessWidget {
_buildMessageTile(
text: "I've been trying to reach you but your phone is off.".tr,
onTap: () {
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'message From Driver',
"I've been trying to reach you but your phone is off.".tr,
controller.tokenPassenger,
@@ -324,7 +330,7 @@ class PassengerInfoWindow extends StatelessWidget {
"Please don't be late, I'm waiting for you at the specified location."
.tr,
onTap: () {
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'message From Driver',
"Please don't be late, I'm waiting for you at the specified location."
.tr,
@@ -338,7 +344,7 @@ class PassengerInfoWindow extends StatelessWidget {
_buildMessageTile(
text: "Please don't be late".tr,
onTap: () {
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
'message From Driver',
"Please don't be late".tr,
controller.tokenPassenger,
@@ -364,7 +370,8 @@ class PassengerInfoWindow extends StatelessWidget {
),
IconButton(
onPressed: () {
FirebaseMessagesController().sendNotificationToDriverMAP(
Get.find<FirebaseMessagesController>()
.sendNotificationToDriverMAP(
'message From Driver',
controller.messageToPassenger.text,
controller.tokenPassenger,

View File

@@ -171,7 +171,7 @@ class SosConnect extends StatelessWidget {
} else {
throw 'Could not launch google maps';
}
};
}();
}
void _sendWhatsAppMessage(MapDriverController mapDriverController) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:sefer_driver/constant/colors.dart';
@@ -5,9 +7,13 @@ import 'package:sefer_driver/constant/style.dart';
import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart';
import 'package:sefer_driver/controller/payment/payment_controller.dart';
import 'package:sefer_driver/views/widgets/mydialoug.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../../../constant/box_name.dart';
import '../../../constant/links.dart';
import '../../../controller/functions/crud.dart';
import '../../../main.dart';
import '../../../print.dart';
import '../../widgets/elevated_btn.dart';
import '../../widgets/my_textField.dart';
@@ -44,21 +50,34 @@ class PointsCaptain extends StatelessWidget {
title: 'Pay with Credit Card'.tr,
onPressed: () async {
Get.back();
await paymentController.payWithPayMob(
context,
pricePoint.toStringAsFixed(2),
box.read(BoxName.countryCode) == 'Egypt'
? 'EGP'
: 'JOD', () async {
// await captainWalletController.getPaymentId(
// 'visa-in', pricePoint);
await captainWalletController.addDriverWallet(
'visa-in', countPoint, pricePoint);
await captainWalletController.addSeferWallet(
'visa-in', pricePoint.toString());
await captainWalletController
.getCaptainWalletFromBuyPoints();
});
var res = await CRUD().postWallet(
// link: AppLink.payWithPayMobWalletPasenger,
link: AppLink.payWithPayMobCardDriver,
payload: {
"amount": pricePoint.toStringAsFixed(2),
"email": box.read(BoxName.emailDriver),
"first_name": (box
.read(BoxName.nameDriver)
.toString()
.split(' ')[0])
.toString(),
"last_name": (box
.read(BoxName.nameDriver)
.toString()
.split(' ')[1])
.toString(),
"phone_number": (box.read(BoxName.phoneDriver)),
});
// var d = jsonDecode(res);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PaymentScreen(
iframeUrl: res['message'],
countPrice: countPoint.toString()),
),
);
}, //51524
),
// Add some spacing between buttons
@@ -88,31 +107,45 @@ class PointsCaptain extends StatelessWidget {
BoxName.phoneWallet,
paymentController
.walletphoneController.text);
await paymentController.payWithPayMobWallet(
context,
pricePoint.toStringAsFixed(2),
box.read(BoxName.countryCode) == 'Egypt'
? 'EGP'
: 'JOD', () async {
// await captainWalletController
// .getPaymentId('visa-in', pricePoint);
await captainWalletController
.addDriverWallet('visa-in',
countPoint, pricePoint);
await captainWalletController
.addSeferWallet(
'visa-in', pricePoint.toString());
await captainWalletController
.getCaptainWalletFromBuyPoints();
});
var res = await CRUD().postWallet(
// link: AppLink.payWithPayMobWalletPasenger,
link: AppLink.payWithWallet,
payload: {
"amount":
pricePoint.toStringAsFixed(2),
"email":
box.read(BoxName.emailDriver),
"first_name": (box
.read(BoxName.nameDriver)
.toString()
.split(' ')[0])
.toString(),
"last_name": (box
.read(BoxName.nameDriver)
.toString()
.split(' ')[1])
.toString(),
"phone_number":
(box.read(BoxName.phoneWallet)),
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
PaymentScreenWallet(
iframeUrl: res['message'],
countPrice:
countPoint.toString()),
),
);
}
MyDialog().getDialog(
'phone number is wrong'.tr,
'',
() {
Get.back();
},
);
// MyDialog().getDialog(
// 'phone number is wrong'.tr,
// '',
// () {
// Get.back();
// },
// );
// Get.back();
}));
},
@@ -173,3 +206,311 @@ class PointsCaptain extends StatelessWidget {
);
}
}
class PaymentScreen extends StatefulWidget {
final String iframeUrl;
final String countPrice;
const PaymentScreen(
{required this.iframeUrl, Key? key, required this.countPrice})
: super(key: key);
@override
State<PaymentScreen> createState() => _PaymentScreenState();
}
class _PaymentScreenState extends State<PaymentScreen> {
late final WebViewController _controller;
final controller = Get.find<CaptainWalletController>();
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageFinished: (url) {
if (url.contains("success")) {
_fetchPaymentStatus(); // ✅ استدعاء الويب هوك بعد نجاح الدفع
} else if (url.contains("failed")) {
showCustomDialog(
title: "Error".tr,
message: 'Payment Failed'.tr, // يتم جلب رسالة الخطأ من الخادم
isSuccess: false,
);
}
},
))
..loadRequest(Uri.parse(widget.iframeUrl));
}
Future<void> _fetchPaymentStatus() async {
final String userId = box.read(BoxName.phoneDriver);
await Future.delayed(const Duration(seconds: 2));
try {
final response = await CRUD().postWallet(
link: AppLink.paymetVerifyDriver,
payload: {
'user_id': userId,
'driverID': box.read(BoxName.driverID),
'paymentMethod': 'visa-in',
},
);
if (response != 'failure' && response != 'token_expired') {
if (response['status'] == 'success') {
final payment = response['message'];
final amount = payment['amount'].toString();
final bonus = payment['bonus'].toString();
final paymentID = payment['paymentID'].toString();
await controller.getCaptainWalletFromBuyPoints();
showCustomDialog(
title: "payment_success".tr,
message:
"${"transaction_id".tr}: $paymentID\n${"amount_paid".tr}: $amount EGP\n${"bonus_added".tr}: $bonus ${"points".tr}",
isSuccess: true,
);
} else {
showCustomDialog(
title: "transaction_failed".tr,
message: response['message'].toString(),
isSuccess: false,
);
}
} else {
showCustomDialog(
title: "connection_failed".tr,
message: response.toString(),
isSuccess: false,
);
}
} catch (e) {
showCustomDialog(
title: "server_error".tr,
message: "server_error_message".tr,
isSuccess: false,
);
}
}
void showCustomDialog({
required String title,
required String message,
required bool isSuccess,
}) {
showDialog(
barrierDismissible: false,
context: Get.context!,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
title: Row(
children: [
Icon(
isSuccess ? Icons.check_circle : Icons.error,
color: isSuccess ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
title,
style: TextStyle(
color: isSuccess ? Colors.green : Colors.red,
fontWeight: FontWeight.bold,
),
),
],
),
content: Text(
message,
style: const TextStyle(fontSize: 16),
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
style: TextButton.styleFrom(
backgroundColor: isSuccess ? Colors.green : Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
"OK",
style: const TextStyle(color: Colors.white),
),
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('إتمام الدفع')),
body: WebViewWidget(controller: _controller),
);
}
}
class PaymentScreenWallet extends StatefulWidget {
final String iframeUrl;
final String countPrice;
const PaymentScreenWallet(
{required this.iframeUrl, Key? key, required this.countPrice})
: super(key: key);
@override
State<PaymentScreenWallet> createState() => _PaymentScreenWalletState();
}
class _PaymentScreenWalletState extends State<PaymentScreenWallet> {
late final WebViewController _controller;
final controller = Get.find<CaptainWalletController>();
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageFinished: (url) {
if (url.contains("success")) {
_fetchPaymentStatus(); // ✅ استدعاء الويب هوك بعد نجاح الدفع
} else if (url.contains("failed")) {
showCustomDialog(
title: "Error".tr,
message: 'Payment Failed'.tr, // يتم جلب رسالة الخطأ من الخادم
isSuccess: false,
);
}
},
))
..loadRequest(Uri.parse(widget.iframeUrl));
}
Future<void> _fetchPaymentStatus() async {
final String userId = '+2' + box.read(BoxName.phoneWallet);
await Future.delayed(const Duration(seconds: 2));
try {
final response = await CRUD().postWallet(
link: AppLink.paymetVerifyDriver,
payload: {
'user_id': userId,
'driverID': box.read(BoxName.driverID),
'paymentMethod': 'visa-in',
},
);
if (response != 'failure' && response != 'token_expired') {
if (response['status'] == 'success') {
final payment = response['message'];
final amount = payment['amount'].toString();
final bonus = payment['bonus'].toString();
final paymentID = payment['paymentID'].toString();
await controller.getCaptainWalletFromBuyPoints();
showCustomDialog(
title: "payment_success".tr,
message:
"${"transaction_id".tr}: $paymentID\n${"amount_paid".tr}: $amount EGP\n${"bonus_added".tr}: $bonus ${"points".tr}",
isSuccess: true,
);
} else {
showCustomDialog(
title: "transaction_failed".tr,
message: response['message'].toString(),
isSuccess: false,
);
}
} else {
showCustomDialog(
title: "connection_failed".tr,
message: response.toString(),
isSuccess: false,
);
}
} catch (e) {
showCustomDialog(
title: "server_error".tr,
message: "server_error_message".tr,
isSuccess: false,
);
}
}
void showCustomDialog({
required String title,
required String message,
required bool isSuccess,
}) {
showDialog(
barrierDismissible: false,
context: Get.context!,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
title: Row(
children: [
Icon(
isSuccess ? Icons.check_circle : Icons.error,
color: isSuccess ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Text(
title,
style: TextStyle(
color: isSuccess ? Colors.green : Colors.red,
fontWeight: FontWeight.bold,
),
),
],
),
content: Text(
message,
style: const TextStyle(fontSize: 16),
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.pop(context);
},
style: TextButton.styleFrom(
backgroundColor: isSuccess ? Colors.green : Colors.red,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text(
"OK",
style: const TextStyle(color: Colors.white),
),
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('إتمام الدفع')),
body: WebViewWidget(controller: _controller),
);
}
}