import 'dart:convert'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; import 'package:sefer_admin1/constant/links.dart'; import '../../constant/box_name.dart'; import '../../constant/info.dart'; import '../../controller/functions/encrypt_decrypt.dart'; import '../../main.dart'; class AddInvoicePage extends StatefulWidget { const AddInvoicePage({super.key}); @override State createState() => _AddInvoicePageState(); } class _AddInvoicePageState extends State { final GlobalKey _formKey = GlobalKey(); final TextEditingController _itemNameController = TextEditingController(); final TextEditingController _amountController = TextEditingController(); File? _imageFile; bool _isLoading = false; // الألوان المستخدمة في الثيم final Color primaryColor = const Color(0xFF4F46E5); // Indigo final Color secondaryColor = const Color(0xFF818CF8); // Lighter Indigo final Color bgColor = const Color(0xFFF3F4F6); // Light Gray Background String generateInvoiceNumber() { final now = DateTime.now(); return "INV-${now.year}${now.month.toString().padLeft(2, '0')}${now.day.toString().padLeft(2, '0')}-${now.microsecond}"; } Future uploadInvoice() async { if (!_formKey.currentState!.validate()) return; final driverID = '123'; // قيمة افتراضية أو يمكن جلبها من الكونترولر final invoiceNumber = generateInvoiceNumber(); final amount = _amountController.text.trim(); final itemName = _itemNameController.text.trim(); final date = DateTime.now().toIso8601String().split('T').first; setState(() => _isLoading = true); try { // إعداد الترويسة (Headers) final headers = { 'Authorization': 'Bearer ${r(box.read(BoxName.jwt)).split(AppInformation.addd)[0]}', 'X-HMAC-Auth': '${box.read(BoxName.hmac)}', }; final uri = Uri.parse(AppLink.addInvoice); final request = http.MultipartRequest('POST', uri) ..fields['driverID'] = driverID ..fields['invoiceNumber'] = invoiceNumber ..fields['amount'] = amount ..fields['name'] = itemName ..fields['date'] = date ..headers.addAll(headers); // إضافة الصورة إذا وجدت if (_imageFile != null) { final multipartFile = await http.MultipartFile.fromPath( 'image', _imageFile!.path, ); request.files.add(multipartFile); } final response = await request.send(); final respStr = await response.stream.bytesToString(); // محاولة تحليل الاستجابة Map data; try { data = jsonDecode(respStr); } catch (e) { data = {'status': 'error', 'message': 'Invalid server response'}; } if (data['status'] == 'success') { Get.snackbar( 'نجاح', 'تم حفظ الفاتورة بنجاح', backgroundColor: Colors.green.withOpacity(0.1), colorText: Colors.green[800], snackPosition: SnackPosition.TOP, margin: const EdgeInsets.all(10), borderRadius: 20, ); _itemNameController.clear(); _amountController.clear(); setState(() => _imageFile = null); // تأخير بسيط قبل العودة لتحديث الصفحة السابقة Future.delayed(const Duration(seconds: 1), () { Get.back(result: true); }); } else { Get.snackbar( 'تنبيه', data['message'] ?? 'حدث خطأ غير معروف', backgroundColor: Colors.red.withOpacity(0.1), colorText: Colors.red[800], ); } } catch (e) { Get.snackbar( 'خطأ في الاتصال', e.toString(), backgroundColor: Colors.red.withOpacity(0.1), colorText: Colors.red[800], ); } finally { if (mounted) setState(() => _isLoading = false); } } Future pickInvoiceImage() async { final picker = ImagePicker(); final picked = await picker.pickImage(source: ImageSource.gallery); if (picked != null) { setState(() => _imageFile = File(picked.path)); } } @override void dispose() { _itemNameController.dispose(); _amountController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: bgColor, appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, centerTitle: true, title: const Text( 'إضافة فاتورة جديدة', style: TextStyle(color: Color(0xFF1F2937), fontWeight: FontWeight.bold), ), leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Color(0xFF1F2937)), onPressed: () => Get.back(), ), flexibleSpace: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.white, bgColor], ), ), ), ), body: SingleChildScrollView( padding: const EdgeInsets.all(20.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // قسم البيانات الأساسية Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 15, offset: const Offset(0, 5), ), ], ), child: Column( children: [ _buildModernTextField( controller: _itemNameController, label: 'اسم البضاعة / الخدمة', icon: Icons.inventory_2_outlined, hint: 'مثال: صيانة سيارة', ), const SizedBox(height: 20), _buildModernTextField( controller: _amountController, label: 'قيمة الفاتورة (د.أ)', icon: Icons.attach_money, hint: '0.00', isNumber: true, ), ], ), ), const SizedBox(height: 25), // قسم الصورة Text( 'صورة الفاتورة', style: TextStyle( color: Colors.grey[700], fontWeight: FontWeight.bold, fontSize: 16, ), ), const SizedBox(height: 10), InkWell( onTap: pickInvoiceImage, borderRadius: BorderRadius.circular(20), child: Container( height: 200, width: double.infinity, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), border: Border.all( color: _imageFile != null ? primaryColor : Colors.grey.shade300, width: 2, style: _imageFile != null ? BorderStyle.solid : BorderStyle.solid, ), image: _imageFile != null ? DecorationImage( image: FileImage(_imageFile!), fit: BoxFit.cover, ) : null, ), child: _imageFile == null ? Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( padding: const EdgeInsets.all(15), decoration: BoxDecoration( color: primaryColor.withOpacity(0.05), shape: BoxShape.circle, ), child: Icon(Icons.add_a_photo_rounded, size: 40, color: primaryColor), ), const SizedBox(height: 10), Text( 'اضغط لرفع صورة الفاتورة', style: TextStyle( color: Colors.grey[500], fontWeight: FontWeight.w500, ), ), ], ) : Stack( children: [ Positioned( top: 10, right: 10, child: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.white.withOpacity(0.9), shape: BoxShape.circle, ), child: Icon(Icons.edit, color: primaryColor, size: 20), ), ), ], ), ), ), const SizedBox(height: 40), // زر الحفظ SizedBox( height: 55, child: ElevatedButton( onPressed: _isLoading ? null : uploadInvoice, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: EdgeInsets.zero, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), child: Ink( decoration: BoxDecoration( gradient: LinearGradient( colors: _isLoading ? [Colors.grey, Colors.grey] : [primaryColor, secondaryColor], begin: Alignment.centerLeft, end: Alignment.centerRight, ), borderRadius: BorderRadius.circular(15), boxShadow: [ if (!_isLoading) BoxShadow( color: primaryColor.withOpacity(0.4), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Container( alignment: Alignment.center, child: _isLoading ? const SizedBox( width: 24, height: 24, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.save_rounded, color: Colors.white), SizedBox(width: 10), Text( 'حفظ الفاتورة', style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), ], ), ), ), ), ), ], ), ), ), ); } Widget _buildModernTextField({ required TextEditingController controller, required String label, required IconData icon, required String hint, bool isNumber = false, }) { return TextFormField( controller: controller, keyboardType: isNumber ? const TextInputType.numberWithOptions(decimal: true) : TextInputType.text, validator: (val) { if (val == null || val.isEmpty) { return 'هذا الحقل مطلوب'; } return null; }, decoration: InputDecoration( labelText: label, hintText: hint, prefixIcon: Icon(icon, color: primaryColor.withOpacity(0.7)), filled: true, fillColor: Colors.grey[50], border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: Colors.grey.shade200), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: primaryColor, width: 1.5), ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), ), ); } }