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