main
  1diff -ruN a/plugin.toml b/plugin.toml
  2--- a/plugin.toml	2026-10-13 10:23:24.611263961 +0800
  3+++ b/plugin.toml	2026-10-13 10:23:24.612151446 +0800
  4@@ -51,6 +51,20 @@
  5 default = false
  6 
  7 [[setting]]
  8+key = "hide_when_offline"
  9+type = "bool"
 10+label_key = "settings.hide_when_offline.label"
 11+description_key = "settings.hide_when_offline.description"
 12+default = false
 13+
 14+[[setting]]
 15+key = "auto_select_online"
 16+type = "bool"
 17+label_key = "settings.auto_select_online.label"
 18+description_key = "settings.auto_select_online.description"
 19+default = true
 20+
 21+[[setting]]
 22 key = "battery_display"
 23 type = "select"
 24 label_key = "settings.battery_display.label"
 25diff -ruN a/service.luau b/service.luau
 26--- a/service.luau	2026-10-13 10:23:24.611276193 +0800
 27+++ b/service.luau	2026-10-13 10:23:24.612157136 +0800
 28@@ -161,6 +161,8 @@
 29 -- In-memory device table keyed by id (mirrors original PhoneConnectService.devices).
 30 local devices= {}
 31 local deviceOrder= {}
 32+-- forward-declared: assigned below once persistSelected exists
 33+local autoSelectOnline
 34 -- forward-declared: fetchMpris re-evaluates the poll interval; the definition
 35 -- lives in the Lifecycle section below.
 36 local intervalMs
 37@@ -177,6 +179,7 @@
 38 local function publishDevices()
 39 	noctalia.state.set("pc.devices", snapshotDevices())
 40 	noctalia.state.set("pc.order", deviceOrder)
 41+	if autoSelectOnline then autoSelectOnline() end
 42 end
 43 
 44 -- ── Persistent state (selected device) ──────────────────────────────────────
 45@@ -216,6 +219,24 @@
 46 		saveData(data)
 47 	end
 48 
 49+	-- Never override a selection that is already online, so a manual pick sticks.
 50+	autoSelectOnline = function()
 51+		if noctalia.getConfig("auto_select_online") ~= true then return end
 52+		local sel = noctalia.state.get("pc.selected")
 53+		local cur = sel and devices[sel]
 54+		if cur and cur.isPaired == true and cur.isReachable == true then return end
 55+		for _, id in ipairs(deviceOrder) do
 56+			local d = devices[id]
 57+			if d and d.isPaired == true and d.isReachable == true then
 58+				if sel ~= id then
 59+					noctalia.state.set("pc.selected", id)
 60+					persistSelected(id)
 61+				end
 62+				return
 63+			end
 64+		end
 65+	end
 66+
 67 	local function persistImageMap(map)
 68 		local data = loadData()
 69 		data.imageMap = map
 70diff -ruN a/translations/en.json b/translations/en.json
 71--- a/translations/en.json	2026-10-13 10:23:24.611362840 +0800
 72+++ b/translations/en.json	2026-10-13 10:23:24.612202053 +0800
 73@@ -71,6 +71,10 @@
 74     "unpaired": "Unpaired"
 75   },
 76   "settings": {
 77+    "auto_select_online": {
 78+      "description": "Automatically select the first online device while the current selection is offline.",
 79+      "label": "Auto-select Online Device"
 80+    },
 81     "battery_display": {
 82       "description": "Choose whether the bar widget shows the battery icon, percentage, both, or neither.",
 83       "hidden": "Hidden",
 84@@ -95,6 +99,10 @@
 85       "description": "Show a quick action to send the clipboard to the device.",
 86       "label": "Show Clipboard Action"
 87     },
 88+    "hide_when_offline": {
 89+      "description": "Hide the bar widget entirely while no device is connected.",
 90+      "label": "Hide When Offline"
 91+    },
 92     "language": {
 93       "description": "Display language",
 94       "en": "English",
 95diff -ruN a/translations/zh-Hans.json b/translations/zh-Hans.json
 96--- a/translations/zh-Hans.json	2026-10-13 10:23:24.611373924 +0800
 97+++ b/translations/zh-Hans.json	2026-10-13 10:23:24.612212356 +0800
 98@@ -69,6 +69,10 @@
 99     "unpaired": "未配对"
100   },
101   "settings": {
102+    "auto_select_online": {
103+      "description": "当前选中设备离线时,自动选择第一个在线的设备。",
104+      "label": "自动选择在线设备"
105+    },
106     "battery_display": {
107       "description": "选择栏部件显示电池图标、百分比、两者或都不显示。",
108       "hidden": "隐藏",
109@@ -93,6 +97,10 @@
110       "description": "显示一键发送剪贴板到设备的快捷操作。",
111       "label": "显示剪贴板操作"
112     },
113+    "hide_when_offline": {
114+      "description": "没有设备连接时完全隐藏栏部件。",
115+      "label": "离线时隐藏"
116+    },
117     "language": {
118       "description": "显示语言。",
119       "en": "English",
120diff -ruN a/widget.luau b/widget.luau
121--- a/widget.luau	2026-10-13 10:23:24.611378697 +0800
122+++ b/widget.luau	2026-10-13 10:23:24.612217417 +0800
123@@ -54,8 +54,25 @@
124 	return nil
125 end
126 
127+local function anyOnline()
128+	local devices = noctalia.state.get("pc.devices") or {}
129+	local order = noctalia.state.get("pc.order") or {}
130+	for _, id in ipairs(order) do
131+		local d = devices[id]
132+		if d and d.isPaired == true and d.isReachable == true then return true end
133+	end
134+	return false
135+end
136+
137 local function render()
138 	local backend = noctalia.state.get("pc.backend") or { available = false }
139+
140+	if noctalia.getConfig("hide_when_offline") == true and not anyOnline() then
141+		barWidget.setVisible(false)
142+		return
143+	end
144+	barWidget.setVisible(true)
145+
146 	local d = selectedDevice()
147 	local enableCharging = noctalia.getConfig("enable_charging_animation")
148 	local showDeviceName = noctalia.getConfig("show_device_name") == true