import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; import '../../../config/translations/localization_service.dart'; import '../../../utils/crypto.dart'; import '../../../utils/log/logger.dart'; import '../../constants/keys.dart'; import '../../constants/sp_keys.dart'; import '../models/banner/banner_list.dart'; import '../models/launch/app_config.dart'; import '../models/launch/groups.dart'; import '../models/launch/launch.dart'; import '../models/launch/upgrade.dart'; import '../models/launch/user.dart'; import '../../modules/home/controllers/home_controller.dart'; import '../../modules/node/controllers/node_controller.dart'; class IXSP { // prevent making instance IXSP._(); // get storage static late SharedPreferences _sharedPreferences; /// init get storage services static Future init() async { _sharedPreferences = await SharedPreferences.getInstance(); } static setStorage(SharedPreferences sharedPreferences) { _sharedPreferences = sharedPreferences; } /// set theme current type as light theme (legacy, for compatibility) static Future setThemeIsLight(bool lightTheme) => _sharedPreferences.setBool(SPKeys.lightTheme, lightTheme); /// get if the current theme type is light (legacy, for compatibility) static bool getThemeIsLight() => _sharedPreferences.getBool(SPKeys.lightTheme) ?? false; // todo set the default theme (true for light, false for dark) /// 主题模式: 'system', 'dark', 'light' static Future setThemeMode(String mode) => _sharedPreferences.setString(SPKeys.themeMode, mode); /// 获取主题模式,默认跟随系统 static String getThemeMode() => _sharedPreferences.getString(SPKeys.themeMode) ?? 'system'; /// save current locale static Future setCurrentLanguage(String languageCode) => _sharedPreferences.setString(SPKeys.currentLocal, languageCode); /// get current locale static Locale getCurrentLocal() { String? langCode = _sharedPreferences.getString(SPKeys.currentLocal); // default language is english if (langCode == null) { return LocalizationService.defaultLanguage; } return LocalizationService.supportedLanguages[langCode]!; } /// save generated fcm token static Future setFcmToken(String token) => _sharedPreferences.setString(SPKeys.fcmToken, token); /// get authorization token static String getFcmToken() => _sharedPreferences.getString(SPKeys.fcmToken) ?? ''; /// set launch game static Future setLaunchGame(bool isLaunch) => _sharedPreferences.setBool(SPKeys.launchGame, isLaunch); /// get launch game static bool getLaunchGame() => _sharedPreferences.getBool(SPKeys.launchGame) ?? false; /// clear all data from shared pref static Future clear() async => await _sharedPreferences.clear(); /// Save unique ID to shared preferences static Future setDeviceId(String deviceId) => _sharedPreferences.setString(SPKeys.deviceId, deviceId); /// Get unique ID from shared preferences static String? getDeviceId() => _sharedPreferences.getString(SPKeys.deviceId); /// Save ignore version to shared preferences static Future setIgnoreVersion(int version) => _sharedPreferences.setInt(SPKeys.ignoreVersion, version); /// Get ignore version from shared preferences static int getIgnoreVersion() => _sharedPreferences.getInt(SPKeys.ignoreVersion) ?? 0; /// Save is new install to shared preferences static Future setIsNewInstall(bool isNewInstall) => _sharedPreferences.setBool(SPKeys.isNewInstall, isNewInstall); /// Get is new install from shared preferences static bool getIsNewInstall() => _sharedPreferences.getBool(SPKeys.isNewInstall) ?? true; // 记录最后一次是否是用户禁用 static Future setLastIsUserDisabled(bool isUserDisabled) async { await _sharedPreferences.setBool(SPKeys.isUserDisabled, isUserDisabled); } // 获取最后一次是否是用户禁用 static bool getLastIsUserDisabled() { return _sharedPreferences.getBool(SPKeys.isUserDisabled) ?? false; } // 记录最后一次是否是地区禁用 static Future setLastIsRegionDisabled(bool isRegionDisabled) async { await _sharedPreferences.setBool(SPKeys.isRegionDisabled, isRegionDisabled); } // 获取最后一次是否是地区禁用 static bool getLastIsRegionDisabled() { return _sharedPreferences.getBool(SPKeys.isRegionDisabled) ?? false; } // 记录最后一次是否是设备禁用 static Future setLastIsDeviceDisabled(bool isDeviceDisabled) async { await _sharedPreferences.setBool(SPKeys.isDeviceDisabled, isDeviceDisabled); } // 获取最后一次是否是设备禁用 static bool getLastIsDeviceDisabled() { return _sharedPreferences.getBool(SPKeys.isDeviceDisabled) ?? false; } /// Save last metrics log static Future setLastMetricsLog(String log) async { await _sharedPreferences.setString(SPKeys.lastMetricsLog, log); } /// Get last metrics log static String getLastMetricsLog() => _sharedPreferences.getString(SPKeys.lastMetricsLog) ?? ''; /// Save last es log static Future setLastESLog(String log) async { await _sharedPreferences.setString(SPKeys.lastESLog, log); } /// Get last es log static String getLastESLog() => _sharedPreferences.getString(SPKeys.lastESLog) ?? ''; /// Save enable debug log static Future setEnableDebugLog(bool enable) async { await _sharedPreferences.setBool(SPKeys.enableDebugLog, enable); } /// Get enable debug log static bool getEnableDebugLog() => _sharedPreferences.getBool(SPKeys.enableDebugLog) ?? false; /// Save enable ping static Future setEnablePingMode(int model) async { await _sharedPreferences.setInt(SPKeys.enablePingMode, model); } /// Get enable ping static int getEnablePingMode() => _sharedPreferences.getInt(SPKeys.enablePingMode) ?? 0; /// 保存当前选中的节点 static Future saveSelectedLocation( Map location, ) async { try { await _sharedPreferences.setString( SPKeys.selectedLocation, jsonEncode(location), ); log('IXSP', 'Selected location saved successfully'); } catch (e) { log('IXSP', 'Error saving selected location: $e'); } } /// 获取当前选中的节点 static Map? getSelectedLocation() { try { final jsonData = _sharedPreferences.getString(SPKeys.selectedLocation); if (jsonData == null) { return null; } return jsonDecode(jsonData) as Map; } catch (e) { log('IXSP', 'Error getting selected location: $e'); return null; } } /// 保存最近选择的节点列表 static Future saveRecentLocations( List> locations, ) async { try { await _sharedPreferences.setString( SPKeys.recentLocations, jsonEncode(locations), ); log('IXSP', 'Recent locations saved successfully'); } catch (e) { log('IXSP', 'Error saving recent locations: $e'); } } /// 获取最近选择的节点列表 static List> getRecentLocations() { try { final jsonData = _sharedPreferences.getString(SPKeys.recentLocations); if (jsonData == null || jsonData.isEmpty) { return []; } final List list = jsonDecode(jsonData); return list.map((e) => e as Map).toList(); } catch (e) { log('IXSP', 'Error getting recent locations: $e'); return []; } } /// 保存 Launch 数据 static Future saveLaunch(Launch launch) async { try { // 获取旧的 Launch 数据,用于比较 groups final oldLaunch = getLaunch(); final oldGroups = oldLaunch?.groups; final newGroups = launch.groups; final jsonData = jsonEncode(launch.toJson()); // 保存数据 await _sharedPreferences.setString( SPKeys.launchData, Crypto.encrypt(jsonData, Keys.aesKey, Keys.aesIv), ); log('IXSP', 'Launch data saved successfully'); // 检查 groups 是否有变化,如果有则通知更新 if (_isGroupsChanged(oldGroups, newGroups)) { log('IXSP', 'Groups data changed, notifying controllers'); _notifyControllersOnGroupsChanged(); } return true; } catch (e) { log('IXSP', 'Error saving launch data: $e'); return false; } } /// 检查 Groups 数据是否有变化 static bool _isGroupsChanged(Groups? oldGroups, Groups? newGroups) { // 如果两者都为 null,没有变化 if (oldGroups == null && newGroups == null) return false; // 如果一个为 null 一个不为 null,有变化 if (oldGroups == null || newGroups == null) return true; // 比较 JSON 序列化后的字符串 try { final oldJson = jsonEncode(oldGroups.toJson()); final newJson = jsonEncode(newGroups.toJson()); return oldJson != newJson; } catch (e) { log('IXSP', 'Error comparing groups: $e'); return true; // 出错时默认认为有变化 } } /// 通知控制器 Groups 数据变化 static void _notifyControllersOnGroupsChanged() { try { // 通知 HomeController if (Get.isRegistered()) { Get.find().refreshOnLaunchChanged(); } // 通知 NodeController if (Get.isRegistered()) { Get.find().refreshOnLaunchChanged(); } } catch (e) { log('IXSP', 'Error notifying controllers: $e'); } } /// 获取 Launch 数据 static Launch? getLaunch() { try { final jsonData = _sharedPreferences.getString(SPKeys.launchData); if (jsonData == null) { return null; } final Map map = jsonDecode( Crypto.decrypt(jsonData, Keys.aesKey, Keys.aesIv), ); return Launch.fromJson(map); } catch (e) { log('IXSP', 'Error getting launch data: $e'); return null; } } /// 获取用户信息 static User? getUser() { final launch = getLaunch(); return launch?.userConfig; } /// 获取app配置 static AppConfig? getAppConfig() { final launch = getLaunch(); return launch?.appConfig; } /// 获取升级信息 static Upgrade? getUpgrade() { final launch = getLaunch(); return launch?.upgradeConfig; } /// 保存用户信息 static Future saveUser(User user) async { final launch = getLaunch(); final newLaunch = launch!.copyWith(userConfig: user); await saveLaunch(newLaunch); } /// 保存app配置 static Future saveAppConfig(AppConfig appConfig) async { final launch = getLaunch(); final newLaunch = launch!.copyWith(appConfig: appConfig); await saveLaunch(newLaunch); } /// 保存 Groups 数据 static Future saveGroups(Groups groups) async { final launch = getLaunch(); final newLaunch = launch!.copyWith(groups: groups); await saveLaunch(newLaunch); } /// 清除 Launch 数据 static Future clearLaunchData() async { try { await _sharedPreferences.remove(SPKeys.launchData); log('IXSP', 'Launch data cleared'); return true; } catch (e) { log('IXSP', 'Error clearing launch data: $e'); return false; } } /// 通用获取字符串方法 static String? getString(String key) { return _sharedPreferences.getString(key); } /// 通用设置字符串方法 static Future setString(String key, String value) async { try { return await _sharedPreferences.setString(key, value); } catch (e) { log('IXSP', 'Error setting string for key $key: $e'); return false; } } /// 保存 Banner 缓存 /// [position] banner 位置类型,如 "boost"、"home" 等 static Future saveBanner(String position, BannerList bannerList) async { try { final key = SPKeys.bannerCacheKey(position); final jsonData = jsonEncode(bannerList.toJson()); await _sharedPreferences.setString(key, jsonData); log('IXSP', 'Banner cache saved for position: $position'); return true; } catch (e) { log('IXSP', 'Error saving banner cache for position $position: $e'); return false; } } /// 获取 Banner 缓存 /// [position] banner 位置类型,如 "boost"、"home" 等 static BannerList? getBanner(String position) { try { final key = SPKeys.bannerCacheKey(position); final jsonData = _sharedPreferences.getString(key); if (jsonData == null) { return null; } final Map map = jsonDecode(jsonData); return BannerList.fromJson(map); } catch (e) { log('IXSP', 'Error getting banner cache for position $position: $e'); return null; } } /// 清除指定位置的 Banner 缓存 static Future clearBanner(String position) async { try { final key = SPKeys.bannerCacheKey(position); await _sharedPreferences.remove(key); log('IXSP', 'Banner cache cleared for position: $position'); return true; } catch (e) { log('IXSP', 'Error clearing banner cache for position $position: $e'); return false; } } }