import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; // تأكد من استيراد الملفات الصحيحة حسب مشروع السائق الخاص بك import 'package:sefer_driver/constant/links.dart'; import 'package:sefer_driver/controller/functions/crud.dart'; import '../../../constant/box_name.dart'; import '../../../main.dart'; // import '../../../print.dart'; // إذا كنت تستخدمه // --- خدمة الدفع للسائق (نفس المنطق الخاص بالسائق) --- class PaymentService { final String _baseUrl = "${AppLink.paymentServer}/ride/shamcash"; Future createInvoice({required double amount}) async { final url = "$_baseUrl/create_invoice_shamcash.php"; try { final response = await CRUD().postWallet( link: url, payload: { 'driverID': box.read(BoxName.driverID), // استخدام driverID 'amount': amount.toString(), }, ).timeout(const Duration(seconds: 15)); if (response != 'failure') { final data = response; if (data['status'] == 'success' && data['invoice_number'] != null) { return data['invoice_number'].toString(); } } return null; } catch (e) { return null; } } Future checkInvoiceStatus(String invoiceNumber) async { final url = "$_baseUrl/check_status.php"; try { final response = await CRUD().postWallet(link: url, payload: { 'invoice_number': invoiceNumber, }).timeout(const Duration(seconds: 10)); if (response != 'failure') { final data = response; return data['status'] == 'success' && data['invoice_status'] == 'completed'; } return false; } catch (e) { return false; } } } enum PaymentStatus { creatingInvoice, waitingForPayment, paymentSuccess, paymentTimeout, paymentError } class PaymentScreenSmsProvider extends StatefulWidget { final double amount; final String providerName; final String providerLogo; final String qrImagePath; const PaymentScreenSmsProvider({ super.key, required this.amount, this.providerName = 'شام كاش', this.providerLogo = 'assets/images/shamCash.png', this.qrImagePath = 'assets/images/shamcashsend.png', }); @override _PaymentScreenSmsProviderState createState() => _PaymentScreenSmsProviderState(); } class _PaymentScreenSmsProviderState extends State with SingleTickerProviderStateMixin { final PaymentService _paymentService = PaymentService(); Timer? _pollingTimer; PaymentStatus _status = PaymentStatus.creatingInvoice; String? _invoiceNumber; // العنوان الثابت للدفع (كما في تطبيق الراكب) final String _paymentAddress = "80f23afe40499b02f49966c3340ae0fc"; // متغيرات الأنيميشن (الوميض) late AnimationController _blinkController; late Animation _colorAnimation; late Animation _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(begin: 2.0, end: 15.0).animate( CurvedAnimation(parent: _blinkController, curve: Curves.easeInOut), ); _createAndPollInvoice(); } @override void dispose() { _pollingTimer?.cancel(); _blinkController.dispose(); super.dispose(); } void _createAndPollInvoice() async { setState(() => _status = PaymentStatus.creatingInvoice); final invoiceNumber = await _paymentService.createInvoice(amount: widget.amount); if (invoiceNumber != null && mounted) { setState(() { _invoiceNumber = invoiceNumber; _status = PaymentStatus.waitingForPayment; }); _startPolling(invoiceNumber); } else if (mounted) { setState(() => _status = PaymentStatus.paymentError); } } void _startPolling(String invoiceNumber) { const timeoutDuration = Duration(minutes: 5); var elapsed = Duration.zero; _pollingTimer = Timer.periodic(const Duration(seconds: 5), (timer) async { elapsed += const Duration(seconds: 5); if (elapsed >= timeoutDuration) { timer.cancel(); if (mounted) setState(() => _status = PaymentStatus.paymentTimeout); return; } final isCompleted = await _paymentService.checkInvoiceStatus(invoiceNumber); if (isCompleted && mounted) { timer.cancel(); setState(() => _status = PaymentStatus.paymentSuccess); } }); } Future _onPopInvoked() async { if (_status == PaymentStatus.waitingForPayment) { return (await showDialog( context: context, builder: (context) => AlertDialog( title: const Text('إلغاء العملية؟', textAlign: TextAlign.right), content: const Text( 'الخروج الآن سيؤدي لإلغاء متابعة عملية الدفع.', textAlign: TextAlign.right), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), child: const Text('البقاء')), TextButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('خروج', style: TextStyle(color: Colors.red))), ], ), )) ?? false; } return true; } @override Widget build(BuildContext context) { return WillPopScope( onWillPop: _onPopInvoked, child: Scaffold( backgroundColor: Colors.grey[50], appBar: AppBar( title: Text("دفع عبر ${widget.providerName}"), centerTitle: true, elevation: 0, backgroundColor: Colors.white, foregroundColor: Colors.black, ), body: SafeArea( child: Padding( padding: const EdgeInsets.all(20.0), child: Center(child: _buildContentByStatus()), ), ), ), ); } Widget _buildContentByStatus() { switch (_status) { case PaymentStatus.creatingInvoice: return const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator(), SizedBox(height: 20), Text("جاري إنشاء رقم البيان...", style: TextStyle(fontSize: 16)), ], ); case PaymentStatus.waitingForPayment: return _buildWaitingForPaymentUI(); case PaymentStatus.paymentSuccess: return _buildSuccessUI(); case PaymentStatus.paymentTimeout: case PaymentStatus.paymentError: return _buildErrorUI(); } } Widget _buildWaitingForPaymentUI() { final currencyFormat = NumberFormat.decimalPattern('ar_SY'); final invoiceText = _invoiceNumber ?? '---'; return SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ // 1. المبلغ المطلوب 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), boxShadow: [ BoxShadow( color: Colors.blue.withOpacity(0.25), blurRadius: 15, offset: const Offset(0, 8)) ], ), 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), // 2. رقم البيان (الإطار الأحمر الوامض) 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: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.warning_rounded, color: Colors.red.shade800, size: 28), const SizedBox(width: 8), Text( "هام جداً: لا تنسَ!", style: TextStyle( color: Colors.red.shade900, fontWeight: FontWeight.bold, fontSize: 18), ), ], ), const SizedBox(height: 10), const Text( "يجب نسخ (رقم البيان) هذا ووضعه في تطبيق شام كاش لضمان نجاح العملية.", textAlign: TextAlign.center, style: TextStyle( fontSize: 15, color: Colors.black87, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 15), InkWell( onTap: () { Clipboard.setData(ClipboardData(text: invoiceText)); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text("تم نسخ رقم البيان ✅", textAlign: TextAlign.center), backgroundColor: Colors.red.shade700, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), margin: const EdgeInsets.all(20), ), ); }, borderRadius: BorderRadius.circular(12), child: Container( padding: const EdgeInsets.symmetric( horizontal: 15, vertical: 12), decoration: BoxDecoration( color: Colors.red.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.red.shade200, width: 1), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("رقم البيان (Invoice No)", style: TextStyle( fontSize: 12, color: Colors.grey)), Text(invoiceText, style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, letterSpacing: 2.0, color: Colors.red.shade900)), ], ), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.red.shade100, borderRadius: BorderRadius.circular(8), ), child: Icon(Icons.copy_rounded, color: Colors.red.shade900, size: 24), ), ], ), ), ), ], ), ); }, ), const SizedBox(height: 25), // 3. عنوان الدفع (للتسهيل على السائق) Container( padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text("عنوان الدفع (Payment Address)", style: TextStyle(fontSize: 12, color: Colors.grey)), const SizedBox(height: 8), InkWell( onTap: () { Clipboard.setData(ClipboardData(text: _paymentAddress)); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text("تم نسخ عنوان الدفع ✅", textAlign: TextAlign.center), backgroundColor: Colors.green.shade600, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10)), margin: const EdgeInsets.all(20), ), ); }, child: Row( children: [ Expanded( child: Text( _paymentAddress, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, fontFamily: 'Courier', color: Colors.black87, ), overflow: TextOverflow.ellipsis, ), ), const SizedBox(width: 8), const Icon(Icons.copy, size: 18, color: Colors.grey), ], ), ), ], ), ), const SizedBox(height: 30), // 4. الـ QR Code const Text("امسح الرمز للدفع", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87)), const SizedBox(height: 10), GestureDetector( onTap: () { showDialog( context: context, builder: (ctx) => Dialog( backgroundColor: Colors.transparent, child: InteractiveViewer( child: Image.asset(widget.qrImagePath), ), ), ); }, child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: Colors.grey.shade300), ), child: Image.asset( widget.qrImagePath, width: 150, height: 150, fit: BoxFit.contain, errorBuilder: (c, o, s) => const Icon(Icons.qr_code_2, size: 100, color: Colors.grey), ), ), ), const SizedBox(height: 40), // مؤشر الانتظار const LinearProgressIndicator(backgroundColor: Colors.white), const SizedBox(height: 10), const Text("ننتظر إشعار الدفع تلقائياً...", style: TextStyle(color: Colors.grey, fontSize: 12)), const SizedBox(height: 20), ], ), ); } 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: 10), const Text("تم إضافة الرصيد إلى محفظتك", style: TextStyle(color: Colors.grey)), 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), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12))), onPressed: () => Navigator.of(context).pop(), child: const Text("متابعة", style: TextStyle(fontSize: 18)), ), ), ], ); } Widget _buildErrorUI() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline_rounded, color: Colors.red.shade400, size: 80), const SizedBox(height: 20), Text( _status == PaymentStatus.paymentTimeout ? "انتهى الوقت" : "لم يتم التحقق", style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold), ), const SizedBox(height: 15), const Padding( padding: EdgeInsets.symmetric(horizontal: 30), child: Text( "لم يصلنا إشعار الدفع. هل تأكدت من وضع (رقم البيان) في الملاحظات؟", textAlign: TextAlign.center, style: TextStyle(color: Colors.grey, height: 1.5)), ), const SizedBox(height: 40), SizedBox( width: double.infinity, child: ElevatedButton.icon( style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12))), onPressed: _createAndPollInvoice, icon: const Icon(Icons.refresh), label: const Text("حاول مرة أخرى"), ), ), const SizedBox(height: 15), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text("إلغاء", style: TextStyle(color: Colors.grey)), ) ], ); } }