Hide App Dock Icon

This commit is contained in:
neo773 2026-01-21 01:30:13 +05:30
parent faa622e379
commit 762edea147
No known key found for this signature in database
6 changed files with 148 additions and 1 deletions

View File

@ -364,6 +364,9 @@
}
},
"shouldTranslate" : false
},
"About Secretive" : {
},
"about_build_log_button" : {
"extractionState" : "manual",
@ -1289,6 +1292,12 @@
}
}
}
},
"Agent Not Running" : {
},
"Agent Running" : {
},
"agent_details_could_not_start_error" : {
"extractionState" : "manual",
@ -18524,6 +18533,9 @@
}
}
}
},
"Integrations..." : {
},
"integrationsGitStepGitconfigSectionNote" : {
"extractionState" : "manual",
@ -19264,6 +19276,9 @@
}
}
}
},
"Open Secretive" : {
},
"persist_authentication_accept_button" : {
"comment" : "When the user authorizes an action using a secret that requires unlock, they're shown a notification offering to leave the secret unlocked for a set period of time. This is the title for the notification.",
@ -19636,6 +19651,9 @@
}
}
}
},
"Quit Secretive" : {
},
"reveal_in_finder_button" : {
"extractionState" : "manual",

View File

@ -74,6 +74,8 @@
50E4C4C32E7765DF00C73783 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50E4C4C22E7765DF00C73783 /* AboutView.swift */; };
50E4C4C82E777E4200C73783 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 50E4C4C72E777E4200C73783 /* AppIcon.icon */; };
50E4C4C92E777E4200C73783 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 50E4C4C72E777E4200C73783 /* AppIcon.icon */; };
B3AE1BB82F201243007B797C /* DockVisibilityController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3AE1BB72F201243007B797C /* DockVisibilityController.swift */; };
B3AE1BBA2F20125C007B797C /* MenuBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3AE1BB92F20125C007B797C /* MenuBarView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -240,6 +242,8 @@
50E4C4522E73C78900C73783 /* WindowBackgroundStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowBackgroundStyle.swift; sourceTree = "<group>"; };
50E4C4C22E7765DF00C73783 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
50E4C4C72E777E4200C73783 /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIcon.icon; sourceTree = "<group>"; };
B3AE1BB72F201243007B797C /* DockVisibilityController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DockVisibilityController.swift; sourceTree = "<group>"; };
B3AE1BB92F20125C007B797C /* MenuBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuBarView.swift; sourceTree = "<group>"; };
F418C9A82F0C57F000E9ADF8 /* OpenSource.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = OpenSource.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -333,6 +337,7 @@
504788F02E681F0100B4556F /* Views */ = {
isa = PBXGroup;
children = (
B3AE1BB92F20125C007B797C /* MenuBarView.swift */,
50E4C4C22E7765DF00C73783 /* AboutView.swift */,
50BDCB712E63BAF20072D2E7 /* AgentStatusView.swift */,
50617D8423FCE48E0099B055 /* ContentView.swift */,
@ -441,6 +446,7 @@
508A58B1241ED1EA0069DC07 /* Controllers */ = {
isa = PBXGroup;
children = (
B3AE1BB72F201243007B797C /* DockVisibilityController.swift */,
508A58B2241ED2180069DC07 /* AgentStatusChecker.swift */,
5091D2BB25183B830049FD9B /* ApplicationDirectoryController.swift */,
50571E0224393C2600F76F6C /* JustUpdatedChecker.swift */,
@ -688,6 +694,7 @@
2C4A9D2F2636FFD3008CC8E2 /* EditSecretView.swift in Sources */,
50E4C4532E73C78C00C73783 /* WindowBackgroundStyle.swift in Sources */,
5091D2BC25183B830049FD9B /* ApplicationDirectoryController.swift in Sources */,
B3AE1BB82F201243007B797C /* DockVisibilityController.swift in Sources */,
504789232E697DD300B4556F /* BoxBackgroundStyle.swift in Sources */,
5066A6C22516F303004B5A36 /* SetupView.swift in Sources */,
5065E313295517C500E16645 /* ToolbarButtonStyle.swift in Sources */,
@ -702,6 +709,7 @@
50C385A52407A76D00AF2719 /* SecretDetailView.swift in Sources */,
5099A02423FD2AAA0062B6F2 /* CreateSecretView.swift in Sources */,
50AE97002E5C1A420018C710 /* IntegrationsView.swift in Sources */,
B3AE1BBA2F20125C007B797C /* MenuBarView.swift in Sources */,
50153E20250AFCB200525160 /* UpdateView.swift in Sources */,
5066A6C82516FE6E004B5A36 /* CopyableView.swift in Sources */,
50B8550D24138C4F009958AC /* DeleteSecretView.swift in Sources */,

View File

@ -9,9 +9,10 @@ struct Secretive: App {
@Environment(\.agentLaunchController) var agentLaunchController
@Environment(\.justUpdatedChecker) var justUpdatedChecker
@Environment(\.dockVisibilityController) var dockVisibilityController
@SceneBuilder var body: some Scene {
WindowGroup {
WindowGroup(id: "main") {
ContentView()
.environment(EnvironmentValues._secretStoreList)
.onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in
@ -31,6 +32,11 @@ struct Secretive: App {
.commands {
AppCommands()
}
MenuBarExtra {
MenuBarView()
} label: {
Image(systemName: "key.fill")
}
WindowGroup(id: String(describing: IntegrationsView.self)) {
IntegrationsView()
}
@ -110,6 +116,9 @@ extension EnvironmentValues {
private static let _justUpdatedChecker = JustUpdatedChecker()
@Entry var justUpdatedChecker: any JustUpdatedCheckerProtocol = _justUpdatedChecker
private static let _dockVisibilityController = DockVisibilityController()
@Entry var dockVisibilityController: DockVisibilityController = _dockVisibilityController
@MainActor var secretStoreList: SecretStoreList {
EnvironmentValues._secretStoreList
}

View File

@ -0,0 +1,37 @@
import AppKit
import Observation
@MainActor protocol DockVisibilityControllerProtocol: Observable, Sendable {
var isDockIconVisible: Bool { get }
func showDockIcon()
func hideDockIcon()
func updateVisibility(hasRunSetup: Bool, hasOpenWindows: Bool)
}
@Observable @MainActor final class DockVisibilityController: DockVisibilityControllerProtocol {
private(set) var isDockIconVisible: Bool = true
nonisolated init() {}
func showDockIcon() {
guard !isDockIconVisible else { return }
NSApp.setActivationPolicy(.regular)
isDockIconVisible = true
NSApp.activate(ignoringOtherApps: true)
}
func hideDockIcon() {
guard isDockIconVisible else { return }
NSApp.setActivationPolicy(.accessory)
isDockIconVisible = false
}
func updateVisibility(hasRunSetup: Bool, hasOpenWindows: Bool) {
if !hasRunSetup || hasOpenWindows {
showDockIcon()
} else {
hideDockIcon()
}
}
}

View File

@ -15,6 +15,7 @@ struct ContentView: View {
@Environment(\.secretStoreList) private var storeList
@Environment(\.updater) private var updater
@Environment(\.agentLaunchController) private var agentLaunchController
@Environment(\.dockVisibilityController) private var dockVisibilityController
@AppStorage("defaultsHasRunSetup") private var hasRunSetup = false
@State private var showingCreation = false
@ -41,6 +42,18 @@ struct ContentView: View {
if !hasRunSetup {
runningSetup = true
}
dockVisibilityController.showDockIcon()
}
.onReceive(NotificationCenter.default.publisher(for: NSWindow.willCloseNotification)) { notification in
// When a window closes, check if we should hide the dock icon
Task { @MainActor in
// Small delay to let the window actually close
try? await Task.sleep(for: .milliseconds(100))
let hasVisibleWindows = NSApp.windows.contains { window in
window.isVisible && window.level == .normal && !window.title.isEmpty
}
dockVisibilityController.updateVisibility(hasRunSetup: hasRunSetup, hasOpenWindows: hasVisibleWindows)
}
}
.focusedSceneValue(\.showCreateSecret, .init(isEnabled: !runningSetup) {
showingCreation = true

View File

@ -0,0 +1,62 @@
import SwiftUI
struct MenuBarView: View {
@Environment(\.openWindow) private var openWindow
@Environment(\.agentLaunchController) private var agentLaunchController
var body: some View {
VStack(alignment: .leading, spacing: 4) {
agentStatusSection
Divider()
actionsSection
Divider()
appSection
}
.padding(.vertical, 4)
}
@ViewBuilder
private var agentStatusSection: some View {
HStack(spacing: 6) {
Circle()
.fill(agentLaunchController.running ? Color.green : Color.red)
.frame(width: 8, height: 8)
Text(agentLaunchController.running ? "Agent Running" : "Agent Not Running")
.font(.caption)
}
.padding(.horizontal, 8)
.padding(.vertical, 4)
}
@ViewBuilder
private var actionsSection: some View {
Button("Open Secretive") {
openMainWindow()
}
.keyboardShortcut("O", modifiers: [.command])
Button("Integrations...") {
openWindow(id: String(describing: IntegrationsView.self))
NSApp.activate(ignoringOtherApps: true)
}
}
@ViewBuilder
private var appSection: some View {
Button("About Secretive") {
openWindow(id: String(describing: AboutView.self))
NSApp.activate(ignoringOtherApps: true)
}
Button("Quit Secretive") {
NSApplication.shared.terminate(nil)
}
.keyboardShortcut("Q", modifiers: [.command])
}
private func openMainWindow() {
openWindow(id: "main")
NSApp.activate(ignoringOtherApps: true)
}
}