import Foundation enum RepoCache { private static let listKey = "repo.list" private static let listFetchedKey = "repo.list.fetchedAt" private static let recentsKey = "repo.recents" private static let recentsCap = 5 static let staleAfter: TimeInterval = 24 * 60 * 60 static var repos: [GiteaRepo] { get { guard let data = AppSettings.localDefaults.data(forKey: listKey) else { return [] } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 return (try? decoder.decode([GiteaRepo].self, from: data)) ?? [] } set { let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 if let data = try? encoder.encode(newValue) { AppSettings.localDefaults.set(data, forKey: listKey) AppSettings.localDefaults.set(Date(), forKey: listFetchedKey) } } } static var fetchedAt: Date? { AppSettings.localDefaults.object(forKey: listFetchedKey) as? Date } static var isStale: Bool { guard let fetched = fetchedAt else { return true } return Date().timeIntervalSince(fetched) > staleAfter } static var recentFullNames: [String] { AppSettings.localDefaults.stringArray(forKey: recentsKey) ?? [] } static func touch(_ fullName: String) { var current = recentFullNames.filter { $0 != fullName } current.insert(fullName, at: 0) if current.count > recentsCap { current = Array(current.prefix(recentsCap)) } AppSettings.localDefaults.set(current, forKey: recentsKey) } }