mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-04-25 14:57:37 +00:00
128 lines
4.4 KiB
Swift
128 lines
4.4 KiB
Swift
@preconcurrency import AppKit
|
|
import Foundation
|
|
import SwiftUI
|
|
|
|
/// Helper to open the Settings window programmatically.
|
|
///
|
|
/// This utility works with DockIconManager to ensure the Settings window
|
|
/// can be properly brought to front. The dock icon visibility is managed
|
|
/// centrally by DockIconManager.
|
|
@MainActor
|
|
enum SettingsOpener {
|
|
/// SwiftUI's hardcoded settings window identifier
|
|
private static let settingsWindowIdentifier = "com_apple_SwiftUI_Settings_window"
|
|
|
|
/// Opens the Settings window using the environment action via notification
|
|
/// This is needed for cases where we can't use SettingsLink (e.g., from notifications)
|
|
static func openSettings() {
|
|
// Ensure dock icon is visible for window activation
|
|
DockIconManager.shared.temporarilyShowDock()
|
|
|
|
// Simple activation and window opening
|
|
Task { @MainActor in
|
|
// Small delay to ensure dock icon is visible
|
|
try? await Task.sleep(for: .milliseconds(50))
|
|
|
|
// Activate the app
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
|
|
// Always use notification approach since we have dock icon visible
|
|
NotificationCenter.default.post(name: .openSettingsRequest, object: nil)
|
|
|
|
// we center twice to reduce jump but also be more resilient against slow systems
|
|
if let settingsWindow = findSettingsWindow() {
|
|
WindowCenteringHelper.centerOnActiveScreen(settingsWindow)
|
|
}
|
|
|
|
// Wait for window to appear
|
|
try? await Task.sleep(for: .milliseconds(100))
|
|
|
|
// Find and bring settings window to front
|
|
if let settingsWindow = findSettingsWindow() {
|
|
// Center the window
|
|
WindowCenteringHelper.centerOnActiveScreen(settingsWindow)
|
|
|
|
// Ensure window is visible and in front
|
|
settingsWindow.makeKeyAndOrderFront(nil)
|
|
settingsWindow.orderFrontRegardless()
|
|
|
|
// Temporarily raise window level to ensure it's on top
|
|
settingsWindow.level = .floating
|
|
|
|
// Reset level after a short delay
|
|
Task { @MainActor in
|
|
try? await Task.sleep(for: .milliseconds(100))
|
|
settingsWindow.level = .normal
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Finds the settings window using multiple detection methods
|
|
static func findSettingsWindow() -> NSWindow? {
|
|
// Try multiple methods to find the window
|
|
NSApp.windows.first { window in
|
|
// Check by identifier
|
|
if window.identifier?.rawValue == settingsWindowIdentifier {
|
|
return true
|
|
}
|
|
|
|
// Check by title
|
|
if window.isVisible && window.styleMask.contains(.titled) &&
|
|
(window.title.localizedCaseInsensitiveContains("settings") ||
|
|
window.title.localizedCaseInsensitiveContains("preferences")
|
|
)
|
|
{
|
|
return true
|
|
}
|
|
|
|
// Check by content view controller type
|
|
if let contentVC = window.contentViewController,
|
|
String(describing: type(of: contentVC)).contains("Settings")
|
|
{
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
}
|
|
|
|
/// Opens the Settings window and navigates to a specific tab
|
|
static func openSettingsTab(_ tab: SettingsTab) {
|
|
openSettings()
|
|
|
|
Task {
|
|
// Then switch to the specific tab
|
|
NotificationCenter.default.post(
|
|
name: .openSettingsTab,
|
|
object: tab
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Hidden Window View
|
|
|
|
/// A minimal hidden window that enables Settings to work in MenuBarExtra apps.
|
|
/// This is a workaround for FB10184971.
|
|
struct HiddenWindowView: View {
|
|
@Environment(\.openSettings)
|
|
private var openSettings
|
|
|
|
var body: some View {
|
|
Color.clear
|
|
.frame(width: 1, height: 1)
|
|
.onReceive(NotificationCenter.default.publisher(for: .openSettingsRequest)) { _ in
|
|
// Another hack, if we don't wait a runloop we crash in some toolbar logic on macOS Tahoe b1.
|
|
Task { @MainActor in
|
|
openSettings()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Notification Extensions
|
|
|
|
extension Notification.Name {
|
|
static let openSettingsRequest = Notification.Name("openSettingsRequest")
|
|
}
|