Add setting to hide the startup picker with a one-time menu-bar hint

Lets someone skip the startup picker entirely; the first time it would've
shown with nothing running, a small popover on the menu bar icon points
there instead, then never again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
bdeshiandClaude Sonnet 5 committed 2026-08-22 12:13:17 +06:00
1 parent 654269a4d2
commit 79395ef9d6
2 files changed
+81 -4

No files matched your search

+68 -2
View File
@@ -41,6 +41,30 @@ enum MenuClickBehavior {
}
}
// Whether the startup picker (see AppDelegate.showStartupPicker) should
// appear at all when nothing's running at launch. Off by default, so the
// existing picker keeps showing up unless someone opts out of it.
enum StartupBehavior {
private static let hidePickerKey = "HideStartupPicker"
static var hidePicker: Bool {
get { UserDefaults.standard.bool(forKey: hidePickerKey) }
set { UserDefaults.standard.set(newValue, forKey: hidePickerKey) }
}
}
// A person who's opted out of the startup picker still needs to discover
// the menu bar icon somehow the very first time — this fires once, ever,
// the first time that situation actually arises, then never again.
private enum MenuBarHintShown {
private static let key = "MenuBarHintShown"
static var value: Bool {
get { UserDefaults.standard.bool(forKey: key) }
set { UserDefaults.standard.set(newValue, forKey: key) }
}
}
final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveStateDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
let menu = NSMenu()
@@ -53,6 +77,7 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveSt
private var accessibilityRecheckScheduled = false
private var activationObserver: NSObjectProtocol?
private var appearanceObserver: NSKeyValueObservation?
private var menuBarHintPopover: NSPopover?
func applicationDidFinishLaunching(_ notification: Notification) {
menu.delegate = self
@@ -91,9 +116,15 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveSt
// Launching this app fresh with nothing running means there's no
// menu-bar title/dots to click yet — offer a picker up front
// instead of leaving the user to discover the dropdown.
// instead of leaving the user to discover the dropdown, unless
// that picker's been turned off, in which case a one-time hint
// takes its place (see MenuBarHintShown).
if currentInfos.filter(\.running).isEmpty {
showStartupPicker(currentInfos)
if StartupBehavior.hidePicker {
showMenuBarHintIfNeeded()
} else {
showStartupPicker(currentInfos)
}
}
UpdateChecker.checkAutomaticallyIfDue()
@@ -403,6 +434,41 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, LiveSt
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in self?.liveState.reconcile() }
}
// Stands in for showStartupPicker when that's been turned off — but
// only the very first time nothing's running at launch, ever. After
// that, someone who opted out of the picker gets silence, same as
// launching with something already running.
private func showMenuBarHintIfNeeded() {
guard !MenuBarHintShown.value, let button = statusItem.button else { return }
MenuBarHintShown.value = true
let label = NSTextField(wrappingLabelWithString: "Claude isn't running — click here to start a profile.")
label.font = .systemFont(ofSize: 13)
label.isEditable = false
label.isBordered = false
label.drawsBackground = false
label.preferredMaxLayoutWidth = 200
let container = NSView()
container.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: container.topAnchor, constant: 12),
label.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -12),
label.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 14),
label.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -14),
])
let viewController = NSViewController()
viewController.view = container
let popover = NSPopover()
popover.contentViewController = viewController
popover.behavior = .transient
menuBarHintPopover = popover
popover.show(relativeTo: button.bounds, of: button, preferredEdge: .maxY)
}
// MARK: - Actions
@objc func pick(_ sender: NSMenuItem) {