feat: N1d/N2/N3 + قانون فلاتر وإعادة ضبط تطبيق السائق
الباك إند: - تعيين أول أدمن صار يُنشئ المستخدم إن لم يوجد — كان يشترط دخولاً سابقاً، وهي بيضة ودجاجة تمنع الدخول إلى لوحة أي مستأجر جديد أصلاً. - OTP_DEV_MODE كان يفشل مفتوحاً (`!== 'false'`): غياب المتغيّر أو خطأ مطبعي يترك الإنتاج برمز ثابت يفتح كل حساب، ويحرس السحب المالي كذلك. صار `=== 'true'` في الإعداد وفي قارئَيه، مع تحذير عند الإقلاع. - N2: التحقّق من اللوغو عند الرفع (PNG/JPEG · 512+ · مربّع · سقف 5MB) عبر قراءة الترويسة بلا اعتمادية — بدل اكتشاف أيقونة ممطوطة بعد النشر. N3: السكربت يولّد build_config.dart بأعلام const (طبقات docs/22 §1.5)، ويضبط bundle IDs واسم التطبيق والأيقونات/splash، و--build يشغّل Shorebird. فلاتر: - docs/23: قانون مُلزِم للتطبيقين (البنية · Cubit · طبقة الشبكة · الأعلام). - السائق: أُزيل Dart القديم (GetX) مع الإبقاء على الأصيل والإضافات وشهادات التوقيع وShorebird وFirebase الخاص به، وأُعيد هيكلته مطابقاً للراكب. - طبقة الشبكة ترسل x-device-id وتجدّد التوكن عند 401 مرة واحدة فقط. - الحزم موحّدة بين التطبيقين، والـAPI https حصراً في الاثنين. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3ab74a13a8
commit
de4bbd00ac
@@ -1,728 +0,0 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'dart:ui';
|
||||
|
||||
// --- IMPORTS ---
|
||||
import 'package:sefer_driver/constant/links.dart';
|
||||
import 'package:sefer_driver/controller/functions/crud.dart';
|
||||
import 'package:sefer_driver/controller/home/payment/paymob_payout.dart';
|
||||
import 'package:sefer_driver/views/home/my_wallet/bank_account_egypt.dart';
|
||||
import 'package:sefer_driver/views/home/my_wallet/payment_history_driver_page.dart';
|
||||
import 'package:sefer_driver/views/widgets/error_snakbar.dart';
|
||||
import 'package:sefer_driver/views/widgets/mydialoug.dart';
|
||||
import 'package:sefer_driver/constant/box_name.dart';
|
||||
import 'package:sefer_driver/controller/home/payment/captain_wallet_controller.dart';
|
||||
import 'package:sefer_driver/main.dart';
|
||||
import 'package:sefer_driver/views/widgets/elevated_btn.dart';
|
||||
import 'package:sefer_driver/views/widgets/my_textField.dart';
|
||||
import '../../../controller/payment/driver_payment_controller.dart';
|
||||
import 'card_wallet_widget.dart';
|
||||
import 'points_captain.dart';
|
||||
import 'transfer_budget_page.dart';
|
||||
import 'weekly_payment_page.dart';
|
||||
|
||||
// --- COLOR PALETTE (Modern & Professional) ---
|
||||
const kBgColor = Color(0xFFF8F9FA); // خلفية فاتحة مريحة للعين
|
||||
const kPrimaryColor = Color(0xFF0056D2); // أزرق احترافي (يشبه PayPal/Visa)
|
||||
const kCardColor = Colors.white;
|
||||
const kTextPrimary = Color(0xFF2D3436);
|
||||
const kTextSecondary = Color(0xFF636E72);
|
||||
const kGreenSuccess = Color(0xFF00B894);
|
||||
const kRedDanger = Color(0xFFD63031);
|
||||
const kGold = Color(0xFFFDCB6E);
|
||||
|
||||
class WalletCaptainRefactored extends StatelessWidget {
|
||||
WalletCaptainRefactored({super.key});
|
||||
|
||||
final CaptainWalletController captainWalletController =
|
||||
Get.put(CaptainWalletController());
|
||||
|
||||
// تحديد لون حالة النقاط (أخضر = أمان، أحمر = خطر وقف حال)
|
||||
Color _getPointsStatusColor(String pointsStr) {
|
||||
final points = double.tryParse(pointsStr) ?? 0.0;
|
||||
if (points < -300) return kRedDanger;
|
||||
if (points < 0) return Colors.orange;
|
||||
return kGreenSuccess;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
captainWalletController.refreshCaptainWallet();
|
||||
return Scaffold(
|
||||
backgroundColor: kBgColor,
|
||||
appBar: AppBar(
|
||||
backgroundColor: kCardColor,
|
||||
elevation: 0,
|
||||
centerTitle: true,
|
||||
title: const Text(
|
||||
'محفظة الكابتن',
|
||||
style: TextStyle(color: kTextPrimary, fontWeight: FontWeight.bold),
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios_new, color: kTextPrimary),
|
||||
onPressed: () => Get.back(),
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh_rounded, color: kPrimaryColor),
|
||||
onPressed: () => captainWalletController.refreshCaptainWallet(),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: GetBuilder<CaptainWalletController>(
|
||||
builder: (controller) {
|
||||
if (controller.isLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(color: kPrimaryColor));
|
||||
}
|
||||
return SingleChildScrollView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 1. كارت النقاط (حالة الحساب)
|
||||
_buildPointsStatusCard(context, controller),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
const CardTripzWalletDriver(), // Kept as is.
|
||||
const SizedBox(height: 20),
|
||||
// 2. ملخص الرصيد (كاش وفيزا)
|
||||
const Text("ملخص الرصيد",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: kTextPrimary)),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildBalanceCard(
|
||||
title: "المديونية (كاش معك)",
|
||||
amount: controller.totalAmount,
|
||||
icon: Icons.money_off_csred_rounded,
|
||||
color: kRedDanger,
|
||||
subtitle: "مبالغ تم تحصيلها كاش",
|
||||
)),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildBalanceCard(
|
||||
title: "رصيدك بالمحفظة",
|
||||
amount: controller.totalAmountVisa,
|
||||
icon: Icons.account_balance_wallet,
|
||||
color: kGreenSuccess,
|
||||
subtitle: "رصيد قابل للسحب/التحويل",
|
||||
)),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 3. الإجراءات السريعة (Quick Actions)
|
||||
const Text("إجراءات سريعة",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: kTextPrimary)),
|
||||
const SizedBox(height: 10),
|
||||
_buildQuickActionsGrid(context, controller),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 4. إعدادات السحب (Payout Settings) - مهم جداً لمصر
|
||||
_buildPayoutSection(context, controller),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 5. البونص والعروض
|
||||
if (controller.walletDate['message'] != null)
|
||||
_buildPromoSection(controller),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 6. شحن النقاط
|
||||
const Text("باقات شحن النقاط",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: kTextPrimary)),
|
||||
const SizedBox(height: 10),
|
||||
_buildPointsPackages(),
|
||||
|
||||
const SizedBox(height: 30),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- WIDGETS ---
|
||||
|
||||
Widget _buildPointsStatusCard(
|
||||
BuildContext context, CaptainWalletController controller) {
|
||||
Color statusColor =
|
||||
_getPointsStatusColor(controller.totalPoints.toString());
|
||||
bool isBlocked = double.parse(controller.totalPoints.toString()) < -300;
|
||||
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
colors: isBlocked
|
||||
? [kRedDanger, Colors.red.shade300]
|
||||
: [kPrimaryColor, Colors.blue.shade400],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: (isBlocked ? kRedDanger : kPrimaryColor).withOpacity(0.3),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 5))
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("رصيد التشغيل (النقاط)",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withOpacity(0.9), fontSize: 16)),
|
||||
InkWell(
|
||||
onTap: () => _showInfoDialog(context),
|
||||
child: const Icon(Icons.info_outline, color: Colors.white),
|
||||
)
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
controller.totalPoints.toString(),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 40,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(bottom: 8.0),
|
||||
child: Icon(Icons.diamond, color: kGold, size: 24),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.2),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
isBlocked
|
||||
? "حسابك موقوف مؤقتاً - اشحن فوراً"
|
||||
: "حالة الحساب: نشط ✅",
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBalanceCard(
|
||||
{required String title,
|
||||
required String amount,
|
||||
required IconData icon,
|
||||
required Color color,
|
||||
required String subtitle}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(15),
|
||||
decoration: BoxDecoration(
|
||||
color: kCardColor,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.1),
|
||||
blurRadius: 5,
|
||||
offset: const Offset(0, 2))
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 28),
|
||||
const SizedBox(height: 10),
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
color: kTextSecondary,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 5),
|
||||
Text("$amount ج.م",
|
||||
style: TextStyle(
|
||||
color: kTextPrimary,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 5),
|
||||
Text(subtitle,
|
||||
style: TextStyle(color: Colors.grey.shade400, fontSize: 10)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildQuickActionsGrid(
|
||||
BuildContext context, CaptainWalletController controller) {
|
||||
return GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1.1,
|
||||
crossAxisSpacing: 10,
|
||||
mainAxisSpacing: 10,
|
||||
children: [
|
||||
_buildActionButton(
|
||||
icon: Icons.swap_horiz_rounded,
|
||||
label: "تحويل نقاط",
|
||||
color: Colors.orange,
|
||||
onTap: () => _showBuyFromBudgetDialog(controller),
|
||||
),
|
||||
_buildActionButton(
|
||||
icon: Icons.send_to_mobile_rounded,
|
||||
label: "تحويل لكابتن",
|
||||
color: Colors.purple,
|
||||
onTap: () => _handleTransferBudget(controller),
|
||||
),
|
||||
_buildActionButton(
|
||||
icon: Icons.history_rounded,
|
||||
label: "سجل العمليات",
|
||||
color: Colors.blueGrey,
|
||||
onTap: () async {
|
||||
// await Get.put(DriverWalletHistoryController()).getArchivePayment();
|
||||
Get.to(() => const PaymentHistoryDriverPage());
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButton(
|
||||
{required IconData icon,
|
||||
required String label,
|
||||
required Color color,
|
||||
required VoidCallback onTap}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: kCardColor,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: Colors.grey.shade200),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundColor: color.withOpacity(0.1),
|
||||
radius: 22,
|
||||
child: Icon(icon, color: color),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(label,
|
||||
style:
|
||||
const TextStyle(fontSize: 12, fontWeight: FontWeight.bold),
|
||||
textAlign: TextAlign.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPayoutSection(
|
||||
BuildContext context, CaptainWalletController controller) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: kCardColor,
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
border: Border.all(color: kPrimaryColor.withOpacity(0.2)),
|
||||
boxShadow: [
|
||||
BoxShadow(color: kPrimaryColor.withOpacity(0.05), blurRadius: 10)
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: const [
|
||||
Icon(Icons.credit_card_rounded, color: kPrimaryColor),
|
||||
SizedBox(width: 10),
|
||||
Text("إعدادات سحب الرصيد (Payout)",
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const Text(
|
||||
"عشان تقدر تسحب فلوسك، لازم تضيف حساب بنكي أو محفظة إلكترونية.",
|
||||
style: TextStyle(fontSize: 12, color: kTextSecondary)),
|
||||
const SizedBox(height: 15),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: kPrimaryColor,
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10)),
|
||||
),
|
||||
onPressed: () {
|
||||
// استدعاء دالة إضافة الحساب البنكي الموجودة أصلاً
|
||||
addBankCodeEgypt(controller);
|
||||
},
|
||||
icon: const Icon(Icons.add_card, size: 18),
|
||||
label: const Text("إضافة حساب بنكي / محفظة",
|
||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
InkWell(
|
||||
onTap: () async {
|
||||
await Get.put(DriverWalletHistoryController())
|
||||
.getWeekllyArchivePayment();
|
||||
Get.to(() => const WeeklyPaymentPage());
|
||||
},
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: const [
|
||||
Text("عرض الأرباح الأسبوعية",
|
||||
style: TextStyle(
|
||||
color: kPrimaryColor, fontWeight: FontWeight.bold)),
|
||||
Icon(Icons.arrow_forward_ios, size: 12, color: kPrimaryColor),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPromoSection(CaptainWalletController controller) {
|
||||
// التأكد من وجود البيانات لتجنب الأخطاء
|
||||
int morningCount = 0;
|
||||
int afternoonCount = 0;
|
||||
try {
|
||||
// morningCount = controller.walletDate['message'][0]['morning_count'] ?? 0;
|
||||
morningCount = controller.morningCount;
|
||||
afternoonCount = controller.afternoonCount;
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text("بونص اليوم 🎁",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: kTextPrimary)),
|
||||
const SizedBox(height: 10),
|
||||
_buildPromoCard(
|
||||
title: "بونص الصبحية",
|
||||
desc: "اعمل 5 رحلات من 7ص لـ 10ص",
|
||||
current: morningCount,
|
||||
max: 5,
|
||||
color: Colors.orange,
|
||||
onTap: () => controller.addDriverWalletFromPromo('Morning Promo', 50),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
_buildPromoCard(
|
||||
title: "بونص آخر النهار",
|
||||
desc: "اعمل 5 رحلات من 3م لـ 6م",
|
||||
current: afternoonCount,
|
||||
max: 5,
|
||||
color: Colors.indigo,
|
||||
onTap: () =>
|
||||
controller.addDriverWalletFromPromo('Afternoon Promo', 50),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPromoCard(
|
||||
{required String title,
|
||||
required String desc,
|
||||
required int current,
|
||||
required int max,
|
||||
required Color color,
|
||||
required VoidCallback onTap}) {
|
||||
double progress = (current / max).clamp(0.0, 1.0);
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
if (current >= max) {
|
||||
onTap();
|
||||
} else {
|
||||
Get.snackbar("شد حيلك", "لسه فاضلك رحلات عشان تاخد البونص");
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: kCardColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: Colors.grey.shade200),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
value: progress,
|
||||
backgroundColor: Colors.grey.shade200,
|
||||
color: color,
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
Text(desc,
|
||||
style:
|
||||
const TextStyle(fontSize: 11, color: kTextSecondary)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (current >= max)
|
||||
const Icon(Icons.check_circle, color: kGreenSuccess)
|
||||
else
|
||||
Text("$current/$max",
|
||||
style: TextStyle(color: color, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPointsPackages() {
|
||||
return SizedBox(
|
||||
height: 140,
|
||||
child: ListView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
children: [
|
||||
_buildPackageCard(price: 100, points: "100", color: Colors.blueGrey),
|
||||
_buildPackageCard(
|
||||
price: 200,
|
||||
points: "210",
|
||||
color: const Color(0xFFCD7F32)), // Bronze
|
||||
_buildPackageCard(
|
||||
price: 400, points: "435", color: Colors.grey), // Silver
|
||||
_buildPackageCard(
|
||||
price: 1000,
|
||||
points: "1100",
|
||||
color: const Color(0xFFFFD700)), // Gold
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPackageCard(
|
||||
{required double price, required String points, required Color color}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: PointsCaptain(
|
||||
kolor: color,
|
||||
pricePoint: price,
|
||||
countPoint: points,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// --- LOGIC DIALOGS ---
|
||||
|
||||
void _showInfoDialog(BuildContext context) {
|
||||
showCupertinoDialog(
|
||||
context: context,
|
||||
builder: (ctx) => CupertinoAlertDialog(
|
||||
title: const Text('نظام النقاط'),
|
||||
content: const Text(
|
||||
'عشان تستقبل رحلات لازم رصيدك يكون أكبر من -300 جنيه.\nلو الرصيد قل عن كده، التطبيق هيوقف استقبال الطلبات لحد ما تشحن.'),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
child: const Text("تمام"), onPressed: () => Navigator.pop(ctx))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showBuyFromBudgetDialog(CaptainWalletController controller) {
|
||||
Get.defaultDialog(
|
||||
title: 'تحويل من المحفظة للنقاط',
|
||||
content: Form(
|
||||
key: controller.formKey,
|
||||
child: Column(
|
||||
children: [
|
||||
Text("رصيدك الحالي بالمحفظة: ${controller.totalAmountVisa} ج.م",
|
||||
style: const TextStyle(
|
||||
color: kGreenSuccess, fontWeight: FontWeight.bold)),
|
||||
const SizedBox(height: 15),
|
||||
MyTextForm(
|
||||
controller: controller.amountFromBudgetController,
|
||||
label: 'المبلغ المراد تحويله',
|
||||
hint: 'أدخل المبلغ',
|
||||
type: TextInputType.number,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'تأكيد التحويل',
|
||||
onPressed: () async {
|
||||
await _authenticateAndExecute(() async {
|
||||
if (double.parse(controller.amountFromBudgetController.text) <=
|
||||
double.parse(controller.totalAmountVisa.toString())) {
|
||||
await controller.payFromBudget();
|
||||
} else {
|
||||
Get.back();
|
||||
mySnackeBarError('رصيد المحفظة غير كافي للعملية');
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
cancel:
|
||||
TextButton(onPressed: () => Get.back(), child: const Text("إلغاء")),
|
||||
);
|
||||
}
|
||||
|
||||
void _handleTransferBudget(CaptainWalletController controller) async {
|
||||
await _authenticateAndExecute(() async {
|
||||
if (double.parse(controller.totalAmountVisa) > 15) {
|
||||
Get.to(() => const TransferBudgetPage());
|
||||
} else {
|
||||
mySnackeBarError("رصيد محفظتك لا يكفي للتحويل (الحد الأدنى 15 ج.م)");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _authenticateAndExecute(Function onSuccess) async {
|
||||
bool isAvailable = await LocalAuthentication().isDeviceSupported();
|
||||
if (isAvailable) {
|
||||
bool didAuthenticate = await LocalAuthentication().authenticate(
|
||||
localizedReason: 'يرجى استخدام البصمة لتأكيد العملية المالية',
|
||||
options: const AuthenticationOptions(
|
||||
biometricOnly: true, sensitiveTransaction: true),
|
||||
);
|
||||
if (didAuthenticate) {
|
||||
onSuccess();
|
||||
} else {
|
||||
MyDialog().getDialog(
|
||||
'فشل التحقق', 'لم يتم التعرف على البصمة', () => Get.back());
|
||||
}
|
||||
} else {
|
||||
// في حالة عدم وجود بصمة، يمكن تنفيذ العملية مباشرة أو طلب كلمة مرور (حسب رغبتك)
|
||||
// هنا سننفذها للتسهيل
|
||||
// onSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- الدوال القديمة (كما هي للإبقاء على اللوجيك) ---
|
||||
|
||||
Future<dynamic> addBankCodeEgypt(
|
||||
CaptainWalletController captainWalletController) {
|
||||
return Get.defaultDialog(
|
||||
title: "بيانات السحب (Payout Info)",
|
||||
content: Form(
|
||||
key: captainWalletController.formKeyAccount,
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
"أدخل بيانات حسابك البنكي أو المحفظة لاستقبال أرباحك الأسبوعية",
|
||||
textAlign: TextAlign.center),
|
||||
const SizedBox(height: 15),
|
||||
MyTextForm(
|
||||
controller: captainWalletController.cardBank,
|
||||
label: "رقم الحساب / المحفظة / الآيبان",
|
||||
hint: 'مثال: 010xxxxxxx أو رقم الحساب',
|
||||
type: TextInputType.number,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
BankDropdown() // تأكد من أن هذا الودجت يعرض البنوك والمحافظ المصرية
|
||||
],
|
||||
),
|
||||
),
|
||||
confirm: MyElevatedButton(
|
||||
title: 'حفظ البيانات',
|
||||
onPressed: () async {
|
||||
if (captainWalletController.formKeyAccount.currentState!.validate()) {
|
||||
Get.back();
|
||||
// هنا يتم إرسال البيانات للسيرفر
|
||||
var res =
|
||||
await CRUD().post(link: AppLink.updateAccountBank, payload: {
|
||||
"bankCode": Get.find<BankController>().selectedBank.toString(),
|
||||
"accountBank": captainWalletController.cardBank.text.toString(),
|
||||
"id": box.read(BoxName.driverID).toString()
|
||||
});
|
||||
|
||||
if (res != 'failure') {
|
||||
mySnackbarSuccess('تم حفظ بيانات الدفع بنجاح');
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// الودجت الخاص باختيار المحفظة (فودافون كاش، اتصالات، إلخ)
|
||||
class MyDropDown1 extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Get.put(PaymobPayout());
|
||||
return GetBuilder<PaymobPayout>(builder: (controller) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.grey),
|
||||
),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
isExpanded: true,
|
||||
value: controller.dropdownValue,
|
||||
icon: const Icon(Icons.keyboard_arrow_down_rounded),
|
||||
style: const TextStyle(
|
||||
color: kTextPrimary, fontWeight: FontWeight.bold),
|
||||
onChanged: (String? newValue) {
|
||||
controller.dropdownValue = newValue!;
|
||||
controller.update();
|
||||
},
|
||||
items: <String>[
|
||||
'etisalat',
|
||||
'aman',
|
||||
'orange',
|
||||
'vodafone',
|
||||
'Bank Account'
|
||||
].map<DropdownMenuItem<String>>((String value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value,
|
||||
child: Text(value), // يمكن تعريب الأسماء هنا إذا أردت
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user