Last active
December 16, 2023 18:31
-
-
Save davidbalbert/3fbb7f88e3c964062b917557d969923d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// OnWindowClose.swift | |
// | |
// Created by David Albert on 12/16/23. | |
// | |
import SwiftUI | |
import AppKit | |
struct WindowReader: NSViewRepresentable { | |
class View: NSView { | |
static let didMoveToWindowNotification: NSNotification.Name = NSNotification.Name("viewDidMoveToWindow") | |
override func viewDidMoveToWindow() { | |
super.viewDidMoveToWindow() | |
NotificationCenter.default.post(name: Self.didMoveToWindowNotification, object: self) | |
} | |
} | |
class Coordinator { | |
var observer: AnyObject? | |
} | |
func makeCoordinator() -> Coordinator { | |
Coordinator() | |
} | |
@Binding var window: NSWindow? | |
func makeNSView(context: Context) -> View { | |
let view = View() | |
let observer = NotificationCenter.default.addObserver(forName: View.didMoveToWindowNotification, object: view, queue: nil) { _ in | |
window = view.window | |
} | |
context.coordinator.observer = observer | |
return view | |
} | |
func updateNSView(_ nsView: View, context: Context) { | |
} | |
static func dismantleNSView(_ nsView: View, coordinator: Coordinator) { | |
guard let observer = coordinator.observer else { | |
return | |
} | |
NotificationCenter.default.removeObserver(observer) | |
} | |
} | |
struct OnWindowClose: ViewModifier { | |
@State var window: NSWindow? | |
@State var observer: AnyObject? | |
let action: () -> Void | |
func body(content: Content) -> some View { | |
content | |
.background { | |
WindowReader(window: $window) | |
} | |
.onChange(of: window) { | |
// Can't just use onReceive and NotificationCenter.publisher(for:) because window starts as nil, and we don't want | |
// to register an observer for every window. | |
if let observer { | |
NotificationCenter.default.removeObserver(observer) | |
self.observer = nil | |
} | |
if let window { | |
observer = NotificationCenter.default.addObserver(forName: NSWindow.willCloseNotification, object: window, queue: nil) { _ in | |
action() | |
} | |
} | |
} | |
} | |
} | |
extension View { | |
func onWindowClose(perform action: @escaping () -> Void) -> some View { | |
modifier(OnWindowClose(action: action)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment