import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:siro_service/constant/box_name.dart'; import 'package:siro_service/controller/functions/crud.dart'; import 'package:siro_service/main.dart'; import 'package:siro_service/print.dart'; /// مدير الجلسة - مسؤول عن مراقبة صلاحية الجلسة /// وتجديدها تلقائياً عند انتهائها class SessionManager extends GetxController { static SessionManager get instance => Get.find(); /// حالة الجلسة الحالية final Rx status = SessionStatus.valid.obs; /// هل يتم تجديد الجلسة حالياً؟ final RxBool isRefreshing = false.obs; /// عدد مرات إعادة المحاولة في حال فشل التجديد static const int _maxRetries = 3; @override void onInit() { super.onInit(); Log.print('🔐 SessionManager initialized'); } /// التحقق من صلاحية الجلسة الحالية SessionStatus checkSessionValidity() { try { final token = box.read(BoxName.jwt)?.toString() ?? ''; if (token.isEmpty) { status.value = SessionStatus.expired; return SessionStatus.expired; } final isValid = CRUD.isJwtValid(token); if (!isValid) { status.value = SessionStatus.expired; return SessionStatus.expired; } status.value = SessionStatus.valid; return SessionStatus.valid; } catch (e) { Log.print('⚠️ Session check error: $e'); return SessionStatus.unknown; } } /// محاولة تجديد الجلسة تلقائياً مع إظهار إشعار للمستخدم Future refreshSession({bool silent = false}) async { // إذا كان التجديد قيد التنفيذ بالفعل، ننتظر if (isRefreshing.value) { Log.print('🔄 Session refresh already in progress, waiting...'); // ننتظر حتى ينتهي التجديد الحالي while (isRefreshing.value) { await Future.delayed(const Duration(milliseconds: 500)); } // نتحقق مرة أخرى بعد انتهاء التجديد final isValid = CRUD.isJwtValid(box.read(BoxName.jwt)?.toString() ?? ''); return isValid; } isRefreshing.value = true; status.value = SessionStatus.refreshing; try { // إظهار إشعار للمستخدم بأن الجلسة تنتهي ويتم تجديدها if (!silent) { _showSessionExpiredNotification(); } // محاولة تجديد الجلسة مع إعادة المحاولة for (int attempt = 1; attempt <= _maxRetries; attempt++) { Log.print('🔄 Session refresh attempt $attempt/$_maxRetries'); await CRUD().getJWT(); // التحقق من نجاح التجديد final newToken = box.read(BoxName.jwt)?.toString() ?? ''; final isValid = CRUD.isJwtValid(newToken); if (isValid) { status.value = SessionStatus.valid; isRefreshing.value = false; // إشعار النجاح if (!silent) { _showSessionRefreshedNotification(); } Log.print('✅ Session refreshed successfully'); return true; } // إذا فشلت المحاولة، انتظر قبل إعادة المحاولة if (attempt < _maxRetries) { await Future.delayed(Duration(seconds: attempt)); } } // فشلت كل محاولات التجديد status.value = SessionStatus.expired; isRefreshing.value = false; if (!silent) { _showSessionExpiredFinalNotification(); } Log.print('❌ Session refresh failed after $_maxRetries attempts'); return false; } catch (e) { status.value = SessionStatus.expired; isRefreshing.value = false; Log.print('❌ Session refresh error: $e'); if (!silent) { _showSessionExpiredFinalNotification(); } return false; } } /// إشعار للمستخدم: الجلسة على وشك الانتهاء ويتم تجديدها void _showSessionExpiredNotification() { if (!Get.isSnackbarOpen) { Get.snackbar( '⚠️ جاري تجديد الجلسة'.tr, 'انتهت صلاحية الجلسة، يتم تجديدها تلقائياً...'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.orange.withValues(alpha: 0.9), colorText: Colors.white, duration: const Duration(seconds: 3), icon: const Icon( Icons.refresh_rounded, color: Colors.white, size: 28, ), ); } } /// إشعار للمستخدم: تم تجديد الجلسة بنجاح void _showSessionRefreshedNotification() { Get.snackbar( '✅ تم تجديد الجلسة'.tr, 'تم تجديد الجلسة بنجاح، يمكنك متابعة العمل'.tr, snackPosition: SnackPosition.TOP, backgroundColor: Colors.green.withValues(alpha: 0.9), colorText: Colors.white, duration: const Duration(seconds: 2), ); } /// إشعار للمستخدم: فشل تجديد الجلسة - يجب إعادة تسجيل الدخول void _showSessionExpiredFinalNotification() { Get.defaultDialog( title: '🔒 انتهت الجلسة'.tr, titleStyle: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), middleText: 'انتهت صلاحية الجلسة ولم نتمكن من تجديدها تلقائياً.\nيرجى إعادة تسجيل الدخول للمتابعة.' .tr, middleTextStyle: const TextStyle(fontSize: 16), confirm: ElevatedButton( onPressed: () { Get.back(); _forceLogout(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12), ), child: const Text('إعادة تسجيل الدخول'), ), barrierDismissible: false, ); } /// تسجيل الخروج القسري عند فشل تجديد الجلسة void _forceLogout() { try { box.erase(); } catch (_) {} Get.offAllNamed('/login'); } } /// حالات الجلسة enum SessionStatus { /// الجلسة صالحة valid, /// الجلسة منتهية الصلاحية expired, /// جاري تجديد الجلسة refreshing, /// حالة غير معروفة unknown, }