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
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
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))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user