Update: 2026-06-11 21:53:27

This commit is contained in:
Hamza-Ayed
2026-06-11 21:53:27 +03:00
parent b87477bec4
commit 7049c7468c
8 changed files with 970 additions and 104 deletions

View File

@@ -88,6 +88,15 @@ static String get payWithSyriatelConfirm =>
"$paymentServer/ride/syriatel/driver/confirm_payment.php";
static String get payWithSyriatelStart =>
"$paymentServer/ride/syriatel/driver/start_payment.php";
static String get createMtnInvoice => "$paymentServer/ride/mtn_new/create_mtn_invoice.php";
static String get uploadMtnProof => "$paymentServer/ride/mtn_new/verify_payment_ai.php";
static String get checkMtnStatus => "$paymentServer/ride/mtn_new/check_status.php";
static String get createCliqInvoice => "$paymentServer/ride/cliq/create_cliq_invoice.php";
static String get uploadCliqProof => "$paymentServer/ride/cliq/verify_payment_ai.php";
static String get checkCliqStatus => "$paymentServer/ride/cliq/check_status.php";
static String get payWithEcashDriver =>
"$paymentServer/ride/ecash/driver/payWithEcash.php";
static String get payWithEcashPassenger =>
@@ -102,6 +111,8 @@ static String get deletePassengersWallet => "$wallet/delete.php";
static String get updatePassengersWallet => "$wallet/update.php";
static String get getWalletByDriver => "$walletDriver/getWalletByDriver.php";
static String get transferWalletDriver => "$endPoint/ride/driverWallet/transfer.php";
static String get convertBudgetToPoints => "$walletDriver/convertBudgetToPoints.php";
static String get driverStatistic =>
"$endPoint/ride/driverWallet/driverStatistic.php";
static String get getDriverDetails =>

View File

