1819a9075Smaotoumaoimport { CustomizedColors } from "@/hooks/useColors"; 2*41ddce91Smaotoumaoimport { getStorage, removeStorage } from "@/utils/storage"; 3819a9075Smaotoumaoimport { ResumeMode, SortType } from "@/constants/commonConst.ts"; 4*41ddce91Smaotoumaoimport getOrCreateMMKV from "@/utils/getOrCreateMMKV.ts"; 5*41ddce91Smaotoumaoimport safeStringify from "@/utils/safeStringify.ts"; 6*41ddce91Smaotoumaoimport { useMMKVObject } from "react-native-mmkv"; 7e22d5e4fS猫头猫 8*41ddce91Smaotoumao 9*41ddce91Smaotoumaoconst configStore = getOrCreateMMKV('App.config'); 10*41ddce91Smaotoumao 11*41ddce91Smaotoumao// 新版本配置类型(扁平化结构) 12e22d5e4fS猫头猫interface IConfig { 13*41ddce91Smaotoumao "$schema": "1"; 14*41ddce91Smaotoumao // Basic 15*41ddce91Smaotoumao "basic.autoPlayWhenAppStart": boolean; 16*41ddce91Smaotoumao "basic.useCelluarNetworkPlay": boolean; 17*41ddce91Smaotoumao "basic.useCelluarNetworkDownload": boolean; 18*41ddce91Smaotoumao "basic.maxDownload": number | string; 19*41ddce91Smaotoumao "basic.clickMusicInSearch": '播放歌曲' | '播放歌曲并替换播放列表'; 20*41ddce91Smaotoumao "basic.clickMusicInAlbum": '播放专辑' | '播放单曲'; 21*41ddce91Smaotoumao "basic.downloadPath": string; 22*41ddce91Smaotoumao "basic.notInterrupt": boolean; 23*41ddce91Smaotoumao "basic.tempRemoteDuck": '暂停' | '降低音量'; 24*41ddce91Smaotoumao "basic.autoStopWhenError": boolean; 25*41ddce91Smaotoumao "basic.pluginCacheControl": string; 26*41ddce91Smaotoumao "basic.maxCacheSize": number; 27*41ddce91Smaotoumao "basic.defaultPlayQuality": IMusic.IQualityKey; 28*41ddce91Smaotoumao "basic.playQualityOrder": 'asc' | 'desc'; 29*41ddce91Smaotoumao "basic.defaultDownloadQuality": IMusic.IQualityKey; 30*41ddce91Smaotoumao "basic.downloadQualityOrder": 'asc' | 'desc'; 31*41ddce91Smaotoumao "basic.musicDetailDefault": 'album' | 'lyric'; 32*41ddce91Smaotoumao "basic.musicDetailAwake": boolean; 33*41ddce91Smaotoumao "basic.maxHistoryLen": number; 34*41ddce91Smaotoumao "basic.autoUpdatePlugin": boolean; 35*41ddce91Smaotoumao "basic.notCheckPluginVersion": boolean; 36*41ddce91Smaotoumao "basic.associateLyricType": 'input' | 'search'; 37*41ddce91Smaotoumao "basic.showExitOnNotification": boolean; 38*41ddce91Smaotoumao "basic.musicOrderInLocalSheet": SortType; 39*41ddce91Smaotoumao "basic.tryChangeSourceWhenPlayFail": boolean; 40e22d5e4fS猫头猫 41*41ddce91Smaotoumao // Lyric 42*41ddce91Smaotoumao "lyric.showStatusBarLyric": boolean; 43*41ddce91Smaotoumao "lyric.topPercent": number; 44*41ddce91Smaotoumao "lyric.leftPercent": number; 45*41ddce91Smaotoumao "lyric.align": number; 46*41ddce91Smaotoumao "lyric.color": string; 47*41ddce91Smaotoumao "lyric.backgroundColor": string; 48*41ddce91Smaotoumao "lyric.widthPercent": number; 49*41ddce91Smaotoumao "lyric.fontSize": number; 50*41ddce91Smaotoumao "lyric.detailFontSize": number; 51*41ddce91Smaotoumao "lyric.autoSearchLyric": boolean; 528b7ddca8S猫头猫 53*41ddce91Smaotoumao // Theme 54*41ddce91Smaotoumao "theme.background": string; 55*41ddce91Smaotoumao "theme.backgroundOpacity": number; 56*41ddce91Smaotoumao "theme.backgroundBlur": number; 57*41ddce91Smaotoumao "theme.colors": CustomizedColors; 58*41ddce91Smaotoumao "theme.customColors"?: CustomizedColors; 59*41ddce91Smaotoumao "theme.followSystem": boolean; 60*41ddce91Smaotoumao "theme.selectedTheme": string; 61a7b42a4cS猫头猫 62*41ddce91Smaotoumao // Backup 63*41ddce91Smaotoumao "backup.resumeMode": ResumeMode; 64*41ddce91Smaotoumao 65*41ddce91Smaotoumao // Plugin 66*41ddce91Smaotoumao "plugin.subscribeUrl": string; 67*41ddce91Smaotoumao 68*41ddce91Smaotoumao // WebDAV 69*41ddce91Smaotoumao "webdav.url": string; 70*41ddce91Smaotoumao "webdav.username": string; 71*41ddce91Smaotoumao "webdav.password": string; 72*41ddce91Smaotoumao 73*41ddce91Smaotoumao // Debug(保持嵌套结构) 74*41ddce91Smaotoumao "debug.errorLog": boolean; 75*41ddce91Smaotoumao "debug.traceLog": boolean; 76*41ddce91Smaotoumao "debug.devLog": boolean; 77e22d5e4fS猫头猫} 78e22d5e4fS猫头猫 79e22d5e4fS猫头猫 80*41ddce91Smaotoumaoexport type ConfigKey = keyof IConfig; 81e22d5e4fS猫头猫 82*41ddce91Smaotoumao// 迁移函数 83*41ddce91Smaotoumaoasync function migrateConfig(): Promise<void> { 84*41ddce91Smaotoumao // 检查是否已经迁移 85*41ddce91Smaotoumao if (configStore.contains('$schema')) { 86e22d5e4fS猫头猫 return; 87e22d5e4fS猫头猫 } 88e22d5e4fS猫头猫 89*41ddce91Smaotoumao // 获取旧配置 90*41ddce91Smaotoumao const oldConfig = await getStorage('local-config'); 91e22d5e4fS猫头猫 92*41ddce91Smaotoumao // 如果没有旧配置,直接初始化新配置 93*41ddce91Smaotoumao if (!oldConfig) { 94*41ddce91Smaotoumao configStore.set('$schema', '1'); 95*41ddce91Smaotoumao return; 96e22d5e4fS猫头猫 } 97e22d5e4fS猫头猫 98*41ddce91Smaotoumao // 迁移每个字段 99*41ddce91Smaotoumao const mapping: [string, ConfigKey][] = [ 100*41ddce91Smaotoumao // Basic 101*41ddce91Smaotoumao ['setting.basic.autoPlayWhenAppStart', 'basic.autoPlayWhenAppStart'], 102*41ddce91Smaotoumao ['setting.basic.useCelluarNetworkPlay', 'basic.useCelluarNetworkPlay'], 103*41ddce91Smaotoumao ['setting.basic.useCelluarNetworkDownload', 'basic.useCelluarNetworkDownload'], 104*41ddce91Smaotoumao ['setting.basic.maxDownload', 'basic.maxDownload'], 105*41ddce91Smaotoumao ['setting.basic.clickMusicInSearch', 'basic.clickMusicInSearch'], 106*41ddce91Smaotoumao ['setting.basic.clickMusicInAlbum', 'basic.clickMusicInAlbum'], 107*41ddce91Smaotoumao ['setting.basic.downloadPath', 'basic.downloadPath'], 108*41ddce91Smaotoumao ['setting.basic.notInterrupt', 'basic.notInterrupt'], 109*41ddce91Smaotoumao ['setting.basic.tempRemoteDuck', 'basic.tempRemoteDuck'], 110*41ddce91Smaotoumao ['setting.basic.autoStopWhenError', 'basic.autoStopWhenError'], 111*41ddce91Smaotoumao ['setting.basic.pluginCacheControl', 'basic.pluginCacheControl'], 112*41ddce91Smaotoumao ['setting.basic.maxCacheSize', 'basic.maxCacheSize'], 113*41ddce91Smaotoumao ['setting.basic.defaultPlayQuality', 'basic.defaultPlayQuality'], 114*41ddce91Smaotoumao ['setting.basic.playQualityOrder', 'basic.playQualityOrder'], 115*41ddce91Smaotoumao ['setting.basic.defaultDownloadQuality', 'basic.defaultDownloadQuality'], 116*41ddce91Smaotoumao ['setting.basic.downloadQualityOrder', 'basic.downloadQualityOrder'], 117*41ddce91Smaotoumao ['setting.basic.musicDetailDefault', 'basic.musicDetailDefault'], 118*41ddce91Smaotoumao ['setting.basic.musicDetailAwake', 'basic.musicDetailAwake'], 119*41ddce91Smaotoumao ['setting.basic.debug.errorLog', 'debug.errorLog'], 120*41ddce91Smaotoumao ['setting.basic.debug.traceLog', 'debug.traceLog'], 121*41ddce91Smaotoumao ['setting.basic.debug.devLog', 'debug.devLog'], 122*41ddce91Smaotoumao ['setting.basic.maxHistoryLen', 'basic.maxHistoryLen'], 123*41ddce91Smaotoumao ['setting.basic.autoUpdatePlugin', 'basic.autoUpdatePlugin'], 124*41ddce91Smaotoumao ['setting.basic.notCheckPluginVersion', 'basic.notCheckPluginVersion'], 125*41ddce91Smaotoumao ['setting.basic.associateLyricType', 'basic.associateLyricType'], 126*41ddce91Smaotoumao ['setting.basic.showExitOnNotification', 'basic.showExitOnNotification'], 127*41ddce91Smaotoumao ['setting.basic.musicOrderInLocalSheet', 'basic.musicOrderInLocalSheet'], 128*41ddce91Smaotoumao ['setting.basic.tryChangeSourceWhenPlayFail', 'basic.tryChangeSourceWhenPlayFail'], 129e22d5e4fS猫头猫 130*41ddce91Smaotoumao // Lyric 131*41ddce91Smaotoumao ['setting.lyric.showStatusBarLyric', 'lyric.showStatusBarLyric'], 132*41ddce91Smaotoumao ['setting.lyric.topPercent', 'lyric.topPercent'], 133*41ddce91Smaotoumao ['setting.lyric.leftPercent', 'lyric.leftPercent'], 134*41ddce91Smaotoumao ['setting.lyric.align', 'lyric.align'], 135*41ddce91Smaotoumao ['setting.lyric.color', 'lyric.color'], 136*41ddce91Smaotoumao ['setting.lyric.backgroundColor', 'lyric.backgroundColor'], 137*41ddce91Smaotoumao ['setting.lyric.widthPercent', 'lyric.widthPercent'], 138*41ddce91Smaotoumao ['setting.lyric.fontSize', 'lyric.fontSize'], 139*41ddce91Smaotoumao ['setting.lyric.detailFontSize', 'lyric.detailFontSize'], 140*41ddce91Smaotoumao ['setting.lyric.autoSearchLyric', 'lyric.autoSearchLyric'], 141e22d5e4fS猫头猫 142*41ddce91Smaotoumao // Theme 143*41ddce91Smaotoumao ['setting.theme.background', 'theme.background'], 144*41ddce91Smaotoumao ['setting.theme.backgroundOpacity', 'theme.backgroundOpacity'], 145*41ddce91Smaotoumao ['setting.theme.backgroundBlur', 'theme.backgroundBlur'], 146*41ddce91Smaotoumao ['setting.theme.colors', 'theme.colors'], 147*41ddce91Smaotoumao ['setting.theme.customColors', 'theme.customColors'], 148*41ddce91Smaotoumao ['setting.theme.followSystem', 'theme.followSystem'], 149*41ddce91Smaotoumao ['setting.theme.selectedTheme', 'theme.selectedTheme'], 150*41ddce91Smaotoumao 151*41ddce91Smaotoumao // Backup 152*41ddce91Smaotoumao ['setting.backup.resumeMode', 'backup.resumeMode'], 153*41ddce91Smaotoumao 154*41ddce91Smaotoumao // Plugin 155*41ddce91Smaotoumao ['setting.plugin.subscribeUrl', 'plugin.subscribeUrl'], 156*41ddce91Smaotoumao 157*41ddce91Smaotoumao // WebDAV 158*41ddce91Smaotoumao ['setting.webdav.url', 'webdav.url'], 159*41ddce91Smaotoumao ['setting.webdav.username', 'webdav.username'], 160*41ddce91Smaotoumao ['setting.webdav.password', 'webdav.password'], 161*41ddce91Smaotoumao ]; 162*41ddce91Smaotoumao 163*41ddce91Smaotoumao // 执行迁移 164e22d5e4fS猫头猫 function getPathValue(obj: Record<string, any>, path: string) { 165e22d5e4fS猫头猫 const keys = path.split('.'); 166e22d5e4fS猫头猫 let tmp = obj; 167e22d5e4fS猫头猫 for (let i = 0; i < keys.length; ++i) { 168e22d5e4fS猫头猫 tmp = tmp?.[keys[i]]; 169e22d5e4fS猫头猫 } 170e22d5e4fS猫头猫 return tmp; 171e22d5e4fS猫头猫 } 172e22d5e4fS猫头猫 173*41ddce91Smaotoumao mapping.forEach(([oldPath, newKey]) => { 174*41ddce91Smaotoumao const value = getPathValue(oldConfig, oldPath); 175*41ddce91Smaotoumao if (value !== undefined) { 176*41ddce91Smaotoumao configStore.set(newKey, safeStringify(value)); 177*41ddce91Smaotoumao } 178*41ddce91Smaotoumao }); 179*41ddce91Smaotoumao 180*41ddce91Smaotoumao // 设置版本标识 181*41ddce91Smaotoumao configStore.set('$schema', '1'); 182*41ddce91Smaotoumao 183*41ddce91Smaotoumao // 清理旧配置 184*41ddce91Smaotoumao await removeStorage('local-config'); // 根据需求决定是否删除旧配置 185e22d5e4fS猫头猫} 186e22d5e4fS猫头猫 187*41ddce91Smaotoumao/** 初始化config */ 188*41ddce91Smaotoumaoasync function setup() { 189*41ddce91Smaotoumao await migrateConfig(); 190e22d5e4fS猫头猫} 191e22d5e4fS猫头猫 192*41ddce91Smaotoumaofunction setConfig<K extends ConfigKey>(key: K, value?: IConfig[K]) { 193*41ddce91Smaotoumao if (value === undefined) { 194*41ddce91Smaotoumao configStore.delete(key); 195e22d5e4fS猫头猫 } else { 196*41ddce91Smaotoumao configStore.set(key, safeStringify(value)); 197e22d5e4fS猫头猫 } 198e22d5e4fS猫头猫} 199e22d5e4fS猫头猫 200*41ddce91Smaotoumaofunction getConfig<K extends ConfigKey>(key: K): IConfig[K] | undefined { 201*41ddce91Smaotoumao const value = configStore.getString(key); 202*41ddce91Smaotoumao if (value === undefined) { 203*41ddce91Smaotoumao return undefined; 204*41ddce91Smaotoumao } 205*41ddce91Smaotoumao return JSON.parse(value); 206*41ddce91Smaotoumao} 207*41ddce91Smaotoumao 208*41ddce91Smaotoumao 209*41ddce91Smaotoumaofunction useConfig<K extends ConfigKey>(key: K) { 210*41ddce91Smaotoumao return useMMKVObject<IConfig[K]>(key, configStore); 211*41ddce91Smaotoumao} 212*41ddce91Smaotoumao 213*41ddce91Smaotoumaofunction useConfigValue<K extends ConfigKey>(key: K) { 214*41ddce91Smaotoumao return useMMKVObject<IConfig[K]>(key, configStore)[0]; 215*41ddce91Smaotoumao} 216*41ddce91Smaotoumao 217e22d5e4fS猫头猫const Config = { 2181f829e09S猫头猫 setup, 219*41ddce91Smaotoumao setConfig, 220*41ddce91Smaotoumao getConfig, 221*41ddce91Smaotoumao useConfig, 222*41ddce91Smaotoumao useConfigValue 223*41ddce91Smaotoumao} 224e22d5e4fS猫头猫 225e22d5e4fS猫头猫export default Config; 226