// // HomeCommonMenuStore.swift // suixinkan // // Created by Codex on 2026/6/22. // import Foundation /// 首页常用应用存储服务,负责按当前权限过滤和持久化常用 URI。 struct HomeCommonMenuStore { static let defaultStorageKey = "home.common.menu.uris" static let defaultBaselineKey = "home.common.menu.android.baseline.v2" private let defaults: UserDefaults private let storageKey: String private let baselineKey: String /// 初始化常用应用存储服务,并允许测试注入独立 UserDefaults。 init( defaults: UserDefaults = .standard, storageKey: String = Self.defaultStorageKey, baselineKey: String = Self.defaultBaselineKey ) { self.defaults = defaults self.storageKey = storageKey self.baselineKey = baselineKey } /// 读取常用 URI,首次使用时写入默认值,并始终按当前权限过滤。 func load(menuItems: [HomeMenuItem]) -> [String] { let availableURIs = Set(menuItems.map(\.uri)) if !defaults.bool(forKey: baselineKey) { let defaults = defaultCommonURIs(availableURIs: availableURIs) save(defaults) self.defaults.set(true, forKey: baselineKey) return defaults } let saved = defaults.stringArray(forKey: storageKey) ?? [] let filtered = unique(saved.compactMap { uri -> String? in let resolved = HomeMenuRouter.canonicalURI(for: uri, availableURIs: availableURIs) return availableURIs.contains(resolved) ? resolved : nil }) save(filtered) return filtered } /// 将指定 URI 加入常用应用,按别名避免重复添加。 func add(_ uri: String, current: [String], menuItems: [HomeMenuItem]) -> [String] { let availableURIs = Set(menuItems.map(\.uri)) let resolved = HomeMenuRouter.canonicalURI(for: uri, availableURIs: availableURIs) guard availableURIs.contains(resolved) else { return current } guard !current.contains(where: { HomeMenuRouter.menuAliasKey(for: $0) == HomeMenuRouter.menuAliasKey(for: resolved) }) else { return current } let next = current + [resolved] save(next) return next } /// 从常用应用中移除指定 URI,同义 URI 会一起移除。 func remove(_ uri: String, current: [String]) -> [String] { let aliasKey = HomeMenuRouter.menuAliasKey(for: uri) let next = current.filter { HomeMenuRouter.menuAliasKey(for: $0) != aliasKey } save(next) return next } /// 保存常用 URI。 func save(_ uris: [String]) { defaults.set(unique(uris), forKey: storageKey) } /// 生成默认常用应用 URI。 private func defaultCommonURIs(availableURIs: Set) -> [String] { let preferred = ["registration_invitation", "location_report", "pm_manager", "pm"] return unique(preferred.compactMap { uri in let resolved = HomeMenuRouter.canonicalURI(for: uri, availableURIs: availableURIs) return availableURIs.contains(resolved) ? resolved : nil }) } /// 按 URI 别名去重,保留首次出现的 URI。 private func unique(_ uris: [String]) -> [String] { var seen = Set() return uris.filter { uri in seen.insert(HomeMenuRouter.menuAliasKey(for: uri)).inserted } } }