- WizardState: Codable persisted fields — currentStage, basename, cwd, printerName, sessionMode (profile|calibration), profileBasename; WizardStateStore writes wizard_state.json atomically - WizardGating: pure gating — 1 always; 2 on .ti1; 3 on .ti1+.ti2; 4 on .ti3 only (never .ti2 — #109/#110); 5 on .ti3+profile (#69). Forward gated, backward always; Stage 0 a side-trip - WizardViewModel: setTarget sanitises basename (#60) and resolves cwd (#59); locked forward nav shows a warning banner; windowDidBecomeKey re-probes and drops back to deepest unlocked when files vanish (#151) - RootView: NSWindow.didBecomeKeyNotification -> revalidate - Sidebar stepper enabled state now driven by artefact gating - 11 new tests incl. gating matrix + persistence; 71/71 green Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
49 lines
1.6 KiB
Swift
49 lines
1.6 KiB
Swift
import AppKit
|
|
import SwiftUI
|
|
|
|
/// Root layout: 270 pt sidebar + main stage area with the notification
|
|
/// banner pinned to the top (docs/21 §Shell).
|
|
struct RootView: View {
|
|
@Bindable var model: WizardViewModel
|
|
@State private var showingSettings = false
|
|
@State private var showingAbout = false
|
|
|
|
var body: some View {
|
|
HStack(spacing: 0) {
|
|
SidebarView(
|
|
model: model,
|
|
onOpenSettings: { showingSettings = true },
|
|
onOpenAbout: { showingAbout = true }
|
|
)
|
|
|
|
Rectangle()
|
|
.fill(Theme.border)
|
|
.frame(width: 1)
|
|
|
|
VStack(spacing: 0) {
|
|
if let notice = model.notice {
|
|
NoticeBanner(notice: notice, onClose: model.dismissNotice)
|
|
}
|
|
StagePlaceholderView(stage: model.stage)
|
|
}
|
|
}
|
|
.frame(minWidth: 1100, minHeight: 700)
|
|
.background(Theme.background)
|
|
// #151: re-probe artefacts when the window regains focus —
|
|
// files deleted in Finder must re-lock stages.
|
|
.onReceive(
|
|
NotificationCenter.default.publisher(
|
|
for: NSWindow.didBecomeKeyNotification
|
|
)
|
|
) { _ in model.windowDidBecomeKey() }
|
|
.sheet(isPresented: $showingSettings) {
|
|
SettingsView()
|
|
}
|
|
.alert("ICCery 2.0.0", isPresented: $showingAbout) {
|
|
Button("OK") {}
|
|
} message: {
|
|
Text("Native macOS printer profiling workstation.\nFull About dialog lands in issue #31.")
|
|
}
|
|
}
|
|
}
|