Files
lanework/Kanban/App/CaptureOpenWindow.swift
T
rzen fccdf56cf4 Stand up the window architecture — welcome, board, card
Four scenes (welcome, restore bootstrap, board group, card group) with
system restoration disabled in favor of the registry's open-now flags:
set when a window actually opens, cleared only on user close, so quit —
and crash — leave exactly the restoration set behind. AppModel joins
windows to sessions (shared store, registry record, card refs, held
security scope); CloseFlushCoordinator pins 02's strict close order as
a seam-injected machine (card sessions end, windows drain, store
flushes, record stamps, teardown) with named slots where m6/m7 flushes
land. HostedWindowController proxies — never replaces — SwiftUI's
window delegate to intercept windowShouldClose for the flush, report
frames, and place saved frames onto live screens. Card windows are
(board path, case-folded card id) values: reopen focuses, and a
snapshot-pure fate function dismisses on delete, tombstone, tombstoned
lane, or cross-board move.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
2026-07-27 07:47:11 -04:00

37 lines
1.6 KiB
Swift

import SwiftUI
/// Lifts SwiftUI's window actions out of the environment and into `AppModel`, from whatever scene
/// happens to be on screen.
///
/// `openWindow` and `dismissWindow` are only readable from a view, and the two places that most need
/// them are not views: `AppDelegate` (a Dock click with no windows must bring up welcome — 02
/// § Launch and window lifecycle) and the close flush (which dismisses a board's card windows before
/// anything else happens). Both are reached from AppKit, with no environment in sight.
///
/// **The captured actions outlive the view that supplied them.** They are values addressed to the
/// app, not to a window, so the last scene to appear leaves behind actions that still work after
/// every window is gone — which is exactly the windowless reactivation case. That is why this is
/// applied to *every* scene root: whichever one exists, the app has its actions.
///
/// Both are captured together despite the name: they are one capability with two halves, and a
/// second modifier for the second half would be ceremony.
struct CaptureOpenWindow: ViewModifier {
let appModel: AppModel
@Environment(\.openWindow) private var openWindow
@Environment(\.dismissWindow) private var dismissWindow
func body(content: Content) -> some View {
content.onAppear {
appModel.captureWindowActions(open: openWindow, dismiss: dismissWindow)
}
}
}
extension View {
func captureWindowActions(into appModel: AppModel) -> some View {
modifier(CaptureOpenWindow(appModel: appModel))
}
}