import 'package:flutter/material.dart'; import '/data/models/contact_model.dart'; import '/data/repositories/contact_repository.dart'; import '/data/datasources/local_db_service.dart'; import '/domain/services/crypto_service.dart'; class ContactProvider extends ChangeNotifier { final ContactRepository _repository = ContactRepository(); final LocalDbService _localDbService = LocalDbService(); final CryptoService _cryptoService = CryptoService(); List _contacts = []; List _allContacts = []; bool _isLoading = false; bool _isFirstLoad = true; String? _error; int? _currentUserId; List get contacts => _contacts; List get allContacts => _allContacts; bool get isLoading => _isLoading; String? get error => _error; void setCurrentUserId(int? id) { _currentUserId = id; notifyListeners(); } int? getCurrentUserId() { return _currentUserId; } Future loadContacts() async { if (_isFirstLoad) { _isFirstLoad = false; _isLoading = true; } _error = null; notifyListeners(); try { final allContacts = await _repository.fetchChatContacts(); // Фильтруем: исключаем себя (для основного списка - только чаты) _contacts = allContacts .where((contact) => contact.id != _currentUserId) .toList(); _allContacts = _contacts; _isLoading = false; notifyListeners(); // Обогащаем превью последним сообщением из локальной БД, не блокируя UI. _enrichContactsWithLastMessages(); } catch (e) { _error = e.toString(); } finally { // Если ошибка — выходим из состояния загрузки тут. // Если всё ок — `_isLoading` уже сброшен выше, чтобы показать список быстрее. if (_error != null) { _isLoading = false; } notifyListeners(); } } // Метод для получения всех контактов (исключая себя) для нового чата Future loadAllContactsForNewChat() async { _isLoading = true; _error = null; notifyListeners(); try { final allContacts = await _repository.fetchAllUsers(); // Фильтруем только исключение самого себя _allContacts = allContacts .where((contact) => contact.id != _currentUserId) .toList(); } catch (e) { _error = e.toString(); } finally { _isLoading = false; notifyListeners(); } } Future _enrichContactsWithLastMessages() async { final myId = _currentUserId; if (myId == null) return; final myPrivKey = await _cryptoService.getPrivateKey(); final List updated = List.from(_contacts); for (int i = 0; i < updated.length; i++) { final contact = updated[i]; // 1) Если сервер уже прислал lastMessage — попробуем расшифровать превью. if (contact.lastMessage != null && contact.lastMessage!.isNotEmpty && myPrivKey != null && contact.publicKey != null) { try { final sharedSecret = await _cryptoService.deriveSharedSecret( myPrivKey, contact.publicKey!, ); final decrypted = await _cryptoService.decryptMessage( contact.lastMessage!, sharedSecret, ); updated[i] = contact.copyWith(lastMessage: decrypted); } catch (_) { // Если расшифровать не удалось — оставляем как есть, дальше попробуем локальную БД. } } // Если сервер уже отдал и сообщение, и время — не трогаем (контакты уже обогащены). final contactAfterServer = updated[i]; if (contactAfterServer.lastMessage != null && contactAfterServer.lastMessage!.isNotEmpty && contactAfterServer.publicKey == null) { // Чтобы не показывать в списке контактов "ciphertext", если ключа нет. updated[i] = contactAfterServer.copyWith( lastMessage: 'Новое сообщение', ); } final contactAfterServer2 = updated[i]; if (contactAfterServer2.lastMessage != null && contactAfterServer2.lastMessageTime != null) { continue; } final last = await _localDbService.getLastMessage(contact.id, myId); if (last == null) continue; final rawContent = last['content']?.toString(); final rawTimestamp = last['timestamp']?.toString(); final lastTime = rawTimestamp == null ? null : DateTime.tryParse(rawTimestamp); String? preview; if (rawContent != null && rawContent.isNotEmpty) { // Пытаемся расшифровать превью, если есть ключи. try { if (myPrivKey != null && contact.publicKey != null) { final sharedSecret = await _cryptoService.deriveSharedSecret( myPrivKey, contact.publicKey!, ); preview = await _cryptoService.decryptMessage( rawContent, sharedSecret, ); } else { preview = 'Новое сообщение'; } } catch (_) { preview = 'Новое сообщение'; } } updated[i] = contactAfterServer2.copyWith( lastMessage: preview, lastMessageTime: contactAfterServer2.lastMessageTime ?? lastTime, ); } _contacts = updated; _allContacts = updated; notifyListeners(); } }