From 0ff73333c067af96bcb829c900026d6b12fcff4e Mon Sep 17 00:00:00 2001
From: Zhuohao Zheng <2200296024@qq.com>
Date: Sun, 22 Mar 2026 22:40:56 +0800
Subject: [PATCH] Add hide menu bar icon option with reopen restore logic
---
BLEUnlock/AppDelegate.swift | 48 ++++++++++++++++++++-
BLEUnlock/Base.lproj/Localizable.strings | 1 +
BLEUnlock/Info.plist | 2 +-
BLEUnlock/ja.lproj/Localizable.strings | 1 +
BLEUnlock/zh-Hans.lproj/Localizable.strings | 1 +
5 files changed, 51 insertions(+), 2 deletions(-)
diff --git a/BLEUnlock/AppDelegate.swift b/BLEUnlock/AppDelegate.swift
index 4ee9c91..7fd2801 100644
--- a/BLEUnlock/AppDelegate.swift
+++ b/BLEUnlock/AppDelegate.swift
@@ -9,6 +9,8 @@ func t(_ key: String) -> String {
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemValidation, NSUserNotificationCenterDelegate, BLEDelegate {
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
+ // Stores whether the menu bar icon is hidden.
+ let hideStatusItemPreferenceKey = "hideStatusItemFromMenuBar"
let ble = BLE()
let mainMenu = NSMenu()
let deviceMenu = NSMenu()
@@ -117,6 +119,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
}
func updateRSSI(rssi: Int?, active: Bool) {
+ // Keep updating the status item even when it is hidden.
if let r = rssi {
lastRSSI = r
monitorMenuItem?.title = String(format:"%ddBm", r) + (active ? " (Active)" : "")
@@ -552,6 +555,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
menuItem.state = wakeWithoutUnlocking ? .on : .off
}
+ @objc func toggleHideMenuBarIcon(_ menuItem: NSMenuItem) {
+ let hideMenuBarIcon = !prefs.bool(forKey: hideStatusItemPreferenceKey)
+ prefs.set(hideMenuBarIcon, forKey: hideStatusItemPreferenceKey)
+ menuItem.state = hideMenuBarIcon ? .on : .off
+
+ // Apply the visibility change immediately.
+ statusItem.isVisible = !hideMenuBarIcon
+ }
+
@objc func lockNow() {
guard !isScreenLocked() else { return }
manualLock = true
@@ -650,6 +662,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
item = mainMenu.addItem(withTitle: t("launch_at_login"), action: #selector(toggleLaunchAtLogin), keyEquivalent: "")
item.state = prefs.bool(forKey: "launchAtLogin") ? .on : .off
+
+ item = mainMenu.addItem(withTitle: t("hide_menu_bar_icon"), action: #selector(toggleHideMenuBarIcon), keyEquivalent: "")
+ item.state = prefs.bool(forKey: hideStatusItemPreferenceKey) ? .on : .off
mainMenu.addItem(withTitle: t("set_rssi_threshold"), action: #selector(setRSSIThreshold),
keyEquivalent: "")
@@ -658,6 +673,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
mainMenu.addItem(withTitle: t("about"), action: #selector(showAboutBox), keyEquivalent: "")
mainMenu.addItem(NSMenuItem.separator())
mainMenu.addItem(withTitle: t("quit"), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "")
+ // Keep the menu attached to the status item.
statusItem.menu = mainMenu
}
@@ -673,11 +689,29 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
}
}
+ func resetHiddenMenuBarIconState() {
+ guard prefs.bool(forKey: hideStatusItemPreferenceKey) else { return }
+
+ // Show the icon again when the app is reopened.
+ prefs.set(false, forKey: hideStatusItemPreferenceKey)
+ statusItem.isVisible = true
+
+ if let item = mainMenu.items.first(where: { $0.action == #selector(toggleHideMenuBarIcon) }) {
+ item.state = .off
+ }
+ }
+
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let button = statusItem.button {
button.image = NSImage(named: "StatusBarDisconnected")
- constructMenu()
}
+ constructMenu()
+
+ let hideMenuBarIcon = prefs.bool(forKey: hideStatusItemPreferenceKey)
+
+ // Restore the saved visibility state on launch.
+ statusItem.isVisible = !hideMenuBarIcon
+
ble.delegate = self
if let str = prefs.string(forKey: "device") {
if let uuid = UUID(uuidString: str) {
@@ -730,7 +764,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate, NSMenuItemVa
// otherwise CBCentralManager.scanForPeripherals won't work.
NSApp.setActivationPolicy(.accessory)
}
+
+ func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
+ // Restore the icon when the running app is reopened.
+ resetHiddenMenuBarIconState()
+ return false
+ }
+
+ func applicationDidBecomeActive(_ notification: Notification) {
+ // Also restore the icon when the app becomes active again.
+ resetHiddenMenuBarIconState()
+ }
+
func applicationWillTerminate(_ aNotification: Notification) {
}
}
diff --git a/BLEUnlock/Base.lproj/Localizable.strings b/BLEUnlock/Base.lproj/Localizable.strings
index 4e75488..6b3c705 100644
--- a/BLEUnlock/Base.lproj/Localizable.strings
+++ b/BLEUnlock/Base.lproj/Localizable.strings
@@ -10,6 +10,7 @@
"enter_rssi_threshold_info" = "Device whose RSSI is less than this value will be ignored while scanning.";
"farther" = "⬇Farther";
"launch_at_login" = "Launch at Login";
+"hide_menu_bar_icon" = "Hide Menu Bar Icon";
"lock_delay" = "Delay to Lock";
"lock_now" = "Lock Screen Now";
"lock_rssi" = "Lock RSSI";
diff --git a/BLEUnlock/Info.plist b/BLEUnlock/Info.plist
index a871345..d75447d 100644
--- a/BLEUnlock/Info.plist
+++ b/BLEUnlock/Info.plist
@@ -19,7 +19,7 @@
CFBundleShortVersionString
1.12.2
CFBundleVersion
- 796
+ 805
LSApplicationCategoryType
public.app-category.utilities
LSMinimumSystemVersion
diff --git a/BLEUnlock/ja.lproj/Localizable.strings b/BLEUnlock/ja.lproj/Localizable.strings
index 39910a7..81262df 100644
--- a/BLEUnlock/ja.lproj/Localizable.strings
+++ b/BLEUnlock/ja.lproj/Localizable.strings
@@ -10,6 +10,7 @@
"enter_rssi_threshold_info" = "この値よりRSSIが小さいデバイスはスキャンに表示されません。";
"farther" = "⬇遠い";
"launch_at_login" = "ログイン時に起動";
+"hide_menu_bar_icon" = "メニューバーアイコンを非表示";
"lock_delay" = "ロックするまでの遅延";
"lock_now" = "今すぐロック";
"lock_rssi" = "ロック信号強度";
diff --git a/BLEUnlock/zh-Hans.lproj/Localizable.strings b/BLEUnlock/zh-Hans.lproj/Localizable.strings
index c8a0303..40e2bee 100644
--- a/BLEUnlock/zh-Hans.lproj/Localizable.strings
+++ b/BLEUnlock/zh-Hans.lproj/Localizable.strings
@@ -10,6 +10,7 @@
"enter_rssi_threshold_info" = "扫描设备时会忽略RSSI值低于该值的设备。";
"farther" = "⬇远离";
"launch_at_login" = "开机启动";
+"hide_menu_bar_icon" = "隐藏菜单栏图标";
"lock_delay" = "延迟锁定";
"lock_now" = "立刻锁定屏幕";
"lock_rssi" = "锁定 RSSI";