import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart'; import '../features/settings/models/app_theme_preset.dart'; import '../models/home_config.dart'; import 'credentials_storage.dart'; /// Сервис для хранения списка "домов" и текущего выбранного. /// Несекретные данные лежат в SharedPreferences, API-ключи -- отдельно. class SettingsService { static const String _homesKey = 'ignis_homes'; static const String _currentHomeKey = 'ignis_current_home_id'; static const String _themeKey = 'ignis_theme_preset'; final CredentialsStorage _credentialsStorage; SettingsService({CredentialsStorage? credentialsStorage}) : _credentialsStorage = credentialsStorage ?? SecureCredentialsStorage(); /// Загрузить все дома Future> getHomes() async { final prefs = await SharedPreferences.getInstance(); final raw = prefs.getString(_homesKey); if (raw == null || raw.isEmpty) return []; final list = jsonDecode(raw) as List; final migrated = await _migrateApiKeysIfNeeded(prefs, list); return migrated.map(HomeConfig.fromJson).toList(); } /// Сохранить весь список домов Future saveHomes(List homes) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString( _homesKey, jsonEncode(homes.map((h) => h.toJson()).toList()), ); } /// Добавить или обновить дом Future upsertHome(HomeConfig home, {String? apiKey}) async { final homes = await getHomes(); final idx = homes.indexWhere((h) => h.id == home.id); if (idx >= 0) { homes[idx] = home; } else { homes.add(home); } if (apiKey != null) { await setHomeApiKey(home.id, apiKey); } await saveHomes(homes); } /// Удалить дом по id Future deleteHome(String id) async { final homes = await getHomes(); homes.removeWhere((h) => h.id == id); await saveHomes(homes); await deleteHomeApiKey(id); // Если удалили текущий -- сбрасываем выбор final currentId = await getCurrentHomeId(); if (currentId == id) { await setCurrentHomeId(homes.isNotEmpty ? homes.first.id : null); } } /// Получить id текущего активного дома Future getCurrentHomeId() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString(_currentHomeKey); } /// Установить текущий дом Future setCurrentHomeId(String? id) async { final prefs = await SharedPreferences.getInstance(); if (id == null) { await prefs.remove(_currentHomeKey); } else { await prefs.setString(_currentHomeKey, id); } } /// Удобный метод: получить текущий HomeConfig или null Future getCurrentHome() async { final homes = await getHomes(); final id = await getCurrentHomeId(); if (id == null && homes.isNotEmpty) return homes.first; try { return homes.firstWhere((h) => h.id == id); } catch (_) { return homes.isNotEmpty ? homes.first : null; } } Future getHomeApiKey(String homeId) => _credentialsStorage.getApiKey(homeId); Future requireHomeApiKey(String homeId) async { final key = await getHomeApiKey(homeId); if (key == null || key.isEmpty) { throw StateError('API key is missing for home $homeId'); } return key; } Future setHomeApiKey(String homeId, String apiKey) => _credentialsStorage.setApiKey(homeId, apiKey); Future deleteHomeApiKey(String homeId) => _credentialsStorage.deleteApiKey(homeId); Future getAppThemePreset() async { final prefs = await SharedPreferences.getInstance(); return AppThemePreset.fromStorageValue(prefs.getString(_themeKey)); } Future setAppThemePreset(AppThemePreset preset) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_themeKey, preset.storageValue); } Future>> _migrateApiKeysIfNeeded( SharedPreferences prefs, List rawList, ) async { var changed = false; final result = >[]; for (final item in rawList) { final map = Map.from(item as Map); final id = map['id']?.toString(); final legacyApiKey = map['apiKey']?.toString(); if (id != null && legacyApiKey != null && legacyApiKey.isNotEmpty) { final existingKey = await getHomeApiKey(id); if (existingKey == null || existingKey.isEmpty) { await setHomeApiKey(id, legacyApiKey); } } if (map.remove('apiKey') != null) { changed = true; } result.add(map); } if (changed) { await prefs.setString(_homesKey, jsonEncode(result)); } return result; } }