WidgetConfigManager.ets 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. import preferences from '@ohos.data.preferences';
  2. import { hilog } from '@kit.PerformanceAnalysisKit';
  3. import { WidgetSize, WidgetTheme, WidgetConfig } from './WidgetTypes';
  4. import { ObjectUtils } from './ObjectUtils';
  5. const TAG = 'WidgetConfigManager';
  6. const CONFIG_PREFERENCES_NAME = 'widget_config_prefs';
  7. /**
  8. * 卡片个性化配置接口
  9. */
  10. export interface WidgetPersonalConfig {
  11. // 显示配置
  12. showProgress: boolean;
  13. showCover: boolean;
  14. showAlbum: boolean;
  15. showTime: boolean;
  16. // 主题配置
  17. theme: WidgetTheme;
  18. backgroundColor: string;
  19. textColor: string;
  20. accentColor: string;
  21. // 布局配置
  22. buttonSize: 'small' | 'medium' | 'large';
  23. fontSize: 'small' | 'medium' | 'large';
  24. borderRadius: number;
  25. // 行为配置
  26. autoUpdate: boolean;
  27. updateInterval: number;
  28. clickBehavior: 'play_pause' | 'open_app' | 'open_player';
  29. // 高级配置
  30. enableAnimations: boolean;
  31. enableHapticFeedback: boolean;
  32. enableShadow: boolean;
  33. }
  34. /**
  35. * 用户偏好设置接口
  36. */
  37. export interface UserPreferences {
  38. // 全局偏好
  39. defaultTheme: WidgetTheme;
  40. defaultSize: WidgetSize;
  41. // 同步设置
  42. syncWithMainApp: boolean;
  43. syncThemeColor: boolean;
  44. // 性能设置
  45. enableCache: boolean;
  46. cacheExpiry: number;
  47. // 隐私设置
  48. showSongInfo: boolean;
  49. showArtistInfo: boolean;
  50. showAlbumCover: boolean;
  51. }
  52. /**
  53. * 卡片配置管理器
  54. * 负责卡片个性化设置和用户偏好管理
  55. * 需求: 5.4, 6.3
  56. */
  57. export class WidgetConfigManager {
  58. private static instance: WidgetConfigManager;
  59. private preferencesStore: preferences.Preferences | null = null;
  60. private configCache: Map<string, WidgetPersonalConfig> = new Map();
  61. private userPreferences: UserPreferences | null = null;
  62. /**
  63. * 获取单例实例
  64. */
  65. public static getInstance(): WidgetConfigManager {
  66. if (!WidgetConfigManager.instance) {
  67. WidgetConfigManager.instance = new WidgetConfigManager();
  68. }
  69. return WidgetConfigManager.instance;
  70. }
  71. private constructor() {
  72. this.initPreferences();
  73. hilog.info(0x0000, TAG, 'WidgetConfigManager initialized');
  74. }
  75. /**
  76. * 初始化配置存储
  77. */
  78. private async initPreferences(): Promise<void> {
  79. try {
  80. this.preferencesStore = await preferences.getPreferences(getContext(), CONFIG_PREFERENCES_NAME);
  81. await this.loadUserPreferences();
  82. hilog.info(0x0000, TAG, 'Config preferences initialized successfully');
  83. } catch (error) {
  84. hilog.error(0x0000, TAG, `Failed to initialize config preferences: ${error}`);
  85. }
  86. }
  87. /**
  88. * 获取卡片个性化配置
  89. * @param formId 卡片ID
  90. * @param size 卡片尺寸
  91. * @returns 个性化配置
  92. */
  93. public async getWidgetConfig(formId: string, size: WidgetSize): Promise<WidgetPersonalConfig> {
  94. // 先从缓存获取
  95. const cacheKey = `${formId}_${size}`;
  96. if (this.configCache.has(cacheKey)) {
  97. return this.configCache.get(cacheKey)!;
  98. }
  99. try {
  100. if (!this.preferencesStore) {
  101. await this.initPreferences();
  102. }
  103. const configKey = `config_${formId}`;
  104. const configStr = await this.preferencesStore?.get(configKey, '') as string;
  105. let config: WidgetPersonalConfig;
  106. if (configStr) {
  107. config = JSON.parse(configStr) as WidgetPersonalConfig;
  108. } else {
  109. config = this.getDefaultConfig(size);
  110. }
  111. // 应用主题色彩同步
  112. if (this.userPreferences?.syncThemeColor) {
  113. config = await this.syncThemeColors(config);
  114. }
  115. // 缓存配置
  116. this.configCache.set(cacheKey, config);
  117. hilog.info(0x0000, TAG, `Widget config loaded for form: ${formId}`);
  118. return config;
  119. } catch (error) {
  120. hilog.error(0x0000, TAG, `Failed to get widget config: ${error}`);
  121. return this.getDefaultConfig(size);
  122. }
  123. }
  124. /**
  125. * 保存卡片个性化配置
  126. * @param formId 卡片ID
  127. * @param size 卡片尺寸
  128. * @param config 配置对象
  129. */
  130. public async saveWidgetConfig(formId: string, size: WidgetSize, config: WidgetPersonalConfig): Promise<void> {
  131. try {
  132. if (!this.preferencesStore) {
  133. await this.initPreferences();
  134. }
  135. const configKey = `config_${formId}`;
  136. await this.preferencesStore?.put(configKey, JSON.stringify(config));
  137. await this.preferencesStore?.flush();
  138. // 更新缓存
  139. const cacheKey = `${formId}_${size}`;
  140. this.configCache.set(cacheKey, config);
  141. hilog.info(0x0000, TAG, `Widget config saved for form: ${formId}`);
  142. } catch (error) {
  143. hilog.error(0x0000, TAG, `Failed to save widget config: ${error}`);
  144. }
  145. }
  146. /**
  147. * 获取用户偏好设置
  148. */
  149. public async getUserPreferences(): Promise<UserPreferences> {
  150. if (this.userPreferences) {
  151. return this.userPreferences;
  152. }
  153. await this.loadUserPreferences();
  154. return this.userPreferences || this.getDefaultUserPreferences();
  155. }
  156. /**
  157. * 保存用户偏好设置
  158. * @param preferences 用户偏好
  159. */
  160. public async saveUserPreferences(preferences: UserPreferences): Promise<void> {
  161. try {
  162. if (!this.preferencesStore) {
  163. await this.initPreferences();
  164. }
  165. await this.preferencesStore?.put('user_preferences', JSON.stringify(preferences));
  166. await this.preferencesStore?.flush();
  167. this.userPreferences = preferences;
  168. hilog.info(0x0000, TAG, 'User preferences saved successfully');
  169. } catch (error) {
  170. hilog.error(0x0000, TAG, `Failed to save user preferences: ${error}`);
  171. }
  172. }
  173. /**
  174. * 同步主题色彩
  175. * @param config 当前配置
  176. * @returns 同步后的配置
  177. */
  178. public async syncThemeColors(config: WidgetPersonalConfig): Promise<WidgetPersonalConfig> {
  179. try {
  180. // 从主应用获取主题色彩
  181. const mainAppTheme = await this.getMainAppTheme();
  182. if (mainAppTheme) {
  183. const updatedConfig = ObjectUtils.cloneWidgetConfig(config);
  184. updatedConfig.theme = mainAppTheme.theme;
  185. updatedConfig.backgroundColor = mainAppTheme.backgroundColor;
  186. updatedConfig.textColor = mainAppTheme.textColor;
  187. updatedConfig.accentColor = mainAppTheme.accentColor;
  188. return updatedConfig;
  189. }
  190. } catch (error) {
  191. hilog.error(0x0000, TAG, `Failed to sync theme colors: ${error}`);
  192. }
  193. return config;
  194. }
  195. /**
  196. * 重置卡片配置为默认值
  197. * @param formId 卡片ID
  198. * @param size 卡片尺寸
  199. */
  200. public async resetWidgetConfig(formId: string, size: WidgetSize): Promise<void> {
  201. const defaultConfig = this.getDefaultConfig(size);
  202. await this.saveWidgetConfig(formId, size, defaultConfig);
  203. hilog.info(0x0000, TAG, `Widget config reset to default for form: ${formId}`);
  204. }
  205. /**
  206. * 批量更新所有卡片配置
  207. * @param updateFn 更新函数
  208. */
  209. public async updateAllWidgetConfigs(updateFn: (config: WidgetPersonalConfig) => WidgetPersonalConfig): Promise<void> {
  210. try {
  211. if (!this.preferencesStore) {
  212. await this.initPreferences();
  213. }
  214. const allKeys = await this.preferencesStore?.getAll();
  215. const allKeysRecord: Record<string, Object> = allKeys as Record<string, Object> || {};
  216. const configKeys = Object.keys(allKeysRecord).filter(key => key.startsWith('config_'));
  217. for (let i = 0; i < configKeys.length; i++) {
  218. const key = configKeys[i];
  219. const configStr = allKeysRecord[key] as string;
  220. if (configStr) {
  221. const config = JSON.parse(configStr) as WidgetPersonalConfig;
  222. const updatedConfig = updateFn(config);
  223. await this.preferencesStore?.put(key, JSON.stringify(updatedConfig));
  224. }
  225. }
  226. await this.preferencesStore?.flush();
  227. // 清除缓存以强制重新加载
  228. this.configCache.clear();
  229. hilog.info(0x0000, TAG, `Updated ${configKeys.length} widget configs`);
  230. } catch (error) {
  231. hilog.error(0x0000, TAG, `Failed to update all widget configs: ${error}`);
  232. }
  233. }
  234. /**
  235. * 删除卡片配置
  236. * @param formId 卡片ID
  237. */
  238. public async removeWidgetConfig(formId: string): Promise<void> {
  239. try {
  240. if (!this.preferencesStore) {
  241. await this.initPreferences();
  242. }
  243. const configKey = `config_${formId}`;
  244. await this.preferencesStore?.delete(configKey);
  245. await this.preferencesStore?.flush();
  246. // 清除相关缓存
  247. const keysToRemove: string[] = [];
  248. const cacheKeys = Array.from(this.configCache.keys());
  249. for (let i = 0; i < cacheKeys.length; i++) {
  250. const key = cacheKeys[i];
  251. if (key.startsWith(formId)) {
  252. keysToRemove.push(key);
  253. }
  254. }
  255. for (let i = 0; i < keysToRemove.length; i++) {
  256. this.configCache.delete(keysToRemove[i]);
  257. }
  258. hilog.info(0x0000, TAG, `Widget config removed for form: ${formId}`);
  259. } catch (error) {
  260. hilog.error(0x0000, TAG, `Failed to remove widget config: ${error}`);
  261. }
  262. }
  263. /**
  264. * 获取默认配置
  265. */
  266. private getDefaultConfig(size: WidgetSize): WidgetPersonalConfig {
  267. const baseConfig: WidgetPersonalConfig = {
  268. // 显示配置
  269. showProgress: true,
  270. showCover: true,
  271. showAlbum: true,
  272. showTime: true,
  273. // 主题配置
  274. theme: WidgetTheme.AUTO,
  275. backgroundColor: '#FFFFFF',
  276. textColor: '#E6000000',
  277. accentColor: '#FF007DFF',
  278. // 布局配置
  279. buttonSize: 'medium',
  280. fontSize: 'medium',
  281. borderRadius: 12,
  282. // 行为配置
  283. autoUpdate: true,
  284. updateInterval: 1000,
  285. clickBehavior: 'play_pause',
  286. // 高级配置
  287. enableAnimations: true,
  288. enableHapticFeedback: true,
  289. enableShadow: true
  290. };
  291. // 根据尺寸调整默认配置
  292. if (size === WidgetSize.SMALL) {
  293. const smallConfig = ObjectUtils.cloneWidgetConfig(baseConfig);
  294. smallConfig.showProgress = false;
  295. smallConfig.showCover = false;
  296. smallConfig.showAlbum = false;
  297. smallConfig.showTime = false;
  298. smallConfig.buttonSize = 'small';
  299. smallConfig.fontSize = 'small';
  300. smallConfig.borderRadius = 8;
  301. return smallConfig;
  302. } else if (size === WidgetSize.MEDIUM) {
  303. const mediumConfig = ObjectUtils.cloneWidgetConfig(baseConfig);
  304. mediumConfig.showCover = false;
  305. mediumConfig.buttonSize = 'medium';
  306. mediumConfig.fontSize = 'medium';
  307. mediumConfig.borderRadius = 12;
  308. return mediumConfig;
  309. } else if (size === WidgetSize.LARGE) {
  310. const largeConfig = ObjectUtils.cloneWidgetConfig(baseConfig);
  311. largeConfig.buttonSize = 'large';
  312. largeConfig.fontSize = 'large';
  313. largeConfig.borderRadius = 16;
  314. return largeConfig;
  315. } else {
  316. return baseConfig;
  317. }
  318. }
  319. /**
  320. * 获取默认用户偏好
  321. */
  322. private getDefaultUserPreferences(): UserPreferences {
  323. return {
  324. // 全局偏好
  325. defaultTheme: WidgetTheme.AUTO,
  326. defaultSize: WidgetSize.MEDIUM,
  327. // 同步设置
  328. syncWithMainApp: true,
  329. syncThemeColor: true,
  330. // 性能设置
  331. enableCache: true,
  332. cacheExpiry: 30000,
  333. // 隐私设置
  334. showSongInfo: true,
  335. showArtistInfo: true,
  336. showAlbumCover: true
  337. };
  338. }
  339. /**
  340. * 加载用户偏好设置
  341. */
  342. private async loadUserPreferences(): Promise<void> {
  343. try {
  344. if (!this.preferencesStore) {
  345. return;
  346. }
  347. const prefsStr = await this.preferencesStore.get('user_preferences', '') as string;
  348. if (prefsStr) {
  349. this.userPreferences = JSON.parse(prefsStr) as UserPreferences;
  350. } else {
  351. this.userPreferences = this.getDefaultUserPreferences();
  352. }
  353. } catch (error) {
  354. hilog.error(0x0000, TAG, `Failed to load user preferences: ${error}`);
  355. this.userPreferences = this.getDefaultUserPreferences();
  356. }
  357. }
  358. /**
  359. * 从主应用获取主题信息
  360. */
  361. private async getMainAppTheme(): Promise<MainAppTheme | null> {
  362. try {
  363. // 这里应该从主应用的主题管理器获取主题信息
  364. // 暂时返回默认主题
  365. return {
  366. theme: WidgetTheme.AUTO,
  367. backgroundColor: '#FFFFFF',
  368. textColor: '#E6000000',
  369. accentColor: '#FF007DFF'
  370. };
  371. } catch (error) {
  372. hilog.error(0x0000, TAG, `Failed to get main app theme: ${error}`);
  373. return null;
  374. }
  375. }
  376. }
  377. /**
  378. * 主应用主题接口
  379. */
  380. interface MainAppTheme {
  381. theme: WidgetTheme;
  382. backgroundColor: string;
  383. textColor: string;
  384. accentColor: string;
  385. }