ix_sp.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:shared_preferences/shared_preferences.dart';
  4. import 'dart:convert';
  5. import '../../../config/translations/localization_service.dart';
  6. import '../../../utils/crypto.dart';
  7. import '../../../utils/log/logger.dart';
  8. import '../../constants/keys.dart';
  9. import '../models/launch/app_config.dart';
  10. import '../models/launch/groups.dart';
  11. import '../models/launch/launch.dart';
  12. import '../models/launch/upgrade.dart';
  13. import '../models/launch/user.dart';
  14. import '../../modules/home/controllers/home_controller.dart';
  15. import '../../modules/node/controllers/node_controller.dart';
  16. class IXSP {
  17. // prevent making instance
  18. IXSP._();
  19. // get storage
  20. static late SharedPreferences _sharedPreferences;
  21. // STORING KEYS
  22. /// Key for storing the device ID
  23. static const String _deviceIdKey = 'omon_device_id';
  24. static const String _fcmTokenKey = 'fcm_token';
  25. static const String _currentLocalKey = 'current_local';
  26. static const String _lightThemeKey = 'is_theme_light';
  27. static const String _launchGame = 'is_launch_game';
  28. static const String _ignoreVersionKey = 'ignore_version';
  29. static const String _isNewInstallKey = 'is_new_install';
  30. static const String _launchDataKey = 'launch_data';
  31. //记录最后一次是否是地区禁用
  32. static const String _isRegionDisabledKey = 'is_region_disabled';
  33. //记录最后一次是否是用户禁用
  34. static const String _isUserDisabledKey = 'is_user_disabled';
  35. //记录最后一次是否是设备禁用
  36. static const String _isDeviceDisabledKey = 'is_device_disabled';
  37. //记录最后一次上传的性能日志boostSessionId
  38. static const String _lastMetricsLogKey = 'last_metrics_log';
  39. //记录最后一次上传的es日志boostSessionId
  40. static const String _lastESLogKey = 'last_es_log';
  41. //记录是否开启debug log
  42. static const String _enableDebugLogKey = 'enable_debug_log';
  43. //记录是否开启ping 0默认 1开启 2关闭
  44. static const String _enablePingModeKey = 'enable_ping_mode';
  45. /// init get storage services
  46. static Future<void> init() async {
  47. _sharedPreferences = await SharedPreferences.getInstance();
  48. }
  49. static setStorage(SharedPreferences sharedPreferences) {
  50. _sharedPreferences = sharedPreferences;
  51. }
  52. /// set theme current type as light theme
  53. static Future<void> setThemeIsLight(bool lightTheme) =>
  54. _sharedPreferences.setBool(_lightThemeKey, lightTheme);
  55. /// get if the current theme type is light
  56. static bool getThemeIsLight() =>
  57. _sharedPreferences.getBool(_lightThemeKey) ??
  58. true; // todo set the default theme (true for light, false for dark)
  59. /// save current locale
  60. static Future<void> setCurrentLanguage(String languageCode) =>
  61. _sharedPreferences.setString(_currentLocalKey, languageCode);
  62. /// get current locale
  63. static Locale getCurrentLocal() {
  64. String? langCode = _sharedPreferences.getString(_currentLocalKey);
  65. // default language is english
  66. if (langCode == null) {
  67. return LocalizationService.defaultLanguage;
  68. }
  69. return LocalizationService.supportedLanguages[langCode]!;
  70. }
  71. /// save generated fcm token
  72. static Future<void> setFcmToken(String token) =>
  73. _sharedPreferences.setString(_fcmTokenKey, token);
  74. /// get authorization token
  75. static String getFcmToken() =>
  76. _sharedPreferences.getString(_fcmTokenKey) ?? '';
  77. /// set launch game
  78. static Future<void> setLaunchGame(bool isLaunch) =>
  79. _sharedPreferences.setBool(_launchGame, isLaunch);
  80. /// get launch game
  81. static bool getLaunchGame() =>
  82. _sharedPreferences.getBool(_launchGame) ?? false;
  83. /// clear all data from shared pref
  84. static Future<void> clear() async => await _sharedPreferences.clear();
  85. /// Save unique ID to shared preferences
  86. static Future<void> setDeviceId(String deviceId) =>
  87. _sharedPreferences.setString(_deviceIdKey, deviceId);
  88. /// Get unique ID from shared preferences
  89. static String? getDeviceId() => _sharedPreferences.getString(_deviceIdKey);
  90. /// Save ignore version to shared preferences
  91. static Future<void> setIgnoreVersion(int version) =>
  92. _sharedPreferences.setInt(_ignoreVersionKey, version);
  93. /// Get ignore version from shared preferences
  94. static int getIgnoreVersion() =>
  95. _sharedPreferences.getInt(_ignoreVersionKey) ?? 0;
  96. /// Save is new install to shared preferences
  97. static Future<void> setIsNewInstall(bool isNewInstall) =>
  98. _sharedPreferences.setBool(_isNewInstallKey, isNewInstall);
  99. /// Get is new install from shared preferences
  100. static bool getIsNewInstall() =>
  101. _sharedPreferences.getBool(_isNewInstallKey) ?? true;
  102. // 记录最后一次是否是用户禁用
  103. static Future<void> setLastIsUserDisabled(bool isUserDisabled) async {
  104. await _sharedPreferences.setBool(_isUserDisabledKey, isUserDisabled);
  105. }
  106. // 获取最后一次是否是用户禁用
  107. static bool getLastIsUserDisabled() {
  108. return _sharedPreferences.getBool(_isUserDisabledKey) ?? false;
  109. }
  110. // 记录最后一次是否是地区禁用
  111. static Future<void> setLastIsRegionDisabled(bool isRegionDisabled) async {
  112. await _sharedPreferences.setBool(_isRegionDisabledKey, isRegionDisabled);
  113. }
  114. // 获取最后一次是否是地区禁用
  115. static bool getLastIsRegionDisabled() {
  116. return _sharedPreferences.getBool(_isRegionDisabledKey) ?? false;
  117. }
  118. // 记录最后一次是否是设备禁用
  119. static Future<void> setLastIsDeviceDisabled(bool isDeviceDisabled) async {
  120. await _sharedPreferences.setBool(_isDeviceDisabledKey, isDeviceDisabled);
  121. }
  122. // 获取最后一次是否是设备禁用
  123. static bool getLastIsDeviceDisabled() {
  124. return _sharedPreferences.getBool(_isDeviceDisabledKey) ?? false;
  125. }
  126. /// Save last metrics log
  127. static Future<void> setLastMetricsLog(String log) async {
  128. await _sharedPreferences.setString(_lastMetricsLogKey, log);
  129. }
  130. /// Get last metrics log
  131. static String getLastMetricsLog() =>
  132. _sharedPreferences.getString(_lastMetricsLogKey) ?? '';
  133. /// Save last es log
  134. static Future<void> setLastESLog(String log) async {
  135. await _sharedPreferences.setString(_lastESLogKey, log);
  136. }
  137. /// Get last es log
  138. static String getLastESLog() =>
  139. _sharedPreferences.getString(_lastESLogKey) ?? '';
  140. /// Save enable debug log
  141. static Future<void> setEnableDebugLog(bool enable) async {
  142. await _sharedPreferences.setBool(_enableDebugLogKey, enable);
  143. }
  144. /// Get enable debug log
  145. static bool getEnableDebugLog() =>
  146. _sharedPreferences.getBool(_enableDebugLogKey) ?? false;
  147. /// Save enable ping
  148. static Future<void> setEnablePingMode(int model) async {
  149. await _sharedPreferences.setInt(_enablePingModeKey, model);
  150. }
  151. /// Get enable ping
  152. static int getEnablePingMode() =>
  153. _sharedPreferences.getInt(_enablePingModeKey) ?? 0;
  154. //记录当前选中的节点
  155. static const String _selectedLocationKey = 'selected_location';
  156. //记录最近选择的节点列表(最多3个)
  157. static const String _recentLocationsKey = 'recent_locations';
  158. /// 保存当前选中的节点
  159. static Future<void> saveSelectedLocation(
  160. Map<String, dynamic> location,
  161. ) async {
  162. try {
  163. await _sharedPreferences.setString(
  164. _selectedLocationKey,
  165. jsonEncode(location),
  166. );
  167. log('IXSP', 'Selected location saved successfully');
  168. } catch (e) {
  169. log('IXSP', 'Error saving selected location: $e');
  170. }
  171. }
  172. /// 获取当前选中的节点
  173. static Map<String, dynamic>? getSelectedLocation() {
  174. try {
  175. final jsonData = _sharedPreferences.getString(_selectedLocationKey);
  176. if (jsonData == null) {
  177. return null;
  178. }
  179. return jsonDecode(jsonData) as Map<String, dynamic>;
  180. } catch (e) {
  181. log('IXSP', 'Error getting selected location: $e');
  182. return null;
  183. }
  184. }
  185. /// 保存最近选择的节点列表
  186. static Future<void> saveRecentLocations(
  187. List<Map<String, dynamic>> locations,
  188. ) async {
  189. try {
  190. await _sharedPreferences.setString(
  191. _recentLocationsKey,
  192. jsonEncode(locations),
  193. );
  194. log('IXSP', 'Recent locations saved successfully');
  195. } catch (e) {
  196. log('IXSP', 'Error saving recent locations: $e');
  197. }
  198. }
  199. /// 获取最近选择的节点列表
  200. static List<Map<String, dynamic>> getRecentLocations() {
  201. try {
  202. final jsonData = _sharedPreferences.getString(_recentLocationsKey);
  203. if (jsonData == null || jsonData.isEmpty) {
  204. return [];
  205. }
  206. final List<dynamic> list = jsonDecode(jsonData);
  207. return list.map((e) => e as Map<String, dynamic>).toList();
  208. } catch (e) {
  209. log('IXSP', 'Error getting recent locations: $e');
  210. return [];
  211. }
  212. }
  213. /// 保存 Launch 数据
  214. static Future<bool> saveLaunch(Launch launch) async {
  215. try {
  216. // 获取旧的 Launch 数据,用于比较 groups
  217. final oldLaunch = getLaunch();
  218. final oldGroups = oldLaunch?.groups;
  219. final newGroups = launch.groups;
  220. final jsonData = jsonEncode(launch.toJson());
  221. // 保存数据
  222. await _sharedPreferences.setString(
  223. _launchDataKey,
  224. Crypto.encrypt(jsonData, Keys.aesKey, Keys.aesIv),
  225. );
  226. log('IXSP', 'Launch data saved successfully');
  227. // 检查 groups 是否有变化,如果有则通知更新
  228. if (_isGroupsChanged(oldGroups, newGroups)) {
  229. log('IXSP', 'Groups data changed, notifying controllers');
  230. _notifyControllersOnGroupsChanged();
  231. }
  232. return true;
  233. } catch (e) {
  234. log('IXSP', 'Error saving launch data: $e');
  235. return false;
  236. }
  237. }
  238. /// 检查 Groups 数据是否有变化
  239. static bool _isGroupsChanged(Groups? oldGroups, Groups? newGroups) {
  240. // 如果两者都为 null,没有变化
  241. if (oldGroups == null && newGroups == null) return false;
  242. // 如果一个为 null 一个不为 null,有变化
  243. if (oldGroups == null || newGroups == null) return true;
  244. // 比较 JSON 序列化后的字符串
  245. try {
  246. final oldJson = jsonEncode(oldGroups.toJson());
  247. final newJson = jsonEncode(newGroups.toJson());
  248. return oldJson != newJson;
  249. } catch (e) {
  250. log('IXSP', 'Error comparing groups: $e');
  251. return true; // 出错时默认认为有变化
  252. }
  253. }
  254. /// 通知控制器 Groups 数据变化
  255. static void _notifyControllersOnGroupsChanged() {
  256. try {
  257. // 通知 HomeController
  258. if (Get.isRegistered<HomeController>()) {
  259. Get.find<HomeController>().refreshOnLaunchChanged();
  260. }
  261. // 通知 NodeController
  262. if (Get.isRegistered<NodeController>()) {
  263. Get.find<NodeController>().refreshOnLaunchChanged();
  264. }
  265. } catch (e) {
  266. log('IXSP', 'Error notifying controllers: $e');
  267. }
  268. }
  269. /// 获取 Launch 数据
  270. static Launch? getLaunch() {
  271. try {
  272. final jsonData = _sharedPreferences.getString(_launchDataKey);
  273. if (jsonData == null) {
  274. return null;
  275. }
  276. final Map<String, dynamic> map = jsonDecode(
  277. Crypto.decrypt(jsonData, Keys.aesKey, Keys.aesIv),
  278. );
  279. return Launch.fromJson(map);
  280. } catch (e) {
  281. log('IXSP', 'Error getting launch data: $e');
  282. return null;
  283. }
  284. }
  285. /// 获取用户信息
  286. static User? getUser() {
  287. final launch = getLaunch();
  288. return launch?.userConfig;
  289. }
  290. /// 获取app配置
  291. static AppConfig? getAppConfig() {
  292. final launch = getLaunch();
  293. return launch?.appConfig;
  294. }
  295. /// 获取升级信息
  296. static Upgrade? getUpgrade() {
  297. final launch = getLaunch();
  298. return launch?.upgradeConfig;
  299. }
  300. /// 保存用户信息
  301. static Future<void> saveUser(User user) async {
  302. final launch = getLaunch();
  303. final newLaunch = launch!.copyWith(userConfig: user);
  304. await saveLaunch(newLaunch);
  305. }
  306. /// 保存app配置
  307. static Future<void> saveAppConfig(AppConfig appConfig) async {
  308. final launch = getLaunch();
  309. final newLaunch = launch!.copyWith(appConfig: appConfig);
  310. await saveLaunch(newLaunch);
  311. }
  312. /// 保存 Groups 数据
  313. static Future<void> saveGroups(Groups groups) async {
  314. final launch = getLaunch();
  315. final newLaunch = launch!.copyWith(groups: groups);
  316. await saveLaunch(newLaunch);
  317. }
  318. /// 清除 Launch 数据
  319. static Future<bool> clearLaunchData() async {
  320. try {
  321. await _sharedPreferences.remove(_launchDataKey);
  322. log('IXSP', 'Launch data cleared');
  323. return true;
  324. } catch (e) {
  325. log('IXSP', 'Error clearing launch data: $e');
  326. return false;
  327. }
  328. }
  329. /// 通用获取字符串方法
  330. static String? getString(String key) {
  331. return _sharedPreferences.getString(key);
  332. }
  333. /// 通用设置字符串方法
  334. static Future<bool> setString(String key, String value) async {
  335. try {
  336. return await _sharedPreferences.setString(key, value);
  337. } catch (e) {
  338. log('IXSP', 'Error setting string for key $key: $e');
  339. return false;
  340. }
  341. }
  342. }