Files
iccery-v2-mac/Sources/ICCery/Stage4View.swift
T
gronodandDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 55dee0f0cd fix(m9): keep Stage4View under Swift 5.7 ViewBuilder 10-child limit (#111)
The formSection VStack had 11 direct children; Xcode 14.2's ViewBuilder
only provides buildBlock overloads up to 10 arguments, so the CI build
on the macOS 12 runner failed at line 144 with "extra argument in call"
(run 31958). Nest the calibration toggle and conditional file row in an
inner VStack with identical alignment and spacing.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-12 08:55:12 +01:00

195 lines
6.9 KiB
Swift

import SwiftUI
import ICCeryCore
/// Stage 4 — build an ICC/ICM profile from the canonical `.ti3`.
struct Stage4View: View {
@ObservedObject var model: ProfileWorkflowViewModel
/// Header reads `model.wizard.basename`; observe the nested
/// ObservableObject directly.
@ObservedObject private var wizard: WizardViewModel
init(model: ProfileWorkflowViewModel) {
self.model = model
self._wizard = ObservedObject(wrappedValue: model.wizard)
}
var body: some View {
VStack(spacing: 0) {
header
ScrollView {
VStack(alignment: .leading, spacing: 16) {
formSection
runSection
}
.padding(20)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Theme.background)
.onAppear { model.restoreCreatedProfileURL() }
}
// MARK: - Header
@ViewBuilder
private var header: some View {
HStack(alignment: .firstTextBaseline) {
VStack(alignment: .leading, spacing: 4) {
Text(model.wizard.basename)
.font(.title3)
.foregroundStyle(Theme.text)
.accessibilityIdentifier("stage4TargetBasename")
Text("Build the ICC profile from the measured .ti3.")
.font(.callout)
.foregroundStyle(.secondary)
.accessibilityIdentifier("stage4TargetMeta")
}
Spacer()
if let progress = model.colprofProgress, model.isColprofRunning {
Text(progress)
.font(.caption)
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Theme.border)
.cornerRadius(4)
.foregroundStyle(Theme.text)
.accessibilityIdentifier("colprofProgress")
}
}
.padding(16)
.background(Theme.panel)
}
// MARK: - Form
@ViewBuilder
private var formSection: some View {
VStack(alignment: .leading, spacing: 12) {
Text("Profile settings")
.font(.headline)
.foregroundStyle(Theme.text)
HStack(spacing: 16) {
Picker("Algorithm", selection: $model.algorithm) {
Text("Lab cLUT").tag("l")
Text("XYZ cLUT").tag("x")
Text("Display XYZ+matrix").tag("X")
Text("Matrix").tag("m")
}
.accessibilityIdentifier("colprofAlgorithm")
Picker("Quality", selection: $model.quality) {
Text("Low").tag("l")
Text("Medium").tag("m")
Text("High").tag("h")
Text("Ultra").tag("u")
}
.accessibilityIdentifier("colprofQuality")
}
Picker("FWA / OBA compensation", selection: $model.fwaSelection) {
ForEach(ColprofFwaSelection.allCases, id: \.self) { selection in
Text(selection.displayName).tag(selection)
}
}
.accessibilityIdentifier("colprofFwa")
if model.fwaSelection == .custom {
HStack {
TextField("Custom .sp spectrum path", text: $model.fwaCustomPath)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofFwaCustomPath")
Button("Browse…") { model.browseForSpectrumFile() }
.accessibilityIdentifier("btnBrowseFwaSp")
}
}
HStack(spacing: 16) {
TextField("Illuminant", text: $model.illuminant)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofIlluminant")
TextField("Observer", text: $model.observer)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofObserver")
}
HStack(spacing: 16) {
TextField("Input viewing condition", text: $model.inputViewingCond)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofInputViewCond")
TextField("Output viewing condition", text: $model.outputViewingCond)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofOutputViewCond")
}
Text("Use 'none' to skip a viewing condition.")
.font(.caption)
.foregroundStyle(.secondary)
TextField("Description", text: $model.profileDescription)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofDescription")
TextField("Copyright", text: $model.copyright)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofCopyright")
// Nested VStack keeps the parent at the Swift 5.7 ViewBuilder
// 10-child limit (Xcode 14.2 / macOS 12 CI runner, #111).
VStack(alignment: .leading, spacing: 12) {
Toggle("Apply calibration curve", isOn: $model.applyCalibration)
.accessibilityIdentifier("colprofApplyCalibration")
if model.applyCalibration {
HStack {
TextField("Calibration .cal file", text: $model.calibrationFile)
.textFieldStyle(.roundedBorder)
.accessibilityIdentifier("colprofCalibrationFile")
Button("Browse…") { model.browseForCalibrationFile() }
.accessibilityIdentifier("btnBrowseCalibrationFile")
}
}
}
}
.padding(16)
.background(Theme.panel)
}
// MARK: - Run controls
@ViewBuilder
private var runSection: some View {
VStack(alignment: .leading, spacing: 12) {
HStack(spacing: 12) {
Button("Create Profile") {
model.createProfile()
}
.disabled(!model.canCreateProfile)
.accessibilityIdentifier("btnCreateProfile")
if model.isColprofRunning {
ProgressView()
.scaleEffect(0.8)
.accessibilityIdentifier("colprofProgressIndicator")
}
Spacer()
}
if !model.colprofLog.isEmpty {
ProcessLogView(
lines: model.colprofLog,
containerId: "colprofLogContainer",
logId: "colprofLog"
)
}
}
.padding(16)
.background(Theme.panel)
}
}