@@ -1,8 +1,6 @@
import 'dart:convert';
import 'package:local_auth/local_auth.dart';
import 'package:siro_driver/constant/style.dart';
import 'package:siro_driver/controller/firebase/firbase_messge.dart';
import 'package:siro_driver/controller/firebase/local_notification.dart';
import 'package:siro_driver/views/widgets/elevated_btn.dart';
import 'package:siro_driver/views/widgets/error_snakbar.dart';
@@ -12,9 +10,10 @@ import 'package:siro_driver/constant/box_name.dart';
import 'package:siro_driver/constant/links.dart';
import 'package:siro_driver/controller/functions/crud.dart';
import 'package:siro_driver/main.dart';
import 'package:siro_driver/views/widgets/mycircular.dart';
import '../../../views/widgets/mydialoug.dart';
import '../../firebase/notification_service.dart';
import '../../../views/home/my_wallet/payment_screen_mtn.dart';
import '../../../views/home/my_wallet/payment_screen_cliq.dart';
class CaptainWalletController extends GetxController {
bool isLoading = false;
@@ -34,36 +33,57 @@ class CaptainWalletController extends GetxController {
final cardBank = TextEditingController();
final bankCode = TextEditingController();
double get transferFee {
String country = box.read(BoxName.countryCode) ?? 'Jordan';
if (country == 'Egypt') return 5.0;
if (country == 'Syria') return 10.0;
if (country == 'Jordan') return 0.25;
return 5.0;
}
double get minTransferAmount {
String country = box.read(BoxName.countryCode) ?? 'Jordan';
if (country == 'Egypt') return 10.0;
if (country == 'Syria') return 100.0;
if (country == 'Jordan') return 1.0;
return 10.0;
}
payFromBudget() async {
if (formKey.currentState!.validate()) {
var pointFromBudget = int.parse((amountFromBudgetController.text));
// await getPaymentId('fromBudgetToPoints',
// int.parse((amountFromBudgetController.text)) * -1);
var paymentToken3 =
await generateToken((pointFromBudget * -1).toString());
var paymentID = await getPaymentId(
'fromBudgetToPoints', (pointFromBudget * -1).toString());
await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'amount': (pointFromBudget * -1).toString(),
'rideId': paymentID.toString(),
'payment_method': 'myBudget',
'passengerID': 'myBudgetToPoint',
'token': paymentToken3,
Get.dialog(const Center(child: MyCircularProgressIndicator()),
barrierDismissible: false);
var res = await CRUD()
.postWallet(link: AppLink.convertBudgetToPoints, payload: {
'amount': pointFromBudget.toString(),
'driverID': box.read(BoxName.driverID).toString(),
});
Future.delayed(const Duration(seconds: 1));
await addDriverWallet(
'fromBudget', pointFromBudget.toString(), pointFromBudget.toString());
update();
Get.back();
await refreshCaptainWallet();
NotificationController().showNotification(
'You have successfully charged your account'.tr,
'$pointFromBudget ${'has been added to your budget'.tr}',
'tone1',
'',
);
Get.back(); // close loading
if (res != 'failure') {
late Map<String, dynamic> mapRes;
if (res is String) {
mapRes = json.decode(res);
} else {
mapRes = res;
}
if (mapRes['status'] == 'success') {
update();
Get.back();
await refreshCaptainWallet();
NotificationController().showNotification(
'You have successfully charged your account'.tr,
'$pointFromBudget ${'has been added to your budget'.tr}',
'tone1',
'',
);
} else {
mySnackeBarError(mapRes['message']?.toString() ?? 'Error');
}
} else {
mySnackeBarError('Error processing request'.tr);
}
}
}
@@ -262,71 +282,45 @@ class CaptainWalletController extends GetxController {
}
Future addTransferDriversWallet(String paymentMethod1, paymentMethod2) async {
var paymentID =
await getPaymentId(paymentMethod1, amountFromBudgetController.text);
paymentToken = await generateToken(
(int.parse(amountFromBudgetController.text) * -1).toString());
await CRUD().postWallet(link: AppLink.addDrivePayment, payload: {
'amount': (int.parse(amountFromBudgetController.text) * -1).toString(),
'rideId': paymentID.toString(),
'payment_method': paymentMethod1,
'passengerID': 'To ${amountToNewDriverMap[0]['id']}',
'token': paymentToken,
Get.dialog(const Center(child: CircularProgressIndicator()),
barrierDismissible: false);
var res =
await CRUD().postWallet(link: AppLink.transferWalletDriver, payload: {
'amount': amountFromBudgetController.text,
'receiverPhone': amountToNewDriverMap[0]['phone'].toString(),
'country': box.read(BoxName.countryCode) ?? 'Egypt',
'driverID': box.read(BoxName.driverID).toString(),
});
Get.back();
paymentID = await getPaymentId(paymentMethod2,
(int.parse(amountFromBudgetController.text) - 5).toString());
paymentToken = await generateToken(amountFromBudgetController.text);
var res1 =
await CRUD().postWallet(link: AppLink.addDriversWalletPoints, payload: {
'driverID': amountToNewDriverMap[0]['id'].toString(),
'paymentID': paymentID.toString(),
'amount': ((int.parse(amountFromBudgetController.text) - 5))
// kazan) // double.parse(kazan) .08 for egypt
.toStringAsFixed(
0), // this will convert buddget to poitns by kazan .08
if (res != 'failure') {
late Map<String, dynamic> mapRes;
if (res is String) {
mapRes = json.decode(res);
} else {
mapRes = res;
}
'token': paymentToken,
'paymentMethod': paymentMethod2.toString(),
});
if (res1 != 'failure') {
// Get.find<FirebaseMessagesController>().sendNotificationToDriverMAP(
// 'Transfer',
// '${'You have transfer to your wallet from'.tr}'
// '${box.read(BoxName.nameDriver)}',
// amountToNewDriverMap[0]['token'].toString(),
// [],
// 'order1.wav');
NotificationService.sendNotification(
target: amountToNewDriverMap[0]['token'].toString(),
title: 'Transfer'.tr,
body: '${'You have transfer to your wallet from'.tr}'
'${box.read(BoxName.nameDriver)}',
isTopic: false, // Important: this is a token
tone: 'ding',
driverList: [], category: 'Transfer',
);
await addSeferWallet('payout fee', '5');
Get.defaultDialog(
title: 'transfer Successful'.tr,
middleText: '',
titleStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'Ok'.tr,
onPressed: () async {
Get.back();
Get.back();
await refreshCaptainWallet();
}));
if (mapRes['status'] == 'success') {
Get.defaultDialog(
title: 'transfer Successful'.tr,
middleText: '',
titleStyle: AppStyle.title,
confirm: MyElevatedButton(
title: 'Ok'.tr,
onPressed: () async {
Get.back();
Get.back();
await refreshCaptainWallet();
}));
} else {
mySnackeBarError(mapRes['message']?.toString() ?? 'Error');
}
} else {
mySnackeBarError('Error processing request'.tr);
}
}
getKazanPercent() async {
var res = await CRUD().get(
link: AppLink.getKazanPercent,
@@ -354,4 +348,110 @@ class CaptainWalletController extends GetxController {
await refreshCaptainWallet();
super.onInit();
}
Future<void> payWithMTNWallet(
BuildContext context, String amount, String currency) async {
try {
final phone = phoneWallet.text.trim();
if (phone.isEmpty) {
Get.defaultDialog(
title: 'Error'.tr, content: Text('Please enter phone number'.tr));
return;
}
Get.dialog(const Center(child: CircularProgressIndicator()),
barrierDismissible: false);
var res = await CRUD().postWalletMtn(
link: AppLink.createMtnInvoice,
payload: {
"amount": amount,
"user_id": box.read(BoxName.driverID).toString(),
"user_type": "driver",
"mtn_phone": phone,
},
);
Get.back(); // close loading
late final Map<String, dynamic> resMap;
if (res is Map<String, dynamic>) {
resMap = res;
} else if (res is String) {
resMap = json.decode(res) as Map<String, dynamic>;
} else {
throw Exception("Unexpected response type");
}
if (resMap['status'] == 'success') {
Get.to(() => PaymentScreenMtn(
invoiceNumber: resMap['invoice_number'],
mtnNumber: resMap['mtn_payment_number'] ?? '---',
amount: double.parse(amount),
));
} else {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(
resMap['message']?.toString() ?? 'Failed to create invoice'.tr),
);
}
} catch (e) {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(title: 'Error'.tr, content: Text(e.toString()));
}
}
Future<void> payWithClickWallet(
BuildContext context, String amount, String currency) async {
try {
final phone = phoneWallet.text.trim();
if (phone.isEmpty) {
Get.defaultDialog(
title: 'Error'.tr, content: Text('Please enter phone number'.tr));
return;
}
Get.dialog(const Center(child: CircularProgressIndicator()),
barrierDismissible: false);
var res = await CRUD().postWalletMtn(
link: AppLink.createCliqInvoice,
payload: {
"amount": amount,
"user_id": box.read(BoxName.driverID).toString(),
"user_type": "driver",
"click_phone": phone,
},
);
Get.back(); // close loading
late final Map<String, dynamic> resMap;
if (res is Map<String, dynamic>) {
resMap = res;
} else if (res is String) {
resMap = json.decode(res) as Map<String, dynamic>;
} else {
throw Exception("Unexpected response type");
}
if (resMap['status'] == 'success') {
Get.to(() => PaymentScreenCliq(
invoiceNumber: resMap['invoice_number'],
cliqAlias: resMap['cliq_alias'] ?? '---',
amount: double.parse(amount),
));
} else {
Get.defaultDialog(
title: 'Error'.tr,
content: Text(
resMap['message']?.toString() ?? 'Failed to create invoice'.tr),
);
}
} catch (e) {
if (Get.isDialogOpen ?? false) Get.back();
Get.defaultDialog(title: 'Error'.tr, content: Text(e.toString()));
}
}
}

View File

@@ -0,0 +1,208 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../constant/links.dart';
import '../../../controller/functions/crud.dart';
class PaymentScreenCliq extends StatefulWidget {
final double amount;
final String invoiceNumber;
final String cliqAlias;
const PaymentScreenCliq({
Key? key,
required this.amount,
required this.invoiceNumber,
required this.cliqAlias,
}) : super(key: key);
@override
State<PaymentScreenCliq> createState() => _PaymentScreenCliqState();
}
class _PaymentScreenCliqState extends State<PaymentScreenCliq> with SingleTickerProviderStateMixin {
Timer? _pollingTimer;
String _status = 'waiting'; // waiting, uploading, verifying, success, error
final TextEditingController _proofController = TextEditingController();
late AnimationController _blinkController;
late Animation<Color?> _colorAnimation;
late Animation<double> _shadowAnimation;
@override
void initState() {
super.initState();
_blinkController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this)..repeat(reverse: true);
_colorAnimation = ColorTween(begin: Colors.red.shade700, end: Colors.red.shade100).animate(_blinkController);
_shadowAnimation = Tween<double>(begin: 2.0, end: 15.0).animate(CurvedAnimation(parent: _blinkController, curve: Curves.easeInOut));
_startPolling();
}
@override
void dispose() {
_pollingTimer?.cancel();
_blinkController.dispose();
_proofController.dispose();
super.dispose();
}
void _startPolling() {
_pollingTimer = Timer.periodic(const Duration(seconds: 5), (timer) async {
if (_status == 'success' || _status == 'verifying') return;
try {
final res = await CRUD().postWallet(link: AppLink.checkCliqStatus, payload: {'invoice_number': widget.invoiceNumber});
if (res != 'failure' && res['status'] == 'success' && res['invoice_status'] == 'completed') {
timer.cancel();
if (mounted) setState(() => _status = 'success');
}
} catch (_) {}
});
}
Future<void> _submitProof() async {
if (_proofController.text.trim().isEmpty) {
Get.snackbar('Error'.tr, 'Please paste the transfer message'.tr, backgroundColor: Colors.red);
return;
}
setState(() => _status = 'verifying');
try {
final res = await CRUD().postWallet(link: AppLink.uploadCliqProof, payload: {
'invoice_number': widget.invoiceNumber,
'proof_text': _proofController.text.trim(),
});
if (res != 'failure' && res['status'] == 'success') {
if (mounted) setState(() => _status = 'success');
} else {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Failed'.tr, content: Text(res['message']?.toString() ?? 'Verification failed'));
}
} catch (e) {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Error'.tr, content: Text('Error uploading proof'.tr));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(title: const Text("Cliq Payment"), centerTitle: true, backgroundColor: Colors.white, foregroundColor: Colors.black),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: _status == 'success' ? _buildSuccessUI() : _buildWaitingUI(),
),
),
);
}
Widget _buildWaitingUI() {
final currencyFormat = NumberFormat.decimalPattern('ar_SY');
return SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
decoration: BoxDecoration(gradient: LinearGradient(colors: [Colors.blue.shade800, Colors.blue.shade600]), borderRadius: BorderRadius.circular(16)),
child: Column(
children: [
const Text("المبلغ المطلوب", style: TextStyle(color: Colors.white70, fontSize: 14)),
const SizedBox(height: 5),
Text("${currencyFormat.format(widget.amount)} ل.س", style: const TextStyle(color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold)),
],
),
),
const SizedBox(height: 25),
AnimatedBuilder(
animation: _blinkController,
builder: (context, child) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: _colorAnimation.value ?? Colors.red, width: 3.0), boxShadow: [BoxShadow(color: (_colorAnimation.value ?? Colors.red).withOpacity(0.4), blurRadius: _shadowAnimation.value, spreadRadius: 2)]),
child: Column(
children: [
const Text("يرجى تحويل المبلغ إلى الاسم المستعار التالي (Alias):", textAlign: TextAlign.center, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 15),
InkWell(
onTap: () {
Clipboard.setData(ClipboardData(text: widget.cliqAlias));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: const Text("تم نسخ الاسم ✅", textAlign: TextAlign.center), backgroundColor: Colors.green.shade600));
},
child: Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(color: Colors.blue.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.blue.shade200)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.cliqAlias, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2.0)),
const Icon(Icons.copy, color: Colors.blue),
],
),
),
),
],
),
);
},
),
const SizedBox(height: 30),
const Text("بعد إتمام التحويل، يرجى نسخ رسالة البنك النصية ولصقها هنا للتحقق التلقائي:", textAlign: TextAlign.center, style: TextStyle(fontSize: 14)),
const SizedBox(height: 10),
TextField(
controller: _proofController,
maxLines: 4,
decoration: InputDecoration(
hintText: "قم بلصق نص رسالة التحويل هنا...",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
filled: true,
fillColor: Colors.white,
),
),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue.shade800, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
onPressed: _status == 'verifying' ? null : _submitProof,
child: _status == 'verifying'
? const CircularProgressIndicator(color: Colors.white)
: const Text("تحقق من الدفع", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold)),
),
),
const SizedBox(height: 20),
const Text("جاري فحص الفاتورة تلقائياً كل 5 ثوانٍ...", style: TextStyle(color: Colors.grey, fontSize: 12)),
],
),
);
}
Widget _buildSuccessUI() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.verified_rounded, color: Colors.green, size: 100),
const SizedBox(height: 20),
const Text("تم الدفع بنجاح!", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16)),
onPressed: () { Get.back(); Get.back(); },
child: const Text("متابعة", style: TextStyle(fontSize: 18)),
),
),
],
);
}
}

