92 lines
3.4 KiB
Swift
92 lines
3.4 KiB
Swift
//
|
||
// 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>) -> [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<String>()
|
||
return uris.filter { uri in
|
||
seen.insert(HomeMenuRouter.menuAliasKey(for: uri)).inserted
|
||
}
|
||
}
|
||
}
|