diff options
| author | Christian Cleberg <[email protected]> | 2026-04-12 22:06:16 -0500 |
|---|---|---|
| committer | Christian Cleberg <[email protected]> | 2026-04-12 22:06:16 -0500 |
| commit | 86bcd9452d3107f68aca085e03e69b02667c0dbb (patch) | |
| tree | 8b0adece5cb0f8ffb178eaab2cd12d025c9ebf0a /Hutch/Views/Projects/ProjectPinStore.swift | |
| parent | 31cbca674957eea7ae2529012e20a9d95158e561 (diff) | |
| download | hutch-86bcd9452d3107f68aca085e03e69b02667c0dbb.tar.gz hutch-86bcd9452d3107f68aca085e03e69b02667c0dbb.tar.bz2 hutch-86bcd9452d3107f68aca085e03e69b02667c0dbb.zip | |
feat: polish read-only project views and home integration
Refs: https://todo.sr.ht/~ccleberg/hutch/36
Refs: https://todo.sr.ht/~ccleberg/hutch/37
Refs: https://todo.sr.ht/~ccleberg/hutch/38
Diffstat (limited to 'Hutch/Views/Projects/ProjectPinStore.swift')
| -rw-r--r-- | Hutch/Views/Projects/ProjectPinStore.swift | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/Hutch/Views/Projects/ProjectPinStore.swift b/Hutch/Views/Projects/ProjectPinStore.swift index cd3d961..77a4172 100644 --- a/Hutch/Views/Projects/ProjectPinStore.swift +++ b/Hutch/Views/Projects/ProjectPinStore.swift @@ -6,7 +6,7 @@ enum ProjectPinStore { defaults: UserDefaults = .standard ) -> [String] { let pinnedProjects = loadAll(defaults: defaults) - return pinnedProjects[userKey] ?? [] + return normalizedProjectIDs(pinnedProjects[userKey] ?? []) } static func isPinned( @@ -23,12 +23,14 @@ enum ProjectPinStore { defaults: UserDefaults = .standard ) { var pinnedProjects = loadAll(defaults: defaults) - var projectIDs = pinnedProjects[userKey] ?? [] + var projectIDs = normalizedProjectIDs(pinnedProjects[userKey] ?? []) if let index = projectIDs.firstIndex(of: projectID) { projectIDs.remove(at: index) } else { - projectIDs.append(projectID) + if let normalizedProjectID = normalizedProjectID(projectID) { + projectIDs.append(normalizedProjectID) + } } pinnedProjects[userKey] = projectIDs @@ -40,11 +42,33 @@ enum ProjectPinStore { return [:] } - return (try? JSONDecoder().decode([String: [String]].self, from: data)) ?? [:] + let decoded = (try? JSONDecoder().decode([String: [String]].self, from: data)) ?? [:] + return decoded.reduce(into: [String: [String]]()) { result, entry in + let normalizedUserKey = entry.key.trimmingCharacters(in: .whitespacesAndNewlines) + guard !normalizedUserKey.isEmpty else { return } + let normalizedProjectIDs = normalizedProjectIDs(entry.value) + if !normalizedProjectIDs.isEmpty { + result[normalizedUserKey] = normalizedProjectIDs + } + } } private static func save(_ pinnedProjects: [String: [String]], defaults: UserDefaults) { guard let data = try? JSONEncoder().encode(pinnedProjects) else { return } defaults.set(data, forKey: AppStorageKeys.pinnedHomeProjects) } + + private static func normalizedProjectIDs(_ projectIDs: [String]) -> [String] { + var seen = Set<String>() + return projectIDs.compactMap { projectID in + guard let normalizedProjectID = normalizedProjectID(projectID) else { return nil } + guard seen.insert(normalizedProjectID).inserted else { return nil } + return normalizedProjectID + } + } + + private static func normalizedProjectID(_ projectID: String) -> String? { + let trimmed = projectID.trimmingCharacters(in: .whitespacesAndNewlines) + return trimmed.isEmpty ? nil : trimmed + } } |