View File

@@ -0,0 +1,208 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import '../../../constant/links.dart';
import '../../../controller/functions/crud.dart';
class PaymentScreenMtn extends StatefulWidget {
final double amount;
final String invoiceNumber;
final String mtnNumber;
const PaymentScreenMtn({
Key? key,
required this.amount,
required this.invoiceNumber,
required this.mtnNumber,
}) : super(key: key);
@override
State<PaymentScreenMtn> createState() => _PaymentScreenMtnState();
}
class _PaymentScreenMtnState extends State<PaymentScreenMtn> with SingleTickerProviderStateMixin {
Timer? _pollingTimer;
String _status = 'waiting'; // waiting, uploading, verifying, success, error
final TextEditingController _proofController = TextEditingController();
late AnimationController _blinkController;
late Animation<Color?> _colorAnimation;
late Animation<double> _shadowAnimation;
@override
void initState() {
super.initState();
_blinkController = AnimationController(duration: const Duration(milliseconds: 800), vsync: this)..repeat(reverse: true);
_colorAnimation = ColorTween(begin: Colors.red.shade700, end: Colors.red.shade100).animate(_blinkController);
_shadowAnimation = Tween<double>(begin: 2.0, end: 15.0).animate(CurvedAnimation(parent: _blinkController, curve: Curves.easeInOut));
_startPolling();
}
@override
void dispose() {
_pollingTimer?.cancel();
_blinkController.dispose();
_proofController.dispose();
super.dispose();
}
void _startPolling() {
_pollingTimer = Timer.periodic(const Duration(seconds: 5), (timer) async {
if (_status == 'success' || _status == 'verifying') return;
try {
final res = await CRUD().postWallet(link: AppLink.checkMtnStatus, payload: {'invoice_number': widget.invoiceNumber});
if (res != 'failure' && res['status'] == 'success' && res['invoice_status'] == 'completed') {
timer.cancel();
if (mounted) setState(() => _status = 'success');
}
} catch (_) {}
});
}
Future<void> _submitProof() async {
if (_proofController.text.trim().isEmpty) {
Get.snackbar('Error'.tr, 'Please paste the transfer message'.tr, backgroundColor: Colors.red);
return;
}
setState(() => _status = 'verifying');
try {
final res = await CRUD().postWallet(link: AppLink.uploadMtnProof, payload: {
'invoice_number': widget.invoiceNumber,
'proof_text': _proofController.text.trim(),
});
if (res != 'failure' && res['status'] == 'success') {
if (mounted) setState(() => _status = 'success');
} else {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Failed'.tr, content: Text(res['message']?.toString() ?? 'Verification failed'));
}
} catch (e) {
if (mounted) setState(() => _status = 'error');
Get.defaultDialog(title: 'Error'.tr, content: Text('Error uploading proof'.tr));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[50],
appBar: AppBar(title: const Text("MTN Payment"), centerTitle: true, backgroundColor: Colors.white, foregroundColor: Colors.black),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: _status == 'success' ? _buildSuccessUI() : _buildWaitingUI(),
),
),
);
}
Widget _buildWaitingUI() {
final currencyFormat = NumberFormat.decimalPattern('ar_SY');
return SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 15),
decoration: BoxDecoration(gradient: LinearGradient(colors: [Colors.blue.shade800, Colors.blue.shade600]), borderRadius: BorderRadius.circular(16)),
child: Column(
children: [
const Text("المبلغ المطلوب", style: TextStyle(color: Colors.white70, fontSize: 14)),
const SizedBox(height: 5),
Text("${currencyFormat.format(widget.amount)} ل.س", style: const TextStyle(color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold)),
],
),
),
const SizedBox(height: 25),
AnimatedBuilder(
animation: _blinkController,
builder: (context, child) {
return Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all(color: _colorAnimation.value ?? Colors.red, width: 3.0), boxShadow: [BoxShadow(color: (_colorAnimation.value ?? Colors.red).withOpacity(0.4), blurRadius: _shadowAnimation.value, spreadRadius: 2)]),
child: Column(
children: [
const Text("يرجى تحويل المبلغ إلى الرقم التالي:", textAlign: TextAlign.center, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
const SizedBox(height: 15),
InkWell(
onTap: () {
Clipboard.setData(ClipboardData(text: widget.mtnNumber));
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: const Text("تم نسخ الرقم ✅", textAlign: TextAlign.center), backgroundColor: Colors.green.shade600));
},
child: Container(
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(color: Colors.blue.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.blue.shade200)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(widget.mtnNumber, style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2.0)),
const Icon(Icons.copy, color: Colors.blue),
],
),
),
),
],
),
);
},
),
const SizedBox(height: 30),
const Text("بعد إتمام التحويل، يرجى نسخ رسالة البنك النصية ولصقها هنا للتحقق التلقائي:", textAlign: TextAlign.center, style: TextStyle(fontSize: 14)),
const SizedBox(height: 10),
TextField(
controller: _proofController,
maxLines: 4,
decoration: InputDecoration(
hintText: "قم بلصق نص رسالة التحويل هنا...",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
filled: true,
fillColor: Colors.white,
),
),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.blue.shade800, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12))),
onPressed: _status == 'verifying' ? null : _submitProof,
child: _status == 'verifying'
? const CircularProgressIndicator(color: Colors.white)
: const Text("تحقق من الدفع", style: TextStyle(fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold)),
),
),
const SizedBox(height: 20),
const Text("جاري فحص الفاتورة تلقائياً كل 5 ثوانٍ...", style: TextStyle(color: Colors.grey, fontSize: 12)),
],
),
);
}
Widget _buildSuccessUI() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.verified_rounded, color: Colors.green, size: 100),
const SizedBox(height: 20),
const Text("تم الدفع بنجاح!", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
const SizedBox(height: 40),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16)),
onPressed: () { Get.back(); Get.back(); },
child: const Text("متابعة", style: TextStyle(fontSize: 18)),
),
),
],
);
}
}

