ix_sp.dart 13 KB

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