import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'dart:convert'; import 'package:siro_admin/constant/links.dart'; import 'package:siro_admin/controller/functions/crud.dart'; import 'package:siro_admin/views/widgets/my_textField.dart'; import '../../print.dart'; // ══════════════════════════════════════════════════════════════ // DESIGN TOKENS (same as AdminHomePage) // ══════════════════════════════════════════════════════════════ const Color _bg = Color(0xFF0D1117); const Color _surface = Color(0xFF161B22); const Color _surfaceElevated = Color(0xFF1C2333); const Color _accent = Color(0xFF00D4AA); const Color _danger = Color(0xFFFF5370); const Color _warning = Color(0xFFFFCB6B); const Color _info = Color(0xFF82AAFF); const Color _textPrimary = Color(0xFFE6EDF3); const Color _textSecondary = Color(0xFF7D8590); const Color _divider = Color(0xFF21262D); class PackageUpdateScreen extends StatelessWidget { PackageUpdateScreen({super.key}); final PackageController packageController = Get.put(PackageController()); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: _bg, appBar: _buildAppBar(), body: GetBuilder( builder: (controller) { if (controller.isLoading.value) { return const Center( child: CircularProgressIndicator(color: _accent, strokeWidth: 2), ); } if (controller.packages.isEmpty) { return _buildEmptyState(); } return ListView.separated( padding: const EdgeInsets.fromLTRB(16, 16, 16, 40), itemCount: controller.packages.length, separatorBuilder: (_, __) => const SizedBox(height: 10), itemBuilder: (context, index) { final package = controller.packages[index]; return _buildPackageCard(context, package, controller); }, ); }, ), ); } // ─────────────────────────── APP BAR ─────────────────────────── PreferredSizeWidget _buildAppBar() { return AppBar( backgroundColor: _bg, elevation: 0, surfaceTintColor: Colors.transparent, leading: GestureDetector( onTap: () => Get.back(), child: Container( margin: const EdgeInsets.all(10), decoration: BoxDecoration( color: _surface, borderRadius: BorderRadius.circular(10), border: Border.all(color: _divider), ), child: const Icon(Icons.arrow_back_ios_new_rounded, color: _textSecondary, size: 16), ), ), title: Row( children: [ Container( padding: const EdgeInsets.all(7), decoration: BoxDecoration( color: _accent.withOpacity(0.12), borderRadius: BorderRadius.circular(9), border: Border.all(color: _accent.withOpacity(0.25)), ), child: const Icon(Icons.system_update_rounded, color: _accent, size: 16), ), const SizedBox(width: 10), const Text( 'تحديث التطبيق', style: TextStyle( color: _textPrimary, fontSize: 17, fontWeight: FontWeight.w600, ), ), ], ), actions: [ GestureDetector( onTap: () => packageController.fetchPackages(), child: Container( margin: const EdgeInsets.only(right: 16), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: _surface, borderRadius: BorderRadius.circular(10), border: Border.all(color: _divider), ), child: const Icon(Icons.refresh_rounded, color: _textSecondary, size: 18), ), ), ], bottom: PreferredSize( preferredSize: const Size.fromHeight(1), child: Container(height: 1, color: _divider), ), ); } // ─────────────────────────── PACKAGE CARD ─────────────────────────── Widget _buildPackageCard( BuildContext context, dynamic package, PackageController controller) { final platform = package['platform']?.toString() ?? ''; final isAndroid = platform.toLowerCase().contains('android'); final isIOS = platform.toLowerCase().contains('ios'); final Color platformColor = isAndroid ? const Color(0xFF4CAF50) : isIOS ? _info : _warning; final IconData platformIcon = isAndroid ? Icons.android_rounded : isIOS ? Icons.apple_rounded : Icons.devices_rounded; return Material( color: Colors.transparent, child: InkWell( onTap: () => _showUpdateDialog(context, package, controller), borderRadius: BorderRadius.circular(16), splashColor: _accent.withOpacity(0.06), highlightColor: Colors.transparent, child: Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: _surface, borderRadius: BorderRadius.circular(16), border: Border.all(color: _divider), ), child: Row( children: [ // Platform Icon Container( width: 48, height: 48, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ platformColor.withOpacity(0.20), platformColor.withOpacity(0.06), ], ), borderRadius: BorderRadius.circular(13), border: Border.all(color: platformColor.withOpacity(0.25)), ), child: Icon(platformIcon, color: platformColor, size: 22), ), const SizedBox(width: 14), // Info Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( package['appName']?.toString() ?? '—', style: const TextStyle( color: _textPrimary, fontSize: 14, fontWeight: FontWeight.w600, ), ), const SizedBox(height: 4), Row( children: [ _buildTag(platform, platformColor), const SizedBox(width: 6), _buildVersionBadge( package['version']?.toString() ?? '?'), ], ), ], ), ), // Update button Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), decoration: BoxDecoration( color: _accent.withOpacity(0.10), borderRadius: BorderRadius.circular(10), border: Border.all(color: _accent.withOpacity(0.25)), ), child: Row( mainAxisSize: MainAxisSize.min, children: const [ Icon(Icons.edit_rounded, color: _accent, size: 13), SizedBox(width: 5), Text( 'تعديل', style: TextStyle( color: _accent, fontSize: 11, fontWeight: FontWeight.w600, ), ), ], ), ), ], ), ), ), ); } Widget _buildTag(String label, Color color) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: color.withOpacity(0.10), borderRadius: BorderRadius.circular(6), ), child: Text( label, style: TextStyle( color: color, fontSize: 10, fontWeight: FontWeight.w600, ), ), ); } Widget _buildVersionBadge(String version) { return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: _divider, borderRadius: BorderRadius.circular(6), ), child: Text( 'v$version', style: const TextStyle( color: _textSecondary, fontSize: 10, fontWeight: FontWeight.w500, fontFamily: 'monospace', ), ), ); } // ─────────────────────────── EMPTY STATE ─────────────────────────── Widget _buildEmptyState() { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: _surface, shape: BoxShape.circle, border: Border.all(color: _divider), ), child: const Icon(Icons.inventory_2_outlined, color: _textSecondary, size: 32), ), const SizedBox(height: 16), const Text('لا توجد حزم متاحة', style: TextStyle( color: _textPrimary, fontSize: 15, fontWeight: FontWeight.w600)), const SizedBox(height: 6), const Text('اسحب للأسفل لإعادة التحميل', style: TextStyle(color: _textSecondary, fontSize: 12)), ], ), ); } // ─────────────────────────── UPDATE DIALOG ─────────────────────────── void _showUpdateDialog( BuildContext context, dynamic package, PackageController controller) { controller.versionController.clear(); Get.dialog( Dialog( backgroundColor: Colors.transparent, child: Container( decoration: BoxDecoration( color: _surfaceElevated, borderRadius: BorderRadius.circular(24), border: Border.all(color: _divider), boxShadow: const [ BoxShadow( color: Colors.black54, blurRadius: 30, offset: Offset(0, 12), ), ], ), padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( children: [ Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: _accent.withOpacity(0.12), borderRadius: BorderRadius.circular(12), border: Border.all(color: _accent.withOpacity(0.25)), ), child: const Icon(Icons.system_update_rounded, color: _accent, size: 20), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'تحديث الإصدار', style: TextStyle( color: _textPrimary, fontSize: 16, fontWeight: FontWeight.w700, ), ), Text( package['appName']?.toString() ?? '', style: const TextStyle( color: _textSecondary, fontSize: 11), ), ], ), ), ], ), const SizedBox(height: 20), Container(height: 1, color: _divider), const SizedBox(height: 20), // Current info Row( children: [ _buildInfoChip(Icons.devices_rounded, package['platform']?.toString() ?? '', _info), const SizedBox(width: 8), _buildInfoChip(Icons.tag_rounded, 'الحالي: ${package['version']}', _warning), ], ), const SizedBox(height: 18), // Input label const Text( 'الإصدار الجديد', style: TextStyle( color: _textSecondary, fontSize: 11, fontWeight: FontWeight.w600, letterSpacing: 0.8, ), ), const SizedBox(height: 8), // Text input Container( decoration: BoxDecoration( color: _bg, borderRadius: BorderRadius.circular(12), border: Border.all(color: _divider), ), child: TextField( controller: controller.versionController, keyboardType: const TextInputType.numberWithOptions(decimal: true), style: const TextStyle( color: _textPrimary, fontSize: 15, fontFamily: 'monospace', fontWeight: FontWeight.w600, ), decoration: InputDecoration( hintText: package['version'].toString(), hintStyle: const TextStyle( color: _textSecondary, fontFamily: 'monospace', ), prefixIcon: const Icon(Icons.tag_rounded, color: _accent, size: 18), border: InputBorder.none, contentPadding: const EdgeInsets.symmetric( horizontal: 14, vertical: 14), ), ), ), const SizedBox(height: 24), // Actions Row( children: [ Expanded( child: TextButton( onPressed: () => Get.back(), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: const BorderSide(color: _divider), ), ), child: const Text( 'إلغاء', style: TextStyle(color: _textSecondary, fontSize: 13), ), ), ), const SizedBox(width: 12), Expanded( child: Obx(() => ElevatedButton.icon( icon: controller.isLoading.value ? const SizedBox( width: 14, height: 14, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Icon(Icons.check_rounded, size: 16), label: Text( controller.isLoading.value ? 'جاري...' : 'تحديث', style: const TextStyle(fontSize: 13), ), style: ElevatedButton.styleFrom( backgroundColor: _accent, foregroundColor: _bg, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 0, ), onPressed: controller.isLoading.value ? null : () async { await controller.updatePackages( package['id'].toString(), controller.versionController.text, ); }, )), ), ], ), ], ), ), ), ); } Widget _buildInfoChip(IconData icon, String label, Color color) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: color.withOpacity(0.08), borderRadius: BorderRadius.circular(8), border: Border.all(color: color.withOpacity(0.2)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, color: color, size: 13), const SizedBox(width: 5), Text( label, style: TextStyle( color: color, fontSize: 11, fontWeight: FontWeight.w600, ), ), ], ), ); } } // ══════════════════════════════════════════════════════════════ // CONTROLLER // ══════════════════════════════════════════════════════════════ class PackageController extends GetxController { List packages = []; var isLoading = false.obs; final versionController = TextEditingController(); final formKey = GlobalKey(); @override void onInit() { super.onInit(); fetchPackages(); } fetchPackages() async { isLoading.value = true; var response = await CRUD().get(link: AppLink.getPackages, payload: {}); if (response is String && (response == 'failure' || response == 'token_expired')) { isLoading.value = false; return; } try { var jsonData = response is String ? jsonDecode(response) : response; packages = jsonData['message'] ?? []; Log.print('✅ Decoded packages: ${packages.length} items'); update(); } catch (e) { Log.print('❌ Error parsing packages: $e'); } isLoading.value = false; } updatePackages(String id, String version) async { if (version.trim().isEmpty) { Get.snackbar( 'تنبيه', 'يرجى إدخال رقم الإصدار', backgroundColor: _warning.withOpacity(0.15), colorText: _textPrimary, borderRadius: 12, margin: const EdgeInsets.all(16), icon: const Icon(Icons.warning_rounded, color: _warning), ); return; } isLoading.value = true; var response = await CRUD().post( link: AppLink.updatePackages, payload: {"id": id, "version": version}, ); Log.print('response: $response'); isLoading.value = false; if (response != 'failure') { Get.back(); Get.snackbar( 'تم التحديث', 'تم تحديث الإصدار بنجاح', backgroundColor: _accent.withOpacity(0.15), colorText: _textPrimary, borderRadius: 12, margin: const EdgeInsets.all(16), icon: const Icon(Icons.check_circle_rounded, color: _accent), ); fetchPackages(); } else { Get.snackbar( 'خطأ', 'فشل التحديث، يرجى المحاولة مجدداً', backgroundColor: _danger.withOpacity(0.15), colorText: _textPrimary, borderRadius: 12, margin: const EdgeInsets.all(16), icon: const Icon(Icons.error_rounded, color: _danger), ); } } }