import AppKit import SwiftUI import CalendarProvider import WeatherProvider /// Führt das Einstellungsfenster selbst. /// /// SwiftUIs `Settings`-Szene wird über `NSApp.sendAction(showSettingsWindow:)` /// geöffnet — ein privater Selektor, dessen Name sich zwischen macOS-Versionen /// schon geändert hat (`showPreferencesWindow:` davor) und der bei /// `.accessory`-Apps ohne Menüleiste unzuverlässig ankommt. Genau das ist hier /// passiert: der Menüeintrag tat nichts. /// /// Ein eigenes `NSWindow` hat diese Abhängigkeit nicht. Es kostet ein paar /// Zeilen mehr und funktioniert dafür. @MainActor final class SettingsWindowController: NSObject, NSWindowDelegate { private var window: NSWindow? /// Muss außerhalb der View liegen, damit ein erneutes Öffnen den Reiter setzen kann. private var selectedTab: SettingsTab = .widgets func show(model: AppModel, calendarModel: CalendarModel, weatherModel: WeatherModel, tab: SettingsTab = .widgets) { selectedTab = tab if window == nil { let hosting = NSHostingController( rootView: SettingsView(model: model, calendarModel: calendarModel, weatherModel: weatherModel, selectedTab: Binding( get: { [weak self] in self?.selectedTab ?? .widgets }, set: { [weak self] in self?.selectedTab = $0 }))) let window = NSWindow(contentViewController: hosting) window.title = "Onyx" window.styleMask = [.titled, .closable, .miniaturizable] window.isReleasedWhenClosed = false window.delegate = self window.center() // Über die Position freuen sich Nutzer mit mehreren Displays: // beim zweiten Öffnen steht es wieder da, wo sie es hingeschoben haben. window.setFrameAutosaveName("onyx.settings") self.window = window } // Ohne `activate` bleibt das Fenster einer .accessory-App hinter der // aktiven App liegen und wirkt, als wäre nichts passiert. NSApp.activate(ignoringOtherApps: true) window?.makeKeyAndOrderFront(nil) } func windowWillClose(_ notification: Notification) { // Zurück in den Hintergrund: Onyx hat sonst weiter den Fokus, obwohl // kein Fenster mehr offen ist. NSApp.hide(nil) } }