native macOS codings agent orchestrator prowl.onev.cat
Something went wrong. Try again.
3.0 kB · 85 lines
Swift
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586import Dependenciesimport Foundationimport Sharing
/// Persisted dictionary keyed by `Repository.ID` (the path-derived id/// from `RepositoryEntryNormalizer`) holding each repo's user-picked/// icon and color. One global file rather than per-repo so the sidebar/// — which renders every row — gets every appearance in a single/// `@Shared` read; per-repo settings would force one file load per/// row at startup.////// On-disk location: `~/.prowl/repository-appearances.json`. Repos/// without an entry behave exactly like before (no icon, accent color/// fallback) so the file is purely additive.nonisolated struct RepositoryAppearancesKeyID: Hashable, Sendable {}
nonisolated enum RepositoryAppearancesFileURLKey: DependencyKey { static var liveValue: URL { ProwlPaths.repositoryAppearancesURL } static var previewValue: URL { ProwlPaths.repositoryAppearancesURL } static var testValue: URL { ProwlPaths.repositoryAppearancesURL }}
extension DependencyValues { nonisolated var repositoryAppearancesFileURL: URL { get { self[RepositoryAppearancesFileURLKey.self] } set { self[RepositoryAppearancesFileURLKey.self] = newValue } }}
nonisolated struct RepositoryAppearancesKey: SharedKey { var id: RepositoryAppearancesKeyID { RepositoryAppearancesKeyID() }
func load( context _: LoadContext<[Repository.ID: RepositoryAppearance]>, continuation: LoadContinuation<[Repository.ID: RepositoryAppearance]> ) { @Dependency(\.settingsFileStorage) var storage @Dependency(\.repositoryAppearancesFileURL) var url let decoder = JSONDecoder() if let data = try? storage.load(url), let entries = try? decoder.decode([Repository.ID: RepositoryAppearance].self, from: data) { continuation.resume(returning: entries) return } continuation.resumeReturningInitialValue() }
func subscribe( context _: LoadContext<[Repository.ID: RepositoryAppearance]>, subscriber _: SharedSubscriber<[Repository.ID: RepositoryAppearance]> ) -> SharedSubscription { SharedSubscription {} }
func save( _ value: [Repository.ID: RepositoryAppearance], context _: SaveContext, continuation: SaveContinuation ) { @Dependency(\.settingsFileStorage) var storage @Dependency(\.repositoryAppearancesFileURL) var url let encoder = JSONEncoder() encoder.outputFormatting = [.prettyPrinted, .sortedKeys] do { // Drop empty entries before writing so the file stays tight when // a user clears both icon and color — the absence of a key is // the canonical "no appearance" state. let pruned = value.filter { !$0.value.isEmpty } let data = try encoder.encode(pruned) try storage.save(data, url) continuation.resume() } catch { continuation.resume(throwing: error) } }}
nonisolated extension SharedReaderKey where Self == RepositoryAppearancesKey.Default { static var repositoryAppearances: Self { Self[RepositoryAppearancesKey(), default: [:]] }}