View File

@@ -6,6 +6,7 @@ import 'package:siro_driver/views/widgets/mycircular.dart';
import 'package:siro_driver/views/widgets/mydialoug.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_driver/constant/currency.dart';
import '../../../controller/home/payment/captain_wallet_controller.dart';
@@ -93,7 +94,19 @@ class TransferBudgetPage extends StatelessWidget {
width: double.maxFinite,
decoration: AppStyle.boxDecoration1,
child: Text(
"${"amount".tr} ${captainWalletController.amountFromBudgetController.text} ${'LE'.tr}",
"${"amount".tr} ${captainWalletController.amountFromBudgetController.text} ${CurrencyHelper.currency}",
style: AppStyle.title,
textAlign: TextAlign.center,
),
),
const SizedBox(
height: 5,
),
Container(
width: double.maxFinite,
decoration: AppStyle.boxDecoration1,
child: Text(
"${"Transfer Fee".tr}: ${captainWalletController.transferFee} ${CurrencyHelper.currency}",
style: AppStyle.title,
textAlign: TextAlign.center,
),
@@ -106,27 +119,29 @@ class TransferBudgetPage extends StatelessWidget {
? MyElevatedButton(
title: 'Transfer'.tr,
onPressed: () async {
if (double.parse(
captainWalletController
.amountFromBudgetController
.text) <
double.parse(
captainWalletController
.totalAmountVisa) -
5) {
double amount = double.tryParse(captainWalletController.amountFromBudgetController.text) ?? 0.0;
double totalAmount = double.tryParse(captainWalletController.totalAmountVisa) ?? 0.0;
double fee = captainWalletController.transferFee;
double minTransfer = captainWalletController.minTransferAmount;
if (amount < minTransfer) {
MyDialog().getDialog(
"Error".tr,
"${"Minimum transfer amount is".tr} $minTransfer ${CurrencyHelper.currency}", () {
Get.back();
});
} else if (amount > (totalAmount - fee)) {
MyDialog().getDialog(
"Insufficient Balance".tr,
"${"You must leave at least".tr} $fee ${CurrencyHelper.currency} ${"for transfer fees".tr}", () {
Get.back();
});
} else {
await captainWalletController
.addTransferDriversWallet(
'TransferFrom',
'TransferTo',
);
} else {
MyDialog().getDialog(
"You dont have money in your Wallet"
.tr,
"You dont have money in your Wallet or you should less transfer 5 LE to activate"
.tr, () {
Get.back();
});
}
})
: const SizedBox()