import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:get_it/get_it.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../features/auth/cubit/login_cubit.dart'; import '../features/auth/data/auth_repository.dart'; import '../features/settings/cubit/settings_cubit.dart'; import 'api/api_client.dart'; import 'session/session_cubit.dart'; import 'storage/token_store.dart'; final sl = GetIt.instance; /// نقطة الإقفال الوحيدة (docs/23 §5): الميزة المطفأة **لا تُسجَّل**، بدل /// `if` مبعثرة في الشاشات. Future setupInjector() async { final prefs = await SharedPreferences.getInstance(); sl.registerSingleton(prefs); const secure = FlutterSecureStorage( iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock), ); final tokens = TokenStore(secure); await tokens.load(); await _ensureDeviceId(tokens); sl.registerSingleton(tokens); sl.registerSingleton(SettingsCubit(prefs)); // انتهاء الجلسة يصعد من طبقة الشبكة إلى `SessionCubit` مباشرة — الراوتر // يستمع إليه فيخرج المستخدم بلا `BuildContext` في الـinterceptor. sl.registerSingleton( ApiClient.create( tokens: tokens, onSessionExpired: () async => sl().onSessionExpired(), ), ); sl.registerSingleton(AuthRepository(sl(), sl())); sl.registerSingleton(SessionCubit(sl())); // تدفّق الدخول قصير العمر: نسخة جديدة لكل دخول، لا نسخة واحدة أبدية. sl.registerFactory(() => LoginCubit(sl(), sl())); } /// بصمة الجهاز (`x-device-id`) — يفرضها الخادم عند تفعيل /// `AUTH_REQUIRE_DEVICE_BINDING` (docs/38 §8). تُرسَل من الآن كي يُفعَّل /// العَلَم لاحقاً بلا تعديل التطبيق: **أرسل أولاً ثم فعّل الخادم**. Future _ensureDeviceId(TokenStore tokens) async { if (await tokens.deviceId() != null) return; final info = DeviceInfoPlugin(); String? id; try { if (defaultTargetPlatform == TargetPlatform.android) { id = (await info.androidInfo).id; } else if (defaultTargetPlatform == TargetPlatform.iOS) { id = (await info.iosInfo).identifierForVendor; } } catch (_) { // منصّة لا تجيب — المعرّف الفارغ أفضل من إقلاع فاشل. } if (id != null && id.isNotEmpty) await tokens.setDeviceId(id); }