Files
iccery-v2-mac/Sources/ICCery/GamutViewModel.swift
gronodandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 32d2184d2e feat(m9): migrate state to Combine and demote SwiftUI views for macOS 12
Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-11 21:51:18 +01:00

57 lines
1.7 KiB
Swift

import Combine
import Foundation
import ICCeryCore
/// View model for the native SceneKit gamut viewer.
///
/// Loads the bundled `sRGB.gam` reference immediately and, optionally, a
/// printer/profile `.gam` from the current working directory.
@MainActor
final class GamutViewModel: ObservableObject {
/// Parsed reference sRGB gamut mesh.
@Published var sRGBMesh: GamutMesh?
/// Parsed printer/profile gamut mesh.
@Published var profileMesh: GamutMesh?
/// User-facing status line.
@Published var status = "Loading gamut…"
/// Closure injected into the SceneKit view to request a camera reset.
@Published var resetCamera: () -> Void = {}
private let profileGamURL: URL?
init(profileGamURL: URL? = nil) {
self.profileGamURL = profileGamURL
Task { await load() }
}
private func load() async {
do {
let referenceURL = BinaryResolver().referenceGamut("sRGB")
let reference = try await parse(url: referenceURL)
sRGBMesh = reference
if let profileGamURL {
let profile = try await parse(url: profileGamURL)
profileMesh = profile
status = "Profile gamut (\(profile.faces.count) faces) vs sRGB reference"
} else {
status = "sRGB reference gamut (\(reference.faces.count) faces)"
}
} catch {
status = "Could not load gamut: \(error.localizedDescription)"
}
}
/// Parses a `.gam` file off the main actor so large meshes do not stall
/// the UI.
private func parse(url: URL) async throws -> GamutMesh {
try await Task.detached {
try GamutMeshParser.parse(url: url)
}.value
}
}