fix flick issue

This commit is contained in:
abue-ammar
2026-07-21 23:27:45 +06:00
parent 1db9f5dc3d
commit 3928f3c457
3 changed files with 26 additions and 29 deletions
+9 -15
View File
@@ -152,33 +152,27 @@ final class AppCore: ObservableObject {
showPalette(mode: .launcher, restoreAnyMode: true)
}
/// Settings runs in its own window (the SwiftUI `Settings` scene is unreliable for accessory apps), raised via the same controller as About.
func showSettings() {
auxWindows.show(
/// Settings runs in its own window (the SwiftUI `Settings` scene is unreliable for accessory apps). A fresh window mounts directly on `tab` (no first-frame flicker); an already-open one is switched in place.
func showSettings(tab: SettingsTab = .general) {
let isNew = auxWindows.show(
id: "settings", title: "Settings", size: CGSize(width: 720, height: 650),
seamlessTitleBar: true
) {
SettingsRootView()
SettingsRootView(initialTab: tab)
.environmentObject(self.appIndex)
.environmentObject(self.visibility)
}
if !isNew {
NotificationCenter.default.post(name: .tinycastSelectSettingsTab, object: tab)
}
}
/// Open Settings on the Backup pane (used by the "Import from Raycast" command, which needs the passphrase field).
func showBackupSettings() {
showSettings()
// Post on the next runloop so the freshly-mounted pane's observer is already listening.
DispatchQueue.main.async {
NotificationCenter.default.post(name: .tinycastShowBackupSettings, object: nil)
}
showSettings(tab: .backup)
}
/// About lives as a pane inside Settings now, so this opens Settings and switches to it.
func showAbout() {
showSettings()
DispatchQueue.main.async {
NotificationCenter.default.post(name: .tinycastShowAbout, object: nil)
}
showSettings(tab: .about)
}
/// The first-run wizard: palette shortcut, Accessibility, Raycast import. Also re-runnable from Settings.
+7 -1
View File
@@ -112,14 +112,19 @@ private struct AboutLinkButton: View {
final class AuxWindowController: NSObject, NSWindowDelegate {
private var windows: [String: NSWindow] = [:]
/// Returns `true` when a new window was created, `false` when an existing one was re-raised.
@discardableResult
func show<Content: View>(
id: String, title: String, size: CGSize, seamlessTitleBar: Bool = false,
@ViewBuilder content: () -> Content
) {
) -> Bool {
let window: NSWindow
let isNew: Bool
if let existing = windows[id] {
window = existing
isNew = false
} else {
isNew = true
var style: NSWindow.StyleMask = [.titled, .closable]
if seamlessTitleBar { style.insert(.fullSizeContentView) }
window = NSWindow(
@@ -153,6 +158,7 @@ final class AuxWindowController: NSObject, NSWindowDelegate {
DispatchQueue.main.async {
window.makeKeyAndOrderFront(nil)
}
return isNew
}
/// Re-focus an open aux window on reopen (Dock-icon click); returns false when none is open. `windows` only holds live windows (`windowWillClose` prunes them).
@@ -1,12 +1,11 @@
import SwiftUI
extension Notification.Name {
static let tinycastShowSettings = Notification.Name("TinycastShowSettings")
static let tinycastShowBackupSettings = Notification.Name("TinycastShowBackupSettings")
static let tinycastShowAbout = Notification.Name("TinycastShowAbout")
/// Switch an already-open Settings window to a pane (object: the target `SettingsTab`).
static let tinycastSelectSettingsTab = Notification.Name("TinycastSelectSettingsTab")
}
private enum SettingsTab: Int, CaseIterable, Identifiable {
enum SettingsTab: Int, CaseIterable, Identifiable {
case general, clipboard, emoji, permissions, shortcuts, backup, about
var id: Int { rawValue }
@@ -49,7 +48,11 @@ private enum SettingsTab: Int, CaseIterable, Identifiable {
}
struct SettingsRootView: View {
@State private var tab: SettingsTab = .general
@State private var tab: SettingsTab
init(initialTab: SettingsTab = .general) {
_tab = State(initialValue: initialTab)
}
var body: some View {
HStack(spacing: 0) {
@@ -75,14 +78,8 @@ struct SettingsRootView: View {
)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onReceive(NotificationCenter.default.publisher(for: .tinycastShowSettings)) { _ in
tab = .general
}
.onReceive(NotificationCenter.default.publisher(for: .tinycastShowBackupSettings)) { _ in
tab = .backup
}
.onReceive(NotificationCenter.default.publisher(for: .tinycastShowAbout)) { _ in
tab = .about
.onReceive(NotificationCenter.default.publisher(for: .tinycastSelectSettingsTab)) { note in
if let target = note.object as? SettingsTab { tab = target }
}
}