Update: 2026-06-11 18:22:57
This commit is contained in:
@@ -6,6 +6,9 @@ import 'package:siro_rider/controller/auth/login_controller.dart';
|
||||
import '../../constant/colors.dart';
|
||||
import '../../controller/auth/otp_controller.dart';
|
||||
import '../../controller/local/phone_intel/intl_phone_field.dart';
|
||||
import '../../controller/functions/country_logic.dart';
|
||||
import '../../constant/box_name.dart';
|
||||
import '../../main.dart';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// SHARED DESIGN TOKENS
|
||||
@@ -485,7 +488,7 @@ class _PhoneNumberScreenState extends State<PhoneNumberScreen> {
|
||||
const BorderSide(color: Color(0xFFEF4444), width: 1.5),
|
||||
),
|
||||
),
|
||||
initialCountryCode: 'SY',
|
||||
initialCountryCode: CountryLogic.getCountryPrefix(box.read(BoxName.countryCode) ?? 'Syria'),
|
||||
onChanged: (phone) {
|
||||
_phoneController.text = phone.completeNumber;
|
||||
},
|
||||
|
||||
@@ -9,6 +9,9 @@ import 'package:get/get.dart';
|
||||
import '../../controller/local/phone_intel/intl_phone_field.dart';
|
||||
import '../../print.dart';
|
||||
import '../widgets/mycircular.dart';
|
||||
import '../../controller/functions/country_logic.dart';
|
||||
import '../../../constant/box_name.dart';
|
||||
import '../../../main.dart';
|
||||
// import 'package:intl_phone_field/intl_phone_field.dart';
|
||||
|
||||
class SmsSignupEgypt extends StatelessWidget {
|
||||
@@ -52,7 +55,7 @@ class SmsSignupEgypt extends StatelessWidget {
|
||||
borderSide: BorderSide(),
|
||||
),
|
||||
),
|
||||
initialCountryCode: 'EG',
|
||||
initialCountryCode: CountryLogic.getCountryPrefix(box.read(BoxName.countryCode) ?? 'Syria'),
|
||||
onChanged: (phone) {
|
||||
// Properly concatenate country code and number
|
||||
registerController.phoneController.text =
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:siro_rider/constant/colors.dart';
|
||||
import 'package:siro_rider/constant/links.dart';
|
||||
import 'package:siro_rider/constant/style.dart';
|
||||
@@ -188,7 +189,7 @@ class ApplyOrderWidget extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'SYP'.tr,
|
||||
CurrencyHelper.currency,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
|
||||
@@ -551,7 +551,7 @@ class Details extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
Text(
|
||||
'Cost for passenger ${controller.totalPassenger.toStringAsFixed(2)} ',
|
||||
'Cost for passenger ${double.parse(controller.totalPassenger.toString()).toStringAsFixed(2)} ',
|
||||
style: AppStyle.title,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:siro_rider/controller/home/map/map_engine_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:siro_rider/constant/box_name.dart';
|
||||
import 'package:siro_rider/constant/colors.dart';
|
||||
@@ -245,7 +247,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
'${_getPassengerPriceText(carTypes[controller.selectedIndex], controller)} ${'SYP'.tr}',
|
||||
'${_getPassengerPriceText(carTypes[controller.selectedIndex], controller)} ${CurrencyHelper.currency}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 13,
|
||||
@@ -413,7 +415,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
),
|
||||
child: FittedBox(
|
||||
child: Text(
|
||||
'${_getPassengerPriceText(carType, controller)} ${'SYP'.tr}',
|
||||
'${_getPassengerPriceText(carType, controller)} ${CurrencyHelper.currency}',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w700,
|
||||
@@ -537,7 +539,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${'You have a negative balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${'SYP'.tr}.',
|
||||
'${'You have a negative balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${CurrencyHelper.currency}.',
|
||||
style: TextStyle(
|
||||
color: Colors.red.shade800,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -557,7 +559,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
String _getPassengerPriceText(
|
||||
CarType carType, RideLifecycleController mapPassengerController) {
|
||||
double rawPrice;
|
||||
String rawPrice;
|
||||
switch (carType.carType) {
|
||||
case 'Comfort':
|
||||
rawPrice = mapPassengerController.totalPassengerComfort;
|
||||
@@ -587,9 +589,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
default:
|
||||
return '...';
|
||||
}
|
||||
final int roundedPrice = rawPrice.round();
|
||||
final formatter = NumberFormat.decimalPattern();
|
||||
return formatter.format(roundedPrice);
|
||||
return rawPrice;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -743,7 +743,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
'${_getPassengerPriceText(carType, mapPassengerController)} ${'SYP'.tr}',
|
||||
'${_getPassengerPriceText(carType, mapPassengerController)} ${CurrencyHelper.currency}',
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w800,
|
||||
@@ -931,7 +931,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
double _getOriginalPrice(
|
||||
String _getOriginalPrice(
|
||||
CarType carType, RideLifecycleController mapPassengerController) {
|
||||
switch (carType.carType) {
|
||||
case 'Comfort':
|
||||
@@ -947,15 +947,11 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
case 'Lady':
|
||||
return mapPassengerController.totalPassengerLady;
|
||||
default:
|
||||
return 0.0;
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildRayehGaiOption(
|
||||
BuildContext context,
|
||||
RideLifecycleController mapPassengerController,
|
||||
String carTypeName,
|
||||
double price) {
|
||||
Widget _buildRayehGaiOption(BuildContext context, RideLifecycleController mapPassengerController, String carTypeName, String price) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
@@ -969,7 +965,7 @@ class CarDetailsTypeToChoose extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(children: [
|
||||
Text(carTypeName.tr),
|
||||
Text(price.toStringAsFixed(0))
|
||||
Text(double.parse(price).toStringAsFixed(0))
|
||||
])),
|
||||
);
|
||||
}
|
||||
@@ -1031,7 +1027,7 @@ class BurcMoney extends StatelessWidget {
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : 'SYP'.tr} ${'due to a previous trip.'.tr}',
|
||||
'${'You have a balance of'.tr} ${passengerWallet.toStringAsFixed(2)} ${box.read(BoxName.countryCode) == 'Egypt' ? 'LE'.tr : CurrencyHelper.currency} ${'due to a previous trip.'.tr}',
|
||||
style: AppStyle.subtitle.copyWith(
|
||||
color: Colors.white,
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:siro_rider/constant/box_name.dart';
|
||||
@@ -80,7 +81,7 @@ class CashConfirmPageShown extends StatelessWidget {
|
||||
icon: Icons.account_balance_wallet_outlined,
|
||||
title: '${AppInformation.appName} Balance'.tr,
|
||||
subtitle:
|
||||
'${'Balance:'.tr} ${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'SYP'.tr}',
|
||||
'${'Balance:'.tr} ${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${CurrencyHelper.currency}',
|
||||
isSelected: paymentCtrl.isWalletChecked,
|
||||
selectedColor: selectedColor,
|
||||
onTap: () =>
|
||||
@@ -107,7 +108,7 @@ class CashConfirmPageShown extends StatelessWidget {
|
||||
final bool isWalletSufficient = (double.tryParse(
|
||||
box.read(BoxName.passengerWalletTotal) ?? '0') ??
|
||||
0) >=
|
||||
controller.totalPassenger;
|
||||
double.parse(controller.totalPassenger.toString());
|
||||
|
||||
// إذا تم اختيار المحفظة والرصيد غير كافٍ
|
||||
if (paymentCtrl.isWalletChecked && !isWalletSufficient) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -7,7 +8,7 @@ import 'package:intl/intl.dart';
|
||||
import '../../../constant/box_name.dart';
|
||||
import '../../../constant/colors.dart';
|
||||
import '../../../constant/links.dart';
|
||||
import '../../../constant/style.dart';
|
||||
import 'package:siro_rider/controller/functions/country_logic.dart';
|
||||
import '../../../controller/functions/audio_record1.dart';
|
||||
import '../../../controller/functions/launch.dart';
|
||||
import '../../../controller/functions/toast.dart';
|
||||
@@ -17,6 +18,7 @@ import '../../../controller/home/map/ride_state.dart';
|
||||
import '../../../controller/profile/profile_controller.dart';
|
||||
import '../../../main.dart';
|
||||
import '../../../views/home/profile/complaint_page.dart';
|
||||
import '../../../controller/functions/country_logic.dart';
|
||||
|
||||
class RideBeginPassenger extends StatelessWidget {
|
||||
const RideBeginPassenger({super.key});
|
||||
@@ -115,7 +117,8 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: AppColor.primaryColor.withValues(alpha: 0.5), width: 1.5),
|
||||
color: AppColor.primaryColor.withValues(alpha: 0.5),
|
||||
width: 1.5),
|
||||
),
|
||||
child: CircleAvatar(
|
||||
radius: 24,
|
||||
@@ -207,7 +210,7 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
color: AppColor.primaryColor,
|
||||
),
|
||||
),
|
||||
Text('SYP',
|
||||
Text(CurrencyHelper.currency,
|
||||
style: TextStyle(fontSize: 9, color: AppColor.grayColor)),
|
||||
],
|
||||
),
|
||||
@@ -240,7 +243,8 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
box.write(BoxName.sosPhonePassenger,
|
||||
profileController.prfoileData['sosPhone']);
|
||||
} else {
|
||||
makePhoneCall('112');
|
||||
makePhoneCall(CountryLogic.getEmergencyNumber(
|
||||
box.read(BoxName.countryCode) ?? 'Syria'));
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -255,13 +259,12 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
// لا يوجد رقم طوارئ — نعرض الديالوج لإدخاله
|
||||
await uiController.shareTripWithFamily();
|
||||
} else {
|
||||
final formattedPhone = uiController.formatSyrianPhoneNumber(
|
||||
phone.toString());
|
||||
final formattedPhone =
|
||||
CountryLogic.formatCurrentCountryPhone(phone.toString());
|
||||
uiController.sendWhatsapp(formattedPhone);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
_compactBtn(
|
||||
icon: Icons.share,
|
||||
label: 'Share'.tr,
|
||||
@@ -287,12 +290,14 @@ class RideBeginPassenger extends StatelessWidget {
|
||||
if (!audioCtx.isRecording) {
|
||||
await audioCtx.startRecording(rideId: controller.rideId);
|
||||
if (context.mounted) {
|
||||
Toast.show(context, 'Start Record'.tr, AppColor.greenColor);
|
||||
Toast.show(
|
||||
context, 'Start Record'.tr, AppColor.greenColor);
|
||||
}
|
||||
} else {
|
||||
await audioCtx.stopRecording();
|
||||
if (context.mounted) {
|
||||
Toast.show(context, 'Record saved'.tr, AppColor.greenColor);
|
||||
Toast.show(
|
||||
context, 'Record saved'.tr, AppColor.greenColor);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:siro_rider/controller/functions/launch.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_font_icons/flutter_font_icons.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../../../controller/functions/country_logic.dart';
|
||||
|
||||
// ... استيراد ملفاتك الأخرى ...
|
||||
import '../../../constant/box_name.dart';
|
||||
@@ -38,7 +40,7 @@ class RideFromStartApp extends StatelessWidget {
|
||||
final driverName = rideData['driverName'] ?? 'Captain'.tr;
|
||||
final driverRate = controller.driverRate;
|
||||
final carType = rideData['carType'] ?? 'Car'.tr;
|
||||
final carModel = controller.model ?? '';
|
||||
final carModel = controller.model;
|
||||
final arrivalTime = box.read(BoxName.arrivalTime) ?? '--:--';
|
||||
|
||||
// تحديد البيانات للعرض
|
||||
@@ -177,7 +179,7 @@ class RideFromStartApp extends StatelessWidget {
|
||||
"Distance".tr),
|
||||
_buildVerticalDivider(),
|
||||
_buildInfoColumn(
|
||||
Icons.attach_money, "$displayPrice SYP", "Price".tr),
|
||||
Icons.attach_money, "$displayPrice ${CurrencyHelper.currency}", "Price".tr),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -213,7 +215,7 @@ class RideFromStartApp extends StatelessWidget {
|
||||
flex: 1,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () =>
|
||||
makePhoneCall(box.read(BoxName.sosPhonePassenger)),
|
||||
makePhoneCall(CountryLogic.getEmergencyNumber(box.read(BoxName.countryCode) ?? 'Syria')),
|
||||
icon: const Icon(Icons.sos, color: Colors.white),
|
||||
label: Text("SOS".tr,
|
||||
style: const TextStyle(color: Colors.white)),
|
||||
|
||||
@@ -14,6 +14,7 @@ import '../../../controller/functions/launch.dart';
|
||||
import '../../../controller/functions/toast.dart';
|
||||
import '../../../controller/home/map/ride_lifecycle_controller.dart';
|
||||
import '../../../controller/home/map/ui_interactions_controller.dart';
|
||||
import '../../../controller/functions/country_logic.dart';
|
||||
|
||||
class VipRideBeginPassenger extends StatelessWidget {
|
||||
const VipRideBeginPassenger({
|
||||
@@ -196,7 +197,7 @@ class VipRideBeginPassenger extends StatelessWidget {
|
||||
profileController.prfoileData['sosPhone']);
|
||||
}
|
||||
} else {
|
||||
makePhoneCall('122');
|
||||
makePhoneCall(CountryLogic.getEmergencyNumber(box.read(BoxName.countryCode) ?? 'Syria'));
|
||||
// box.read(BoxName.sosPhonePassenger));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -153,7 +154,7 @@ class PassengerWallet extends StatelessWidget {
|
||||
.copyWith(color: Colors.white.withOpacity(0.7)),
|
||||
),
|
||||
Text(
|
||||
'${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${'SYP'.tr}',
|
||||
'${box.read(BoxName.passengerWalletTotal) ?? '0.0'} ${CurrencyHelper.currency}',
|
||||
style: AppStyle.headTitle2.copyWith(
|
||||
color: Colors.white,
|
||||
fontSize: 28,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'package:siro_rider/print.dart';
|
||||
import 'package:siro_rider/constant/style.dart';
|
||||
import 'package:siro_rider/controller/functions/encrypt_decrypt.dart';
|
||||
// import 'package:siro_rider/controller/functions/encrypt_decrypt.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
@@ -42,7 +43,7 @@ class PassengerWalletDialog extends StatelessWidget {
|
||||
child: Text(
|
||||
box.read(BoxName.countryCode) == 'Syria'
|
||||
? '10000 ${'LE'.tr}'
|
||||
: '10 ${'SYP'.tr}',
|
||||
: '10 ${CurrencyHelper.currency}',
|
||||
),
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
@@ -55,7 +56,7 @@ class PassengerWalletDialog extends StatelessWidget {
|
||||
child: Text(
|
||||
box.read(BoxName.countryCode) == 'Syria'
|
||||
? '20000 ${'LE'.tr} = 2050 ${'LE'.tr}'
|
||||
: '20 ${'SYP'.tr}',
|
||||
: '20 ${CurrencyHelper.currency}',
|
||||
),
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
@@ -68,7 +69,7 @@ class PassengerWalletDialog extends StatelessWidget {
|
||||
child: Text(
|
||||
box.read(BoxName.countryCode) == 'Syria'
|
||||
? '40000 ${'LE'.tr} = 4150 ${'LE'.tr}'
|
||||
: '40 ${'SYP'.tr}',
|
||||
: '40 ${CurrencyHelper.currency}',
|
||||
),
|
||||
),
|
||||
CupertinoActionSheetAction(
|
||||
@@ -81,7 +82,7 @@ class PassengerWalletDialog extends StatelessWidget {
|
||||
child: Text(
|
||||
box.read(BoxName.countryCode) == 'Syria'
|
||||
? '100000 ${'LE'.tr} = 11000 ${'LE'.tr}'
|
||||
: '50 ${'SYP'.tr}',
|
||||
: '50 ${CurrencyHelper.currency}',
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -130,10 +131,10 @@ void showPaymentBottomSheet(BuildContext context) {
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(15.0)),
|
||||
),
|
||||
builder: (BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return PopScope(
|
||||
canPop: true,
|
||||
onPopInvokedWithResult: (didPop, result) async {
|
||||
Get.back();
|
||||
return false;
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
@@ -154,7 +155,7 @@ void showPaymentBottomSheet(BuildContext context) {
|
||||
controller: controller,
|
||||
amount: 500,
|
||||
bonusAmount: 30,
|
||||
currency: 'SYP'.tr,
|
||||
currency: CurrencyHelper.currency,
|
||||
),
|
||||
|
||||
const SizedBox(height: 8.0),
|
||||
@@ -163,7 +164,7 @@ void showPaymentBottomSheet(BuildContext context) {
|
||||
controller: controller,
|
||||
amount: 1000,
|
||||
bonusAmount: 70,
|
||||
currency: 'SYP'.tr,
|
||||
currency: CurrencyHelper.currency,
|
||||
),
|
||||
|
||||
const SizedBox(height: 8.0),
|
||||
@@ -172,7 +173,7 @@ void showPaymentBottomSheet(BuildContext context) {
|
||||
controller: controller,
|
||||
amount: 2000,
|
||||
bonusAmount: 180,
|
||||
currency: 'SYP'.tr,
|
||||
currency: CurrencyHelper.currency,
|
||||
),
|
||||
|
||||
const SizedBox(height: 8.0),
|
||||
@@ -181,7 +182,7 @@ void showPaymentBottomSheet(BuildContext context) {
|
||||
controller: controller,
|
||||
amount: 5000,
|
||||
bonusAmount: 700,
|
||||
currency: 'SYP'.tr,
|
||||
currency: CurrencyHelper.currency,
|
||||
),
|
||||
|
||||
const SizedBox(height: 16.0),
|
||||
@@ -266,7 +267,7 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
|
||||
// controller.payWithMTNWallet(
|
||||
// context,
|
||||
// controller.selectedAmount.toString(),
|
||||
// 'SYP',
|
||||
// CurrencyHelper.currency,
|
||||
// );
|
||||
// await controller.getPassengerWallet();
|
||||
// controller.isLoading = false;
|
||||
@@ -331,148 +332,215 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
|
||||
// Get.back();
|
||||
// Get.defaultDialog(
|
||||
// barrierDismissible: false,
|
||||
// title: 'Insert Wallet phone number'.tr,
|
||||
// content: Form(
|
||||
// key: controller.formKey,
|
||||
// child: MyTextForm(
|
||||
// controller: controller.walletphoneController,
|
||||
// label: 'Insert Wallet phone number'.tr,
|
||||
// hint: '963941234567',
|
||||
// type: TextInputType.phone)),
|
||||
// confirm: MyElevatedButton(
|
||||
// title: 'OK'.tr,
|
||||
// onPressed: () async {
|
||||
// Get.back();
|
||||
// if (controller.formKey.currentState!.validate()) {
|
||||
// if (controller.selectedAmount != 0) {
|
||||
// controller.isLoading = true;
|
||||
// controller.update();
|
||||
// box.write(BoxName.phoneWallet,
|
||||
// (controller.walletphoneController.text));
|
||||
// Get.back();
|
||||
// await controller.payWithMTNWallet(
|
||||
// context,
|
||||
// controller.selectedAmount.toString(),
|
||||
// 'SYP',
|
||||
// );
|
||||
// await controller.getPassengerWallet();
|
||||
|
||||
// controller.isLoading = false;
|
||||
// controller.update();
|
||||
// } else {
|
||||
// Toast.show(
|
||||
// context,
|
||||
// '⚠️ You need to choose an amount!'.tr,
|
||||
// AppColor.redColor,
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// }));
|
||||
// },
|
||||
// child: Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// Text(
|
||||
// 'Pay by MTN Wallet'.tr,
|
||||
// style: AppStyle.title,
|
||||
// ),
|
||||
// const SizedBox(width: 10),
|
||||
// Image.asset(
|
||||
// 'assets/images/cashMTN.png',
|
||||
// width: 70,
|
||||
// height: 70,
|
||||
// fit: BoxFit.contain,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// )),
|
||||
if (box.read(BoxName.countryCode) == 'Syria')
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: 'Insert Wallet phone number'.tr,
|
||||
content: Form(
|
||||
key: controller.formKey,
|
||||
child: MyTextForm(
|
||||
controller: controller.walletphoneController,
|
||||
label: 'Insert Wallet phone number'.tr,
|
||||
hint: '963941234567',
|
||||
type: TextInputType.phone)),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
if (controller.formKey.currentState!.validate()) {
|
||||
if (controller.selectedAmount != 0) {
|
||||
controller.isLoading = true;
|
||||
controller.update();
|
||||
box.write(BoxName.phoneWallet,
|
||||
(controller.walletphoneController.text));
|
||||
await controller.payWithMTNWallet(
|
||||
context,
|
||||
controller.selectedAmount.toString(),
|
||||
CurrencyHelper.currency,
|
||||
);
|
||||
await controller.getPassengerWallet();
|
||||
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: 'Insert Wallet phone number'.tr,
|
||||
content: Form(
|
||||
key: controller.formKey,
|
||||
child: MyTextForm(
|
||||
controller: controller.walletphoneController,
|
||||
label: 'Insert Wallet phone number'.tr,
|
||||
hint: '963941234567',
|
||||
type: TextInputType.phone)),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
if (controller.formKey.currentState!.validate()) {
|
||||
box.write(BoxName.phoneWallet,
|
||||
controller.walletphoneController.text);
|
||||
await controller.payWithSyriaTelWallet(
|
||||
controller.selectedAmount.toString(), 'SYP');
|
||||
}
|
||||
}));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Pay by Syriatel Wallet'.tr,
|
||||
controller.isLoading = false;
|
||||
controller.update();
|
||||
} else {
|
||||
Toast.show(
|
||||
context,
|
||||
'⚠️ You need to choose an amount!'.tr,
|
||||
AppColor.redColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
}));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Pay by MTN Wallet'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Image.asset(
|
||||
'assets/images/cashMTN.png',
|
||||
width: 70,
|
||||
height: 70,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
|
||||
if (box.read(BoxName.countryCode) == 'Jordan')
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: 'Insert Wallet phone number'.tr,
|
||||
content: Form(
|
||||
key: controller.formKey,
|
||||
child: MyTextForm(
|
||||
controller: controller.walletphoneController,
|
||||
label: 'Insert Wallet phone number'.tr,
|
||||
hint: '962791234567',
|
||||
type: TextInputType.phone)),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
if (controller.formKey.currentState!.validate()) {
|
||||
if (controller.selectedAmount != 0) {
|
||||
controller.isLoading = true;
|
||||
controller.update();
|
||||
box.write(BoxName.phoneWallet,
|
||||
(controller.walletphoneController.text));
|
||||
await controller.payWithClickWallet(
|
||||
context,
|
||||
controller.selectedAmount.toString(),
|
||||
CurrencyHelper.currency,
|
||||
);
|
||||
await controller.getPassengerWallet();
|
||||
|
||||
controller.isLoading = false;
|
||||
controller.update();
|
||||
} else {
|
||||
Toast.show(
|
||||
context,
|
||||
'⚠️ You need to choose an amount!'.tr,
|
||||
AppColor.redColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
}));
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Colors.transparent,
|
||||
),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
'Pay by Cliq'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Image.asset(
|
||||
'assets/images/syriatel.png',
|
||||
width: 70,
|
||||
height: 70,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
// التحقق بالبصمة قبل أي شيء
|
||||
bool isAuthSupported =
|
||||
await LocalAuthentication().isDeviceSupported();
|
||||
trailing: const Icon(Icons.payment, size: 40, color: Colors.green),
|
||||
),
|
||||
)), if (box.read(BoxName.countryCode) == 'Syria')
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
Get.defaultDialog(
|
||||
barrierDismissible: false,
|
||||
title: 'Insert Wallet phone number'.tr,
|
||||
content: Form(
|
||||
key: controller.formKey,
|
||||
child: MyTextForm(
|
||||
controller: controller.walletphoneController,
|
||||
label: 'Insert Wallet phone number'.tr,
|
||||
hint: '963941234567',
|
||||
type: TextInputType.phone)),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'OK'.tr,
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
if (controller.formKey.currentState!.validate()) {
|
||||
box.write(BoxName.phoneWallet,
|
||||
controller.walletphoneController.text);
|
||||
await controller.payWithSyriaTelWallet(
|
||||
controller.selectedAmount.toString(),
|
||||
CurrencyHelper.currency);
|
||||
}
|
||||
}));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Pay by Syriatel Wallet'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Image.asset(
|
||||
'assets/images/syriatel.png',
|
||||
width: 70,
|
||||
height: 70,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
if (box.read(BoxName.countryCode) == 'Syria')
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
// التحقق بالبصمة قبل أي شيء
|
||||
bool isAuthSupported =
|
||||
await LocalAuthentication().isDeviceSupported();
|
||||
|
||||
if (isAuthSupported) {
|
||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||
localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع',
|
||||
);
|
||||
if (isAuthSupported) {
|
||||
bool didAuthenticate =
|
||||
await LocalAuthentication().authenticate(
|
||||
localizedReason: 'استخدم بصمة الإصبع أو الوجه لتأكيد الدفع',
|
||||
);
|
||||
|
||||
if (!didAuthenticate) {
|
||||
Log.print("❌ User did not authenticate with biometrics");
|
||||
return;
|
||||
if (!didAuthenticate) {
|
||||
Log.print("❌ User did not authenticate with biometrics");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// الانتقال مباشرة لإنشاء الفاتورة بعد النجاح بالبصمة
|
||||
Get.to(() => PaymentScreenSmsProvider(
|
||||
amount: double.parse(controller.selectedAmount.toString())));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Pay by Sham Cash'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Image.asset(
|
||||
'assets/images/shamCash.png',
|
||||
width: 70,
|
||||
height: 70,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
// الانتقال مباشرة لإنشاء الفاتورة بعد النجاح بالبصمة
|
||||
Get.to(() => PaymentScreenSmsProvider(
|
||||
amount:
|
||||
double.parse(controller.selectedAmount.toString())));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Pay by Sham Cash'.tr,
|
||||
style: AppStyle.title,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Image.asset(
|
||||
'assets/images/shamCash.png',
|
||||
width: 70,
|
||||
height: 70,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
],
|
||||
cancelButton: CupertinoActionSheetAction(
|
||||
child: Text('Cancel'.tr),
|
||||
@@ -483,4 +551,4 @@ void showPaymentOptions(BuildContext context, PaymentController controller) {
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
208
siro_rider/lib/views/home/my_wallet/payment_screen_cliq.dart
Normal file
208
siro_rider/lib/views/home/my_wallet/payment_screen_cliq.dart
Normal 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)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
208
siro_rider/lib/views/home/my_wallet/payment_screen_mtn.dart
Normal file
208
siro_rider/lib/views/home/my_wallet/payment_screen_mtn.dart
Normal 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)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:siro_rider/constant/currency.dart';
|
||||
import 'dart:math' as math;
|
||||
import 'dart:typed_data';
|
||||
|
||||
@@ -191,7 +192,7 @@ class _HistoryCard extends StatelessWidget {
|
||||
Text('Total Price'.tr,
|
||||
style: AppStyle.title.copyWith(fontSize: 15)),
|
||||
Text(
|
||||
'${ride['price']} ${'SYP'.tr}',
|
||||
'${ride['price']} ${CurrencyHelper.currency}',
|
||||
style: AppStyle.headTitle.copyWith(
|
||||
fontSize: 20, color: AppColor.primaryColor),
|
||||
),
|
||||
@@ -559,7 +560,7 @@ class _RideDetailSheetState extends State<_RideDetailSheet> {
|
||||
color:
|
||||
AppColor.writeColor.withOpacity(0.55))),
|
||||
const SizedBox(height: 2),
|
||||
Text('${ride['price']} ${'SYP'.tr}',
|
||||
Text('${ride['price']} ${CurrencyHelper.currency}',
|
||||
style: AppStyle.headTitle.copyWith(
|
||||
fontSize: 22, color: AppColor.primaryColor)),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user