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

@@ -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),
);
}
}