import 'dart:async'; import 'dart:io'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:convert'; class ContactLocalNamesService { static final ContactLocalNamesService _instance = ContactLocalNamesService._internal(); factory ContactLocalNamesService() => _instance; ContactLocalNamesService._internal(); final Map> _cache = {}; final _changesController = StreamController.broadcast(); Stream get changes => _changesController.stream; bool _initialized = false; Future initialize() async { if (_initialized) return; try { final prefs = await SharedPreferences.getInstance(); final keys = prefs.getKeys(); for (final key in keys) { if (key.startsWith('contact_')) { final contactIdStr = key.replaceFirst('contact_', ''); final contactId = int.tryParse(contactIdStr); if (contactId != null) { final data = prefs.getString(key); if (data != null) { try { final decoded = jsonDecode(data) as Map; final avatarPath = decoded['avatarPath'] as String?; if (avatarPath != null) { final file = File(avatarPath); if (!await file.exists()) { decoded.remove('avatarPath'); } } _cache[contactId] = decoded; } catch (e) { print( 'Ошибка парсинга локальных данных для контакта $contactId: $e', ); } } } } } _initialized = true; print( '✅ ContactLocalNamesService: загружено ${_cache.length} локальных имен', ); } catch (e) { print('❌ Ошибка инициализации ContactLocalNamesService: $e'); } } Map? getContactData(int contactId) { return _cache[contactId]; } String getDisplayName({ required int contactId, String? originalName, String? originalFirstName, String? originalLastName, }) { final localData = _cache[contactId]; if (localData != null) { final firstName = localData['firstName'] as String?; final lastName = localData['lastName'] as String?; if (firstName != null && firstName.isNotEmpty || lastName != null && lastName.isNotEmpty) { final fullName = '${firstName ?? ''} ${lastName ?? ''}'.trim(); if (fullName.isNotEmpty) { return fullName; } } } if (originalFirstName != null || originalLastName != null) { final fullName = '${originalFirstName ?? ''} ${originalLastName ?? ''}' .trim(); if (fullName.isNotEmpty) { return fullName; } } return originalName ?? 'ID $contactId'; } String? getDisplayDescription({ required int contactId, String? originalDescription, }) { final localData = _cache[contactId]; if (localData != null) { final notes = localData['notes'] as String?; if (notes != null && notes.isNotEmpty) { return notes; } } return originalDescription; } Future saveContactAvatar(File imageFile, int contactId) async { try { final directory = await getApplicationDocumentsDirectory(); final avatarDir = Directory('${directory.path}/contact_avatars'); if (!await avatarDir.exists()) { await avatarDir.create(recursive: true); } final fileName = 'contact_$contactId.jpg'; final savePath = '${avatarDir.path}/$fileName'; await imageFile.copy(savePath); final localData = _cache[contactId] ?? {}; localData['avatarPath'] = savePath; _cache[contactId] = localData; final prefs = await SharedPreferences.getInstance(); final key = 'contact_$contactId'; await prefs.setString(key, jsonEncode(localData)); _changesController.add(contactId); print('✅ Локальный аватар контакта сохранен: $savePath'); return savePath; } catch (e) { print('❌ Ошибка сохранения локального аватара контакта: $e'); return null; } } String? getContactAvatarPath(int contactId) { final localData = _cache[contactId]; if (localData != null) { return localData['avatarPath'] as String?; } return null; } String? getDisplayAvatar({ required int contactId, String? originalAvatarUrl, }) { final localAvatarPath = getContactAvatarPath(contactId); if (localAvatarPath != null) { final file = File(localAvatarPath); if (file.existsSync()) { return 'file://$localAvatarPath'; } else { final localData = _cache[contactId]; if (localData != null) { localData.remove('avatarPath'); _cache[contactId] = localData; } } } return originalAvatarUrl; } Future removeContactAvatar(int contactId) async { try { final localData = _cache[contactId]; if (localData != null) { final avatarPath = localData['avatarPath'] as String?; if (avatarPath != null) { final file = File(avatarPath); if (await file.exists()) { await file.delete(); } } localData.remove('avatarPath'); _cache[contactId] = localData; final prefs = await SharedPreferences.getInstance(); final key = 'contact_$contactId'; await prefs.setString(key, jsonEncode(localData)); _changesController.add(contactId); print('✅ Локальный аватар контакта удален'); } } catch (e) { print('❌ Ошибка удаления локального аватара контакта: $e'); } } Future saveContactData(int contactId, Map data) async { try { final prefs = await SharedPreferences.getInstance(); final key = 'contact_$contactId'; await prefs.setString(key, jsonEncode(data)); _cache[contactId] = data; _changesController.add(contactId); print('✅ Сохранены локальные данные для контакта $contactId'); } catch (e) { print('❌ Ошибка сохранения локальных данных контакта: $e'); } } Future clearContactData(int contactId) async { try { final prefs = await SharedPreferences.getInstance(); final key = 'contact_$contactId'; await prefs.remove(key); _cache.remove(contactId); _changesController.add(contactId); print('✅ Очищены локальные данные для контакта $contactId'); } catch (e) { print('❌ Ошибка очистки локальных данных контакта: $e'); } } void clearCache() { _cache.clear(); } void dispose() { _changesController.close(); } }