~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain-ios

1 collaborator
0
1
main
38 lines · 1.4 KB Raw History
import Foundation

/// The label definitions every card resolves a gallery's labels against,
/// read from grain-serve's `social.grain.moderation.describeLabels` once,
/// and kept for the next launch. Until that answers, and when it cannot,
/// the last ones read stand, or else the copy the app carries.
@Observable
@MainActor
final class LabelDefinitionsCache {
    private(set) var definitions: [LabelDefinition]
    private var hasLoaded = false

    static let storageKey = "labelDefinitions.v1"

    init(definitions: [LabelDefinition]? = nil) {
        self.definitions = definitions ?? Self.stored() ?? LabelDefinition.all
    }

    func loadIfNeeded(client: XRPCClient, auth: AuthContext?) async {
        guard !hasLoaded else { return }
        do {
            let fetched = try await client.describeLabels(auth: auth)
            hasLoaded = true
            guard !fetched.isEmpty else { return }
            definitions = fetched
            if let data = try? JSONEncoder().encode(fetched) {
                StorageEnvironment.defaults.set(data, forKey: Self.storageKey)
            }
        } catch {
            // Keep what there is; the next call asks again.
        }
    }

    private static func stored() -> [LabelDefinition]? {
        guard let data = StorageEnvironment.defaults.data(forKey: storageKey) else { return nil }
        return try? JSONDecoder().decode([LabelDefinition].self, from: data)
    }
}