From 0fcfbb245af1768733909e62081b358d713de5a7 Mon Sep 17 00:00:00 2001 From: brightestautumn Date: Wed, 9 Sep 2026 00:10:57 +0530 Subject: [PATCH 1/2] refactor: refactor phone-operate UI, service logic, and persistence layer with updated translations and assets --- phone-operate/README.md | 34 +- phone-operate/lib/persistence.luau | 21 + phone-operate/panel.luau | 1318 ++++++++++------------- phone-operate/plugin.toml | 12 +- phone-operate/service.luau | 11 - phone-operate/thumbnail.webp | Bin 65570 -> 69772 bytes phone-operate/translations/en.json | 63 +- phone-operate/translations/zh-Hans.json | 57 +- 8 files changed, 663 insertions(+), 853 deletions(-) diff --git a/phone-operate/README.md b/phone-operate/README.md index bd71572f7..113d32ab1 100644 --- a/phone-operate/README.md +++ b/phone-operate/README.md @@ -1,8 +1,8 @@ # Phone Operate Mirror and control your Android phone with scrcpy (wired or wireless), and run -KDE Connect device actions (ring, ping, clipboard, SMS, media) — all from one -device card in a Noctalia panel. +KDE Connect device actions (ring, ping, clipboard, SMS, media) — all from a +unified Noctalia panel. ## Plugin @@ -40,18 +40,24 @@ noctalia msg panel-toggle icefish/phone-operate:main_floating noctalia msg panel-toggle icefish/phone-operate:main_widget ``` -The panel lists KDE Connect devices. Each device card offers: - -- **Cast** (when the device also has an adb connection, matched by LAN IP): opens - the parameter panel. Pick a preset or set resolution / bitrate / fps, then - press **Start Casting**. USB devices cast directly; wireless first-time setup - needs the pairing port, debug port, and pairing code from the phone's Wireless - debugging screen. -- **Ring / Ping / Browse / Clipboard / Share / Unpair** -- **Media controls** (now playing, previous / play-pause / next / stop, seek, volume) -- **Send SMS** (destination + message) - -Click a device's avatar to change its image, or its name to rename it. +The panel provides a split workspace for managing KDE Connect and ADB devices: + +- **Sidebar**: Lists paired and available devices with connection status and + unpair / disconnect buttons. Quick action buttons trigger **Ring**, **Ping**, + **Browse**, **Clipboard**, and **Share**. +- **Dashboard**: Shows selected device avatar, battery percentage, Wi-Fi / USB + link info, and an editable device alias (pencil icon). +- **Cast & Connect**: Mirrors and controls the phone screen via `scrcpy`. Pick + a preset (**HD**, **Bal**, **Save**) or customize resolution, bitrate, and + frame rate. Toggle **Screen Off** to mirror while keeping the phone display + dark, or **Record** to save the session to a video file. Press **Cast** / + **Stop** to manage the session. USB devices cast directly; wireless devices + switch between **Pair** (one-time setup with pair port and 6-digit PIN) and + **Connect** (reconnects to the phone's debug port). +- **Messages**: Send SMS with phone number, clear button (`x`), persistent + favorite contacts with names, inline renaming, and live search while typing. +- **Media bar**: Bottom playback bar showing album art, now playing title and + artist, previous / play-pause / next transport buttons, and a seek slider. ### Bar widget diff --git a/phone-operate/lib/persistence.luau b/phone-operate/lib/persistence.luau index 9ae217933..df8570129 100644 --- a/phone-operate/lib/persistence.luau +++ b/phone-operate/lib/persistence.luau @@ -84,4 +84,25 @@ function M.loadName(device_id) return data.names and data.names[device_id] or nil end +-- 常用联系人:{ { number = "12345", name = "Alice" }, ... } +function M.loadFavorites() + local data = loadAll() + local list = data.favorites or {} + local clean = {} + for _, f in ipairs(list) do + if type(f) == "string" then + table.insert(clean, { number = f, name = "" }) + elseif type(f) == "table" and f.number then + table.insert(clean, { number = tostring(f.number), name = tostring(f.name or "") }) + end + end + return clean +end + +function M.saveFavorites(favs) + local data = loadAll() + data.favorites = favs + saveAll(data) +end + return M diff --git a/phone-operate/panel.luau b/phone-operate/panel.luau index 51f98a226..55cd5a98c 100644 --- a/phone-operate/panel.luau +++ b/phone-operate/panel.luau @@ -1,870 +1,690 @@ --- panel.luau --- 合并面板:phone-connect 的完整 UI(设备卡/媒体/短信/操作栏/页脚)+ scrcpy: --- adb 设备(id 前缀 "adb:")在右栏显示 投屏/停止、投屏参数、断开; --- 「投屏参数」展开时覆盖左栏。参数读 lib/persistence,写经 pc.cmd 通道。 - +-- panel.luau — merged UI: device card / media / SMS / toolbar / scrcpy cast +-- adb devices (id prefixed "adb:") show cast/stop, cast params, disconnect in right column. +-- Params read via lib/persistence, write via pc.cmd. local persistence = require("./lib/persistence.luau") local common = require("./lib/common.luau") +local t, sendCmd = common.t, common.sendCmd + +local function tr(key, fb) + local v = t(key); if not v or v == key then return fb or key end; return v +end -local t = common.t -local sendCmd = common.sendCmd +local smsDrafts, smsFavorites, mediaDragState, deviceNameEdits, favNameEdits = {}, persistence.loadFavorites(), {}, {}, {} +local isConnectMode, castPort, castDebugPort, castCode, connectAddr, smsDestRev = false, "", "", "", "", 0 --- ── 每设备 UI 状态 ─────────────────────────────────────────────────────────── -local smsDrafts = {} local function draftFor(id) - local d = smsDrafts[id] - if not d then - d = { dest = "", msg = "" } - smsDrafts[id] = d - end - return d + id = id or "default"; if not smsDrafts[id] then smsDrafts[id] = { dest = "", msg = "" } end; return smsDrafts[id] end -local mediaDragState = {} -local volumeDragState = {} -local mutedPrevVolume = {} -local deviceNameEdits = {} - --- ── scrcpy 参数状态 ────────────────────────────────────────────────────────── --- 注:无 activePreset 状态变量--按钮高亮由 detectPreset(params) 值推导 -local paramsExpanded = false -local pairExpanded = false -local pairAddr = "" -local pairCode = "" --- 首次无线投屏的配对输入(配对端口 + 调试端口 + 配对码) -local castPort = "" -local castDebugPort = "5555" -local castCode = "" - --- 每设备参数内存缓存 [adbId] = params。paramsPanel 每次 render 会重建, --- 若每次都从磁盘 loadParams,拖动滑块时 onChange 的内存修改会被磁盘旧值 --- 覆盖(数字回退)。缓存保证 render 期间读到的都是最新值,commit 才写盘。 +-- Per-device param cache — prevents disk reads from overwriting in-memory slider changes local paramCache = {} - local function paramsFor(adbId) - local p = paramCache[adbId] - if not p then - p = persistence.loadParams(adbId) - paramCache[adbId] = p - end - return p + if not paramCache[adbId] then paramCache[adbId] = persistence.loadParams(adbId) end; return paramCache[adbId] end local PRESETS = { - hd = { max_size = 1920, bit_rate = 16, max_fps = 60 }, - perf = { max_size = 1280, bit_rate = 8, max_fps = 60 }, - save = { max_size = 1024, bit_rate = 4, max_fps = 30 }, + hd = { max_size = 1920, bit_rate = 16, max_fps = 60 }, + perf = { max_size = 1280, bit_rate = 8, max_fps = 60 }, + save = { max_size = 1024, bit_rate = 4, max_fps = 30 }, } --- 当前参数命中的预设档;与任何预设都不匹配则为 "custom"。 --- 按钮高亮由 params 值推导而非独立状态变量:引擎对程序化设值的滑块 --- 也会异步触发 onChange(setValue 回声),独立变量会被回声改写导致 --- 「点预设高亮停在自定义」;值推导则天然免疫回声。 -local function detectPreset(params) - for key, p in pairs(PRESETS) do - if params.max_size == p.max_size - and params.bit_rate == p.bit_rate - and params.max_fps == p.max_fps then - return key - end +-- Derived from values (not separate state) to be immune to slider onChange echo +local function detectPreset(p) + for k, v in pairs(PRESETS) do + if p.max_size == v.max_size and p.bit_rate == v.bit_rate and p.max_fps == v.max_fps then return k end end return "custom" end --- 投屏目标解析:adb 设备用它自身;KDE 设备用 IP 匹配到的 adb 序列号 --- (service 已按局域网 IP 匹配填充 d.adbId),无匹配时回退到 "IP:5555"。 +-- Resolve adb cast target for a device local function castTarget(d) - if not d then return nil end - local allDevices = noctalia.state.get("pc.devices") or {} - local adbId - if d.source == "adb" then - adbId = d.adbId - else - adbId = d.adbId or (d.ipv4 and (d.ipv4 .. ":5555")) - end - if not adbId then return nil end - local adbDev = allDevices["adb:" .. adbId] - local ip = adbDev and adbDev.ip or (d.source ~= "adb" and d.ipv4) or common.ipFromSerial(adbId) - return { - adbId = adbId, - ip = ip, - online = adbDev and adbDev.isReachable == true or false, - transport = adbDev and adbDev.transport or "wifi", - } + if not d then return { adbId = "device", ip = nil, online = false, transport = "wifi" } end + local all = noctalia.state.get("pc.devices") or {} + local adbId = d.source == "adb" and d.adbId or d.adbId or (d.ipv4 and (d.ipv4 .. ":5555")) or (d.id and ("kde:" .. d.id)) or d.id or "device" + local ad = all["adb:" .. adbId] or all[adbId] + return { adbId = adbId, ip = ad and ad.ip or (d.source ~= "adb" and d.ipv4) or common.ipFromSerial(adbId), + online = ad and ad.isReachable == true or false, transport = ad and ad.transport or "wifi" } end --- ── 工具 ───────────────────────────────────────────────────────────────────── -local fmtTime = function(ms) +-- ── Helpers ───────────────────────────────────────────────────────────────── +local function fmtTime(ms) if type(ms) ~= "number" or ms <= 0 then return "0:00" end local s = math.floor(ms / 1000) - local m = math.floor(s / 60) - s = s % 60 - return string.format("%d:%02d", m, s) + return string.format("%d:%02d", math.floor(s / 60), s % 60) end --- ── 头部:连接数 + 设备切换器 + 刷新/关闭 ───────────────────────────────────── -local function headerRow(order, devices, sel) - local connected = 0 - for _, id in ipairs(order) do - local d = devices[id] - if d and d.isPaired and d.isReachable then connected = connected + 1 end - end - local connText = t("panel.devices_connected"):gsub("{connected}", tostring(connected)) - local aliasMap = noctalia.state.get("pc.aliasMap") or {} - local multi = #order > 1 - local kids = { - ui.glyph({ name = "device-mobile", size = 18, color = "primary" }), - ui.label({ text = connText, fontSize = 13, fontWeight = "medium", - color = "on_surface", flexGrow = multi and 0 or 1 }), - } - if multi then - for idx, id in ipairs(order) do - local d = devices[id] - if d then - local isSel = id == sel - local devName = aliasMap[id] or d.name or "Your-Phone" - table.insert(kids, ui.button({ - key = "sw-" .. id, - text = tostring(idx), - glyph = d.source == "adb" - and (d.transport == "wifi" and "wifi" or "usb") - or common.deviceGlyph(d), - variant = isSel and "primary" or "outline", - controlSize = "sm", - selected = isSel, - flexGrow = 1, - tooltip = devName, - onClick = function() - -- 切换设备不自动展开投屏参数,避免打断浏览 - paramsExpanded = false - sendCmd({ op = "select", device = id }) - end, - })) - end - end - end - table.insert(kids, ui.button({ key = "add-device", glyph = "plus", variant = "ghost", - controlSize = "sm", width = 32, height = 32, tooltip = t("panel.pair_add"), - onClick = function() - pairExpanded = true - render() - end })) - table.insert(kids, ui.button({ glyph = "refresh", variant = "ghost", controlSize = "sm", - tooltip = t("action.refresh"), - onClick = function() sendCmd({ op = "refresh" }) end })) - table.insert(kids, ui.button({ glyph = "close", variant = "ghost", controlSize = "sm", - tooltip = t("panel.close"), - onClick = function() panel.close() end })) - return ui.row({ gap = 8, align = "center" }, kids) +local function truncate(s, limit) + if not s or s == "" then return "" end + local len = utf8.len(s) + if not len then return (#s > limit) and (s:sub(1, limit) .. "…") or s end + if len <= limit then return s end + local cut = utf8.offset(s, limit + 1) + return (cut and s:sub(1, cut - 1) or s) .. "…" end --- ── 设备卡 ─────────────────────────────────────────────────────────────────── -local function adbDeviceCard(d) - local online = d.isReachable == true - local runningMap = noctalia.state.get("pc.running") or {} - local casting = runningMap[d.adbId] == true - local statusText = online and t("status.connected") or t("status.offline") - local statusColor = online and "primary" or "on_surface_variant" - - return ui.row({ key = "device-card", gap = 10, padding = 12, radius = 10, fill = "surface/0.7", - border = "primary/0.2", borderWidth = 1, align = "center" }, { - ui.box({ width = 44, height = 44, radius = 22, fill = "primary/0.15" }, { - ui.glyph({ name = d.transport == "wifi" and "wifi" or "usb", - size = 24, color = "primary" }), - }), - ui.column({ gap = 3, flexGrow = 1, minWidth = 0 }, { - ui.label({ text = d.name, fontSize = 14, fontWeight = "bold", - color = "on_surface", maxLines = 1 }), - ui.row({ gap = 6, align = "center" }, { - ui.row({ radius = 8, fill = statusColor .. "/0.15", paddingH = 6, paddingV = 2 }, { - ui.label({ text = statusText, fontSize = 10, color = statusColor }), - }), - casting and ui.row({ radius = 8, fill = "primary/0.15", paddingH = 6, paddingV = 2 }, { - ui.label({ text = t("status.mirroring"), fontSize = 10, color = "primary" }), - }) or nil, - }), - }), - }) +local function isDeviceConnected(d) + return d and d.id ~= "default" and ((d.source == "adb" and d.isReachable == true) or (d.isPaired == true and d.isReachable == true)) or false +end +local function isDeviceOffline(d) + return d and d.id ~= "default" and not isDeviceConnected(d) and d.source ~= "adb" and d.isPaired == true or false end -local function deviceCard(d) - if d.source == "adb" then - return adbDeviceCard(d) +-- Notify with the right error for offline / disconnected; returns true if NOT connected +local function notifyIfDisconnected(d) + if isDeviceConnected(d) then return false end + if isDeviceOffline(d) then + noctalia.notifyError(tr("status.offline", "Offline"), tr("error.device_offline_hint", "Device is offline.")) + else + noctalia.notifyError(tr("error.no_device", "No device connected"), tr("error.no_device_hint", "Connect a device first.")) end + return true +end - local reachable = d.isPaired == true and d.isReachable == true - local aliasMap = noctalia.state.get("pc.aliasMap") or {} - local name = aliasMap[d.id] or d.name or "Your-Phone" - local glyph = common.deviceGlyph(d) - local imgMap = noctalia.state.get("pc.imageMap") or {} - local imgPath = imgMap[d.id] - if imgPath and imgPath ~= "" and not noctalia.fileExists(imgPath) then - noctalia.log("[phone-operate] image not found: " .. imgPath) - end +-- Themed input — avoids repeating 5 style props on every ui.input call +local function mkInput(p) + p.controlSize = "sm"; p.paddingH = 4; p.fill = "surface/0.8" + p.border = "outline/0.3"; p.borderWidth = 1; p.radius = 8 + return ui.input(p) +end - local statusText, statusColor - if not reachable then - statusText = t("status.offline") - statusColor = "on_surface_variant" - else - statusText = t("status.connected") - statusColor = "primary" +-- Resolve drag-frozen slider value; clears stale drag state as side effect +local function frozenDragValue(stateMap, id, fallback) + local st = id and stateMap[id] or nil + if st and st.dragging then + if (os.clock() - (st.at or 0)) < 2.0 then return st.position, true end + stateMap[id] = nil end + return fallback, false +end - local charge = d.batteryCharge - local hasCharge = type(charge) == "number" and charge >= 0 - local chargeText = hasCharge and (tostring(charge) .. "%") or "--" - local chargeColor = "on_surface" - if hasCharge and charge <= 20 then chargeColor = "error" end - local charging = d.batteryCharging == true - - local netText = (d.networkType and d.networkType ~= "") - and (d.networkType .. (type(d.networkStrength) == "number" - and d.networkStrength >= 0 and (" " .. tostring(d.networkStrength) .. "/4") or "")) - or "--" - - local vol = tonumber(d.mediavolume) - local hasVol = type(vol) == "number" and vol >= 0 - local muted = hasVol and vol <= 0 - local vDrag = volumeDragState[d.id] - local vFrozen = vDrag and vDrag.dragging and (os.clock() - (vDrag.at or 0)) < 2.0 - if vDrag and vDrag.dragging and not vFrozen then volumeDragState[d.id] = nil end - local volValue = vFrozen and vDrag.position or (hasVol and vol or 0) - local volLabel = hasVol and (tostring(math.floor(volValue)) .. "%") or "--" - - local function toggleMute() - if not hasVol then return end - if muted then - local restore = mutedPrevVolume[d.id] or 50 - sendCmd({ op = "media_set_volume", device = d.id, volume = tostring(restore) }) - else - mutedPrevVolume[d.id] = vol - sendCmd({ op = "media_set_volume", device = d.id, volume = "0" }) - end +-- ── Device sidebar ────────────────────────────────────────────────────────── +local function deviceSidebar(visibleOrder, devices, sel) + local aliasMap = noctalia.state.get("pc.aliasMap") or {} + local paired, available = {}, {} + for _, id in ipairs(visibleOrder) do + local d = devices[id] + if d then table.insert(d.source == "adb" or d.isPaired == true and paired or available, id) end end - local volumeGroup - if hasVol then - volumeGroup = ui.row({ gap = 4, align = "center", width = 132 }, { - ui.button({ - glyph = muted and "volume-off" or "volume", - variant = "ghost", - controlSize = "sm", - glyphSize = 13, - tooltip = t(muted and "media.unmute" or "media.mute"), - onClick = toggleMute, - }), - ui.label({ text = volLabel, fontSize = 10, color = "on_surface_variant", width = 34 }), - ui.slider({ - key = "vol-" .. d.id, - min = 0, max = 100, step = 1, value = volValue, - controlSize = "sm", enabled = reachable, flexGrow = 1, - onChange = function(v) - volumeDragState[d.id] = { dragging = true, position = tonumber(v) or 0, at = os.clock() } - end, - onDragEnd = function() - local st = volumeDragState[d.id] - local target = (st and st.position) or (hasVol and vol or 0) - volumeDragState[d.id] = nil - sendCmd({ op = "media_set_volume", device = d.id, volume = tostring(target) }) - end, + local items = {} + for _, id in ipairs(paired) do + local d = devices[id] + local isSel = id == sel + local name = aliasMap[id] or d.name or "Device" + local reachable = (d.source == "adb" and d.isReachable == true) + or (d.isPaired == true and d.isReachable == true) + local status = reachable and tr("status.connected", "Connected") + or (d.source == "adb" and tr("status.disconnected", "Disconnected") + or tr("status.offline", "Offline")) + local isAdb = d.source == "adb" + local actionBtn = ui.button({ key = "unp-" .. id, + glyph = isAdb and "plug-off" or "link-off", + variant = "ghost", controlSize = "sm", glyphSize = 13, + tooltip = tr(isAdb and "action.disconnect" or "action.unpair", isAdb and "Disconnect" or "Unpair"), + onClick = function() + if isAdb then sendCmd({ op = "adb_disconnect", device = d.adbId }) + else sendCmd({ op = "unpair", device = id }) end + end }) + table.insert(items, ui.row({ + key = "dev-" .. id, gap = 6, paddingH = 8, paddingV = 6, radius = 8, align = "center", + fill = isSel and "primary/0.12" or "surface/0.8", border = isSel and "primary/0.3" or nil, borderWidth = isSel and 1 or 0, + onClick = function() sendCmd({ op = "select", device = id }) end, + }, { + ui.column({ gap = 1, flexGrow = 1, minWidth = 0 }, { + ui.label({ text = name, fontSize = 13, fontWeight = isSel and "bold" or "normal", color = "on_surface", maxLines = 1 }), + ui.label({ text = status, fontSize = 11, color = reachable and "primary" or "on_surface_variant" }), }), - }) - end - - local function pickImage() - sendCmd({ op = "pick_image", device = d.id }) + actionBtn, + })) end - local function commitName(v) - local newName = (v or ""):gsub("^%s+", ""):gsub("%s+$", "") - deviceNameEdits[d.id] = nil - sendCmd({ op = "set_alias", device = d.id, alias = newName }) - render() + if #available > 0 then + table.insert(items, ui.label({ text = tr("panel.available", "AVAILABLE"), fontSize = 11, + fontWeight = "bold", color = "on_surface_variant", paddingH = 4, paddingV = 4 })) + for _, id in ipairs(available) do + local d = devices[id] + table.insert(items, ui.row({ key = "dev-" .. id, gap = 6, paddingH = 8, paddingV = 6, radius = 8, fill = "surface/0.3", align = "center" }, { + ui.label({ text = d.name or "Device", fontSize = 13, color = "on_surface_variant", maxLines = 1, flexGrow = 1 }), + ui.button({ key = "pair-" .. id, glyph = "link", variant = "ghost", controlSize = "sm", glyphSize = 13, + tooltip = tr("action.pair", "Pair"), onClick = function() sendCmd({ op = "pair", device = id }) end }), + })) + end end - return ui.row({ key = "device-card", gap = 10, padding = 12, radius = 10, fill = "surface/0.7", - border = "primary/0.2", borderWidth = 1, align = "center" }, { - imgPath and ui.image({ path = imgPath, width = 44, height = 44, - radius = 22, fit = "cover", onClick = pickImage }) - or ui.box({ width = 44, height = 44, radius = 22, fill = "primary/0.15", - onClick = pickImage }, { - ui.glyph({ name = glyph, size = 24, color = "primary" }), - ui.glyph({ name = "pencil", size = 10, color = "on_surface_variant" }), - }), - ui.column({ gap = 3, flexGrow = 1, minWidth = 0 }, { - deviceNameEdits[d.id] and ui.input({ - key = "name-edit-" .. d.id, - value = name, - placeholder = name, - controlSize = "sm", - onSubmit = commitName, - }) - or ui.row({ gap = 4, align = "center", onClick = function() - deviceNameEdits[d.id] = true - render() - end }, { - ui.label({ text = name, fontSize = 14, fontWeight = "bold", - color = "on_surface", maxLines = 1 }), - ui.glyph({ name = "pencil", size = 10, color = "on_surface_variant" }), - }), - ui.row({ gap = 6, align = "center" }, { - ui.row({ radius = 8, fill = statusColor .. "/0.15", paddingH = 6, paddingV = 2 }, { - ui.label({ text = statusText, fontSize = 10, color = statusColor }), - }), - }), - }), - volumeGroup, - ui.column({ gap = 2, align = "center", width = 52 }, { - ui.glyph({ name = "antenna", size = 16, - color = (reachable and d.networkType and d.networkType ~= "") and "primary" or "on_surface_variant" }), - ui.label({ text = netText, fontSize = 9, color = "on_surface_variant" }), - }), - ui.column({ gap = 2, align = "center", width = 52 }, { - ui.glyph({ name = common.batteryGlyph(charge, charging), size = 16, color = chargeColor }), - ui.label({ text = chargeText, fontSize = 10, fontWeight = "medium", color = chargeColor }), + local kids = { + ui.row({ align = "center", justify = "space_between", paddingH = 5, paddingV = 0 }, { + ui.label({ text = tr("panel.devices", "DEVICES"), fontSize = 14, fontWeight = "bold", color = "on_surface" }), + ui.button({ glyph = "refresh", variant = "ghost", controlSize = "sm", + tooltip = tr("action.refresh", "Refresh"), + onClick = function() sendCmd({ op = "refresh" }) end }), }), - }) -end - --- ── 右栏操作按钮 ───────────────────────────────────────────────────────────── --- 右栏固定宽 + 按钮内容宽(右栏宽 - scroll padding 16)。按钮固定宽度让 --- label 在 maxWidth 内省略号,不溢出;改右栏宽时同步改这里。 -local RIGHT_COL_WIDTH = 110 -local RIGHT_BTN_WIDTH = RIGHT_COL_WIDTH - 16 - -local function vActionBtn(text, glyph, onClick, variant, tooltip) - return ui.button({ text = text, glyph = glyph, variant = variant or "outline", - controlSize = "sm", width = RIGHT_BTN_WIDTH, tooltip = tooltip, onClick = onClick }) -end - -local function rightColumn(d) - if d.source == "adb" then - local runningMap = noctalia.state.get("pc.running") or {} - local casting = runningMap[d.adbId] == true - local btns = {} - -- 未投屏时点「投屏」展开左侧参数面板(含开始投屏),不再直接开投 - table.insert(btns, vActionBtn(casting and t("action.stop") or t("action.cast"), - casting and "player-stop" or "player-play", - function() - if casting then - sendCmd({ op = "stop_cast", device = d.adbId }) - else - paramsExpanded = true - render() - end - end, casting and "destructive" or "primary")) - table.insert(btns, vActionBtn(t("panel.params"), "adjustments", - function() - paramsExpanded = not paramsExpanded - render() - end, paramsExpanded and "primary" or "outline")) - table.insert(btns, vActionBtn(t("action.disconnect"), "plug-off", - function() sendCmd({ op = "adb_disconnect", device = d.adbId }) end, "ghost")) - return ui.column({ key = "right-col", width = RIGHT_COL_WIDTH }, { - ui.scroll({ key = "right-scroll", flexGrow = 1, gap = 8, padding = 8, align = "stretch" }, btns), - }) + } + if #items > 0 then + table.insert(kids, ui.scroll({ key = "dev-scroll", flexGrow = 1, gap = 4 }, items)) + else + table.insert(kids, ui.column({ flexGrow = 1, align = "center", justify = "center" }, { + ui.label({ text = tr("panel.empty", "No devices found. Pair a device in KDE Connect."), + fontSize = 12, color = "on_surface_variant", textAlign = "center" }), + })) end + return ui.column({ key = "sidebar", gap = 6, flexGrow = 1, + fill = "surface_variant/0.8", radius = 12, padding = 6 }, kids) +end - local reachable = d.isReachable == true - local paired = d.isPaired == true +-- ── Tools card ────────────────────────────────────────────────────────────── +local function toolsCard(d) + local defs = { + { "t-ring", "bell-ringing", "action.ring", "Ring", "ring" }, + { "t-ping", "message", "action.ping", "Ping", "ping" }, + { "t-browse", "folder", "action.browse", "Browse", "browse" }, + { "t-share", "share", "action.share", "Share", "pick_share" }, + } + if noctalia.getConfig("enable_clipboard_action") then table.insert(defs, 3, { "t-clip", "clipboard", "action.clipboard", "Clipboard", "clipboard" }) end local btns = {} - -- KDE 设备:若按局域网 IP 匹配到了 adb 设备(service 填充 d.adbId), - -- 提供投屏入口;否则只能显示基础操作 - local cast = castTarget(d) - if reachable and paired then - if cast then - local runningMap = noctalia.state.get("pc.running") or {} - local casting = runningMap[cast.adbId] == true - table.insert(btns, vActionBtn(casting and t("action.stop") or t("action.cast"), - casting and "player-stop" or "player-play", - function() - if casting then - sendCmd({ op = "stop_cast", device = cast.adbId }) - else - paramsExpanded = true - render() - end - end, casting and "destructive" or "primary")) - end - table.insert(btns, vActionBtn(t("action.ring"), "bell-ringing", - function() sendCmd({ op = "ring", device = d.id }) end, cast and "outline" or "primary")) - table.insert(btns, vActionBtn(t("action.ping"), "message", - function() sendCmd({ op = "ping", device = d.id }) end)) - table.insert(btns, vActionBtn(t("action.browse"), "folder", - function() sendCmd({ op = "browse", device = d.id }) end)) - if noctalia.getConfig("enable_clipboard_action") then - table.insert(btns, vActionBtn(t("action.clipboard"), "clipboard", - function() sendCmd({ op = "clipboard", device = d.id }) end)) - end - table.insert(btns, vActionBtn(t("action.share"), "share", - function() sendCmd({ op = "pick_share", device = d.id }) end)) - table.insert(btns, vActionBtn(t("action.unpair"), "link-off", - function() sendCmd({ op = "unpair", device = d.id }) end, "ghost")) - elseif not paired then - table.insert(btns, vActionBtn(t("action.pair"), "link", - function() sendCmd({ op = "pair", device = d.id }) end, "primary")) - else - table.insert(btns, vActionBtn(t("action.unpair"), "link-off", - function() sendCmd({ op = "unpair", device = d.id }) end, "ghost")) + for _, def in ipairs(defs) do + table.insert(btns, ui.button({ + key = def[1], glyph = def[2], variant = "ghost", controlSize = "sm", glyphSize = 18, width = 36, height = 36, + tooltip = tr(def[3], def[4]), + onClick = function() if not notifyIfDisconnected(d) then sendCmd({ op = def[5], device = d.id }) end end, + })) end - return ui.column({ key = "right-col", width = RIGHT_COL_WIDTH }, { - ui.scroll({ key = "right-scroll", flexGrow = 1, gap = 8, padding = 8, align = "stretch" }, btns), - }) + return ui.row({ key = "tools-card", gap = 2, paddingH = 5, paddingV = 5, radius = 12, fill = "surface_variant/0.8", align = "center", justify = "space_between" }, btns) end --- ── 左栏:媒体 + 短信(connect 原版) ────────────────────────────────────────── -local function mediaSection(d) - local title = d.mediatitle - if not title or title == "" then - return ui.column({ gap = 6, padding = 10, radius = 8, fill = "surface/0.5" }, { - ui.row({ gap = 6, align = "center" }, { - ui.glyph({ name = "music", size = 13, color = "primary" }), - ui.label({ text = t("panel.now_playing"), fontSize = 10, - color = "primary", fontWeight = "bold", flexGrow = 1 }), - }), - ui.row({ gap = 8, align = "center" }, { - ui.glyph({ name = "music-off", size = 20, color = "on_surface_variant" }), - ui.label({ text = t("panel.no_media"), fontSize = 11, - color = "on_surface_variant" }), - }), - }) +-- ── Dashboard card ────────────────────────────────────────────────────────── +local function dashboardCard(d) + local connected, offline = isDeviceConnected(d), isDeviceOffline(d) + local isKde = d.source ~= "adb" + local devId = isKde and (d.id or "device") or (d.adbId and ("adb:" .. d.adbId) or (d.id or "device")) + local aliasMap = noctalia.state.get("pc.aliasMap") or {} + local name = aliasMap[devId] or d.name or "Device" + local imgMap = noctalia.state.get("pc.imageMap") or {} + local imgPath = isKde and imgMap[d.id] or nil + if imgPath and imgPath ~= "" and not noctalia.fileExists(imgPath) then imgPath = nil end + local glyph = isKde and common.deviceGlyph(d) or (d.transport == "wifi" and "wifi" or "usb") + + local function pickImage() + if connected and isKde then sendCmd({ op = "pick_image", device = d.id }) end end - local artist = d.mediaartist or "" - local album = d.mediaalbum or "" - local playing = d.mediaisPlaying == true - local length = tonumber(d.medialength) or 0 - local position = tonumber(d.mediaposition) or 0 - local canSeek = d.mediacanSeek == true - local artUrl = d.mediaArtPath - - if artUrl and artUrl ~= "" and not noctalia.fileExists(artUrl) then - artUrl = nil + local function commitName(v) + local n = (v or ""):gsub("^%s+", ""):gsub("%s+$", "") + deviceNameEdits[devId] = nil + if connected and isKde then sendCmd({ op = "set_alias", device = d.id, alias = n }) end + render() end - local header = ui.row({ gap = 6, align = "center" }, { - ui.glyph({ name = "music", size = 13, color = "primary" }), - ui.label({ text = t("panel.now_playing"), fontSize = 10, - color = "primary", fontWeight = "bold", flexGrow = 1 }), - }) - - local titleBlock - if artUrl then - titleBlock = ui.row({ gap = 8, align = "center" }, { - ui.image({ path = artUrl, width = 36, height = 36, radius = 4, fit = "cover" }), - ui.column({ gap = 1, flexGrow = 1 }, { - ui.label({ text = title, fontSize = 12, fontWeight = "medium", - color = "on_surface", maxLines = 1 }), - ui.label({ text = artist, fontSize = 10, color = "on_surface_variant", maxLines = 1 }), - ui.label({ text = album, fontSize = 9, color = "on_surface_variant", maxLines = 1 }), - }), + -- Profile picture + local pfp + if connected and imgPath then + pfp = ui.image({ path = imgPath, width = 54, height = 54, radius = 10, fit = "cover", onClick = pickImage }) + elseif connected then + pfp = ui.column({ width = 54, height = 54, radius = 10, fill = "primary/0.15", + align = "center", justify = "center", onClick = pickImage }, + { ui.glyph({ name = glyph, size = 30, color = "primary" }) }) + elseif offline and imgPath then + pfp = ui.image({ path = imgPath, width = 54, height = 54, radius = 10, fit = "cover", opacity = 0.45 }) + else -- offline without image, or fully disconnected + pfp = ui.column({ width = 54, height = 54, radius = 10, fill = "surface/0.8", + border = "outline/0.2", borderWidth = 1, align = "center", justify = "center" }, + { ui.glyph({ name = offline and glyph or "device-mobile-off", + size = offline and 30 or 26, color = "on_surface_variant" }) }) + end + + -- Device name + local nameEl + if connected and deviceNameEdits[devId] then + nameEl = mkInput({ key = "name-edit", value = name, placeholder = name, width = 120, onSubmit = commitName }) + elseif connected then + nameEl = ui.row({ gap = 4, align = "center", flexGrow = 1, minWidth = 0, + onClick = function() deviceNameEdits[devId] = true; render() end }, { + ui.label({ text = name, fontSize = 14, fontWeight = "bold", color = "on_surface", maxLines = 1 }), + ui.glyph({ name = "pencil", size = 11, color = "on_surface_variant" }), }) else - titleBlock = ui.column({ gap = 1 }, { - ui.label({ text = title, fontSize = 12, fontWeight = "medium", - color = "on_surface", maxLines = 1 }), - ui.label({ text = artist, fontSize = 10, color = "on_surface_variant", maxLines = 1 }), - ui.label({ text = album, fontSize = 9, color = "on_surface_variant", maxLines = 1 }), + nameEl = ui.label({ text = offline and name or tr("status.disconnected", "Disconnected"), + fontSize = 14, fontWeight = "bold", flexGrow = 1, maxLines = 1, + color = offline and "on_surface" or "on_surface_variant" }) + end + + -- Battery (connected KDE only) + local battEl = nil + if connected and isKde then + local charge, hasCharge = d.batteryCharge, type(d.batteryCharge) == "number" and d.batteryCharge >= 0 + local charging = d.batteryCharging == true + local cc = hasCharge and charge <= 20 and "error" or "on_surface" + battEl = ui.row({ gap = 3, align = "center" }, { + ui.glyph({ name = common.batteryGlyph(charge, charging), size = 16, color = cc }), + ui.label({ text = hasCharge and (tostring(charge) .. "%") or "--", fontSize = 13, fontWeight = "medium", color = cc }), + charging or nil, }) end - local transport = ui.row({ gap = 4, align = "center" }, { - ui.button({ glyph = "player-skip-back", variant = "ghost", controlSize = "sm", - tooltip = t("media.previous"), - onClick = function() sendCmd({ op = "media", device = d.id, action = "Previous" }) end }), - ui.button({ glyph = playing and "player-pause" or "player-play", - variant = "primary", controlSize = "sm", - tooltip = t(playing and "media.pause" or "media.play"), - onClick = function() sendCmd({ op = "media", device = d.id, action = "PlayPause" }) end }), - ui.button({ glyph = "player-skip-forward", variant = "ghost", controlSize = "sm", - tooltip = t("media.next"), - onClick = function() sendCmd({ op = "media", device = d.id, action = "Next" }) end }), - ui.button({ glyph = "player-stop", variant = "ghost", controlSize = "sm", - tooltip = t("media.stop"), - onClick = function() sendCmd({ op = "media", device = d.id, action = "Stop" }) end }), - }) - - local progress - if canSeek and length > 0 then - local st = mediaDragState[d.id] - local frozen = st and st.dragging and (os.clock() - (st.at or 0)) < 2.0 - if st and st.dragging and not frozen then mediaDragState[d.id] = nil end - local sliderValue = frozen and st.position or position - progress = ui.column({ gap = 2 }, { - ui.slider({ min = 0, max = length, step = 1000, value = sliderValue, - controlSize = "sm", - onChange = function(v) - mediaDragState[d.id] = { dragging = true, position = tonumber(v) or position, at = os.clock() } - end, - onDragEnd = function() - local st2 = mediaDragState[d.id] - local target = (st2 and st2.position) or position - mediaDragState[d.id] = nil - sendCmd({ op = "media_seek", device = d.id, offset = tostring(target) }) - end }), - ui.row({ justify = "space_between" }, { - ui.label({ text = fmtTime(sliderValue), fontSize = 9, color = "on_surface_variant" }), - ui.label({ text = fmtTime(length), fontSize = 9, color = "on_surface_variant" }), - }), + -- Status row + local statusRow = nil + if connected then + local wg, ipText + if isKde then + local s = d.networkStrength + local tiers = { "wifi-0", "wifi-1", "wifi-2", "wifi-3", "wifi" } + wg = (type(s) == "number" and s >= 0) and tiers[math.min(5, s > 4 and math.floor(s/20)+1 or s+1)] or "wifi" + ipText = d.ipv4 or "--" + if d.ipv6 then ipText = ipText .. " | " .. d.ipv6 end + else + wg = d.transport == "usb" and "usb" or "wifi"; ipText = d.adbId or "--" + end + statusRow = ui.row({ gap = 4, align = "center" }, { + ui.glyph({ name = wg, size = 15, color = "primary" }), + ui.label({ text = ipText, fontSize = 12, color = "on_surface_variant", maxLines = 1 }), + }) + elseif offline then + statusRow = ui.row({ gap = 4, align = "center" }, { + ui.glyph({ name = "wifi-off", size = 15, color = "on_surface_variant" }), + ui.label({ text = tr("status.offline", "Offline"), fontSize = 12, color = "on_surface_variant", maxLines = 1 }), }) end - local children = { header, titleBlock, transport } - if progress then table.insert(children, progress) end - return ui.column({ gap = 6, padding = 10, radius = 8, fill = "primary/0.08" }, children) -end + local infoKids = { ui.row({ gap = 4, align = "center", justify = "space_between" }, { nameEl, battEl }) } + if statusRow then table.insert(infoKids, statusRow) end -local function smsComposer(d) - local draft = draftFor(d.id) - return ui.column({ gap = 8, padding = 12, radius = 8, fill = "surface/0.5", - border = "on_surface/0.1", borderWidth = 1 }, { - ui.label({ text = t("panel.sms"), fontSize = 12, fontWeight = "bold", - color = "on_surface" }), - ui.input({ key = "sms-dest-" .. d.id, placeholder = t("panel.sms_dest"), - value = draft.dest, controlSize = "sm", - onChange = function(v) draftFor(d.id).dest = v end }), - ui.input({ key = "sms-msg-" .. d.id, placeholder = t("panel.sms_msg"), - value = draft.msg, controlSize = "sm", - onChange = function(v) draftFor(d.id).msg = v end }), - ui.button({ text = t("panel.sms_send"), glyph = "send", - variant = "primary", controlSize = "sm", - onClick = function() - local df = draftFor(d.id) - if df.dest ~= "" and df.msg ~= "" then - sendCmd({ op = "sms_send", device = d.id, - destination = df.dest, text = df.msg }) - df.msg = "" - render() - end - end }), + return ui.column({ key = "dashboard", gap = 4, paddingV = 6, paddingH = 10, radius = 12, + fill = "surface_variant/0.8" }, { + ui.row({ gap = 6, align = "center" }, { + pfp, ui.column({ gap = 2, flexGrow = 1, minWidth = 0, justify = "center" }, infoKids), + }), }) end --- ── 投屏参数面板(adb 设备,覆盖左栏) ──────────────────────────────────────── -local function paramsPanel(target) - local adbId = target.adbId - -- 用内存缓存,避免每次 render 从磁盘加载导致拖动回退 - local params = paramsFor(adbId) +-- ── Cast & connect card ───────────────────────────────────────────────────── +local function castCard(d) + local target = castTarget(d) + if not target then return nil end + local adbId, params = target.adbId, paramsFor(target.adbId) + local casting = (noctalia.state.get("pc.running") or {})[adbId] == true - local function commit(saveCustom) + local function commit(saveCust) persistence.saveParams(adbId, params) - -- custom 档只在用户手动调整时更新(滑块/开关),预设应用不覆盖它, - -- 否则点预设后自定义档会被预设值污染 - if saveCustom then - persistence.saveCustom(adbId, params) - end + if saveCust then persistence.saveCustom(adbId, params) end sendCmd({ op = "restart_params", device = adbId, params = params }) end - - local function applyPreset(_key, p) - for k, v in pairs(p) do params[k] = v end - commit(false) - render() - end - local function startCast() - noctalia.log("[phone-operate] startCast: adbId=" .. tostring(adbId) - .. " online=" .. tostring(target.online) - .. " ip=" .. tostring(target.ip) - .. " transport=" .. tostring(target.transport)) - -- 设备已在线(USB 或 wifi 已连接):直接投屏 - if target.online then - sendCmd({ op = "cast", device = adbId, params = params }) - return - end - -- wifi 首次连接:需配对端口 + 配对码 + 调试端口 + if target.online then sendCmd({ op = "cast", device = adbId, params = params }); return end if target.ip then - if castPort == "" or castCode == "" then - noctalia.notifyError(t("error.pair_failed"), t("panel.pair_missing")) - return + local dbg = castDebugPort ~= "" and castDebugPort + or (connectAddr ~= "" and (connectAddr:match(":(%d+)$") or connectAddr)) or "5555" + if castPort ~= "" and castCode ~= "" then + local port = castPort:match(":(%d+)$") or castPort + local ip = castPort:match("^(%d+%.%d+%.%d+%.%d+)") or target.ip + sendCmd({ op = "pair_and_cast", address = ip, port = port, + debugPort = dbg, code = castCode, params = params }) + else + sendCmd({ op = "pair_and_cast", address = target.ip, port = "", + debugPort = dbg, code = "", params = params }) end - sendCmd({ op = "pair_and_cast", address = target.ip, port = castPort, - debugPort = castDebugPort, code = castCode, params = params }) return end - -- 离线且无 IP(如 USB 设备未被 adb 识别):明确提示,而不是静默失败 - noctalia.notifyError(t("error.cast_failed"), t("panel.cast_offline_hint")) + noctalia.notifyError(tr("error.cast_failed", "Cast failed"), + tr("panel.cast_offline_hint", "Device is not reachable by adb. Check the USB cable / wireless debugging, then retry.")) end + local cur = detectPreset(params) local children = {} - -- 按钮高亮由参数值推导(detectPreset),与状态变量无关, - -- 引擎的 setValue 回声不会影响高亮正确性 - local currentPreset = detectPreset(params) - - table.insert(children, ui.row({ gap = 4 }, { - ui.button({ text = t("panel.preset_hd"), variant = "ghost", controlSize = "sm", - selected = currentPreset == "hd", - onClick = function() applyPreset("hd", PRESETS.hd) end, flexGrow = 1 }), - ui.button({ text = t("panel.preset_perf"), variant = "ghost", controlSize = "sm", - selected = currentPreset == "perf", - onClick = function() applyPreset("perf", PRESETS.perf) end, flexGrow = 1 }), - ui.button({ text = t("panel.preset_save"), variant = "ghost", controlSize = "sm", - selected = currentPreset == "save", - onClick = function() applyPreset("save", PRESETS.save) end, flexGrow = 1 }), - ui.button({ text = t("panel.preset_custom"), variant = "ghost", controlSize = "sm", - selected = currentPreset == "custom", + -- Preset buttons + local function presetBtn(key, label, p) + return ui.button({ key = "pre-" .. key, text = label, + variant = cur == key and "secondary" or "ghost", controlSize = "sm", onClick = function() - local c = persistence.loadCustom(adbId) - if c then - for k, v in pairs(c) do params[k] = v end - commit(false) + if key == "custom" then + local c = persistence.loadCustom(adbId) + if c then for k, v in pairs(c) do params[k] = v end; commit(false) end + else + for k, v in pairs(p) do params[k] = v end; commit(false) end render() - end, flexGrow = 1 }), + end }) + end + + local modeLabel = isConnectMode and tr("action.connect", "Connect") or tr("action.pair", "Pair") + table.insert(children, ui.row({ align = "center", justify = "space_between", paddingV = 1 }, { + ui.row({ gap = 6, align = "center" }, { + ui.toggle({ key = "pair-mode-toggle", checked = isConnectMode, tooltip = modeLabel, + onChange = function(v) isConnectMode = (v == true or v == "true"); render() end }), + ui.label({ text = modeLabel, fontSize = 12, fontWeight = "medium", color = "on_surface" }), + }), + ui.row({ gap = 2, padding = 2, radius = 8, fill = "surface/0.8", align = "center" }, { + presetBtn("hd", tr("panel.preset_hd", "HD"), PRESETS.hd), + presetBtn("perf", tr("panel.preset_perf", "Bal"), PRESETS.perf), + presetBtn("save", tr("panel.preset_save", "Save"), PRESETS.save), + presetBtn("custom", tr("panel.preset_custom", "Cust"), nil), + }), })) - local function paramSlider(labelKey, val, min, max, step, suffix, setter) - table.insert(children, ui.row({ key = "row-" .. labelKey, gap = 8, align = "center" }, { - -- 参数名 minWidth:中文/英文都能完整显示,不截断;slider 是 - -- 唯一 flexGrow,吃掉剩余宽度(label 不用 flexGrow,避免平分)。 - ui.label({ text = t(labelKey), minWidth = 72, - fontSize = 11, color = "on_surface_variant" }), - ui.slider({ - key = "slider-" .. labelKey, - min = min, max = max, step = step, value = val, - controlSize = "sm", - onChange = function(v) - setter(tonumber(v)) - render() - end, - onDragEnd = function() - commit(true) - render() - end, - flexGrow = 1, - }), - ui.label({ text = tostring(val) .. suffix, width = 52, fontSize = 11, - textAlign = "end", color = "on_surface" }), + -- Connection / pairing controls + if target.online then + table.insert(children, ui.row({ gap = 6, align = "center", padding = 5, radius = 8, fill = "surface/0.8" }, { + ui.glyph({ name = target.transport == "usb" and "usb" or "wifi", size = 14, color = "primary" }), + ui.label({ text = string.format("%s (%s)", target.ip or adbId, tr("status.connected", "Connected")), + fontSize = 11, color = "on_surface", flexGrow = 1 }), + ui.button({ glyph = "plug-off", tooltip = tr("action.disconnect", "Disconnect"), variant = "ghost", + controlSize = "sm", glyphSize = 15, width = 36, height = 32, + onClick = function() sendCmd({ op = "adb_disconnect", device = adbId }) end }), })) - end - - paramSlider("panel.max_size", params.max_size or 1920, 256, 3840, 64, "", - function(v) params.max_size = v end) - paramSlider("panel.bit_rate", params.bit_rate or 8, 1, 30, 1, "M", - function(v) params.bit_rate = v end) - paramSlider("panel.max_fps", params.max_fps or 60, 1, 240, 1, "", - function(v) params.max_fps = v end) - - local function toggleBlock(labelKey, descKey, checked, setter) - table.insert(children, ui.column({ gap = 2 }, { - ui.row({ gap = 8, align = "center" }, { - ui.label({ text = t(labelKey), fontSize = 12, color = "on_surface", flexGrow = 1 }), - ui.toggle({ - checked = checked, - onChange = function(v) - setter(v == "true") - commit(true) - render() - end, - }), - }), - ui.label({ text = t(descKey), fontSize = 10, color = "on_surface_variant" }), + elseif isConnectMode then + local ph = (target.ip and (target.ip .. ":debugport")) or "ip:debugport" + local function doConnect() + local trimmed = (connectAddr or ""):gsub("^%s+", ""):gsub("%s+$", "") + local full = trimmed:find(":") and trimmed or nil + if not full then + local ip = target.ip or common.ipFromSerial(adbId) + if ip then full = ip .. ":" .. (trimmed ~= "" and trimmed or "5555") end + end + if full then sendCmd({ op = "adb_connect", address = full }) + else noctalia.notifyError(tr("error.conn_failed", "Wireless connection failed"), + tr("error.conn_hint", "Could not connect to the debug port.")) end + end + table.insert(children, ui.row({ gap = 4, align = "center" }, { + mkInput({ key = "connect-addr-input", placeholder = ph, value = connectAddr, + fontSize = 12, flexGrow = 1, tooltip = tr("action.connect", "Connect") .. " (ip:debugport)", + onChange = function(v) connectAddr = v end, onSubmit = doConnect }), + ui.button({ key = "conn-btn", glyph = "plug", tooltip = tr("action.connect", "Connect"), + variant = "primary", controlSize = "sm", glyphSize = 16, width = 36, height = 32, + onClick = doConnect }), + })) + else + local function doPair() + local full = castPort:find(":") and castPort or ((target.ip or "") .. ":" .. castPort) + if full ~= "" and castCode ~= "" then + sendCmd({ op = "adb_pair", address = full, code = castCode }) + isConnectMode = true + if castDebugPort ~= "" then + local ip = castPort:match("^(%d+%.%d+%.%d+%.%d+)") or target.ip or common.ipFromSerial(adbId) + if ip then + sendCmd({ op = "adb_connect", + address = castDebugPort:find(":") and castDebugPort or (ip .. ":" .. castDebugPort) }) + end + end + render() + else + noctalia.notifyError(tr("error.pair_failed", "Pairing failed"), + tr("panel.pair_missing", "Enter both the pairing port and code first.")) + end + end + table.insert(children, ui.row({ gap = 4, align = "center" }, { + mkInput({ key = "pair-port-input", placeholder = tr("panel.pair_port_placeholder", "Pair port"), + value = castPort, fontSize = 12, flexGrow = 1, + tooltip = tr("panel.pair_port_placeholder", "Pair port") .. " (5 digits)", + onChange = function(v) castPort = v end, onSubmit = doPair }), + mkInput({ key = "pair-debug-input", placeholder = tr("panel.debug_port_placeholder", "Debug port"), + value = castDebugPort, fontSize = 12, width = 120, + tooltip = tr("panel.debug_port_placeholder", "Debug port") .. " (5 digits)", + onChange = function(v) castDebugPort = v end, onSubmit = doPair }), + mkInput({ key = "pair-code-input", placeholder = "PIN", value = castCode, + fontSize = 12, width = 80, + tooltip = tr("panel.pair_code_placeholder", "Pairing code (6 digits)"), + onChange = function(v) castCode = v end, onSubmit = doPair }), + ui.button({ key = "pair-btn", glyph = "link", tooltip = tr("action.pair", "Pair"), + variant = "primary", controlSize = "sm", glyphSize = 16, width = 36, height = 32, + onClick = doPair }), })) end - toggleBlock("panel.turn_screen_off", "panel.turn_screen_off_desc", - params.turn_screen_off or false, function(v) params.turn_screen_off = v end) - toggleBlock("panel.record", "panel.record_desc", - params.record or false, function(v) params.record = v end) - - -- 首次无线连接:配对端口 + 配对码(仅当设备未在线且知道 IP 时显示) - local pairInput - if not target.online and target.ip then - pairInput = ui.column({ key = "cast-pair", gap = 6, padding = 10, radius = 8, - fill = "primary/0.08", border = "primary/0.25", borderWidth = 1 }, { - ui.label({ text = t("panel.pair_first_title"), fontSize = 11, fontWeight = "bold", - color = "primary" }), - ui.label({ text = t("panel.pair_first_hint"), fontSize = 10, color = "on_surface_variant" }), - ui.input({ key = "cast-port", placeholder = t("panel.pair_port_placeholder"), - value = castPort, controlSize = "sm", - onChange = function(v) castPort = v end }), - ui.row({ key = "cast-pair-debug", gap = 6 }, { - ui.input({ key = "cast-debug", placeholder = t("panel.debug_port_placeholder"), - value = castDebugPort, controlSize = "sm", flexGrow = 1, - onChange = function(v) castDebugPort = v end }), - ui.input({ key = "cast-code", placeholder = t("panel.pair_code_placeholder"), - value = castCode, controlSize = "sm", width = 120, - onChange = function(v) castCode = v end }), - }), - }) + -- Slider rows: RES / BIT / FPS + local rows = {} + for _, s in ipairs({ + { tr("panel.max_size","RES"), "s-res", "max_size", 256, 3840, 64, 1920, "p" }, + { tr("panel.bit_rate","BIT"), "s-br", "bit_rate", 1, 30, 1, 8, "M" }, + { tr("panel.max_fps","FPS"), "s-fps", "max_fps", 1, 240, 1, 60, "fps" }, + }) do + local val = params[s[3]] or s[7] + table.insert(rows, ui.row({ key = "row-" .. s[3], gap = 6, align = "center" }, { + ui.label({ text = s[1], fontSize = 12, fontWeight = "bold", color = "on_surface_variant", width = 32 }), + ui.slider({ key = s[2], min = s[4], max = s[5], step = s[6], value = val, controlSize = "sm", flexGrow = 1, + onChange = function(v) params[s[3]] = tonumber(v); render() end, onDragEnd = function() commit(true); render() end }), + ui.label({ text = tostring(val) .. s[8], fontSize = 11, textAlign = "end", color = "on_surface", width = 44 }), + })) end - -- 开始投屏:在线直接投;离线 wifi 需先配对 - local startBtn = ui.button({ key = "cast-start", text = t("panel.start_cast"), glyph = "player-play", - variant = "primary", controlSize = "md", - onClick = startCast }) + table.insert(children, ui.row({ gap = 8, align = "center" }, { + ui.column({ gap = 6, flexGrow = 1, minWidth = 0 }, rows), + ui.column({ gap = 6, width = 105 }, { + ui.button({ key = "rec-tog", glyph = "circle", text = tr("panel.record", "Record"), + variant = params.record and "secondary" or "ghost", controlSize = "sm", width = 105, selected = params.record == true, + tooltip = tr("panel.record_desc", "Record the mirror to a file"), + onClick = function() params.record = not params.record; commit(true); render() end }), + ui.button({ key = "scr-off", glyph = "device-mobile-off", text = tr("panel.turn_screen_off", "Screen Off"), + variant = params.turn_screen_off and "secondary" or "ghost", controlSize = "sm", width = 105, selected = params.turn_screen_off == true, + tooltip = tr("panel.turn_screen_off_desc", "Phone screen off while mirroring"), + onClick = function() params.turn_screen_off = not params.turn_screen_off; commit(true); render() end }), + ui.button({ key = "cast-btn", text = casting and tr("action.stop", "Stop") or tr("action.cast", "Cast"), + glyph = casting and "player-stop" or "player-play", variant = casting and "destructive" or "primary", controlSize = "sm", width = 105, + tooltip = casting and tr("action.stop", "Stop") or tr("action.cast", "Cast"), + onClick = function() if casting then sendCmd({ op = "stop_cast", device = adbId }) else startCast() end end }), + }), + })) - local scrollItems = { - startBtn, - } - if pairInput then - table.insert(scrollItems, pairInput) - end - for _, c in ipairs(children) do - table.insert(scrollItems, c) - end - -- 底部小字提示(替代原「投屏参数」标题卡片,节省空间),居中显示 - table.insert(scrollItems, ui.label({ key = "params-hint-foot", text = t("panel.params_hint"), - fontSize = 12, color = "on_surface_variant", textAlign = "center" })) - return ui.column({ key = "left-panel", width = 340 }, { - ui.scroll({ key = "left-panel-scroll", flexGrow = 1, gap = 10, padding = 0 }, scrollItems), - }) + return ui.column({ key = "cast-card", gap = 6, padding = 8, radius = 12, + fill = "surface_variant/0.8" }, children) end --- ── 左栏 ───────────────────────────────────────────────────────────────────── -local function leftColumn(d) - -- 投屏参数面板:adb 设备,或 KDE 设备匹配到 adb 目标时(paramsExpanded 时展开) - local target = castTarget(d) - if target and paramsExpanded then - return paramsPanel(target) - end - if d.source == "adb" then - return ui.column({ key = "left-hint", flexGrow = 1, minWidth = 340 }, { - ui.scroll({ key = "left-hint-scroll", flexGrow = 1, gap = 12, padding = 0 }, { - ui.column({ gap = 6, padding = 10, radius = 8, fill = "surface/0.5" }, { - ui.row({ gap = 6, align = "center" }, { - ui.glyph({ name = "device-mobile", size = 13, color = "primary" }), - ui.label({ text = t("panel.params"), fontSize = 10, - color = "primary", fontWeight = "bold", flexGrow = 1 }), +-- ── Messages card ─────────────────────────────────────────────────────────── +local function messagesCard(d) + local draft = draftFor(d.id) + local query = (draft.dest or ""):lower():gsub("^%s+", ""):gsub("%s+$", "") + local isFav = false + for _, f in ipairs(smsFavorites) do + if f.number == draft.dest or (f.name ~= "" and f.name:lower() == query) then isFav = true; break end + end + + local favItems = {} + for _, fav in ipairs(smsFavorites) do + local nMatch = fav.name ~= "" and fav.name:lower():find(query, 1, true) ~= nil + local numMatch = fav.number:lower():find(query, 1, true) ~= nil + if query == "" or nMatch or numMatch then + local num = fav.number + local sel = function() draftFor(d.id).dest = num; smsDestRev = smsDestRev + 1; render() end + if favNameEdits[num] then + local curName = fav.name + local function commit(v) + local val = (type(v) == "string" and v ~= "") and v or curName + fav.name = (val or ""):gsub("^%s+", ""):gsub("%s+$", "") + favNameEdits[num] = nil; persistence.saveFavorites(smsFavorites); render() + end + table.insert(favItems, ui.row({ key = "fav-edit-" .. num, gap = 4, paddingH = 6, paddingV = 2, radius = 6, fill = "surface", align = "center" }, { + mkInput({ key = "fav-name-in-" .. num, value = curName, placeholder = tr("panel.contact_name", "Contact name"), flexGrow = 1, focus = true, onChange = function(v) curName = v end, onSubmit = commit }), + ui.button({ glyph = "check", variant = "ghost", controlSize = "sm", glyphSize = 12, onClick = commit }), + ui.button({ glyph = "x", variant = "ghost", controlSize = "sm", glyphSize = 10, onClick = function() favNameEdits[num] = nil; render() end }), + })) + else + table.insert(favItems, ui.row({ key = "fav-" .. num, gap = 6, paddingH = 6, paddingV = 3, radius = 6, fill = "surface", align = "center", onClick = sel }, { + ui.glyph({ name = "star-filled", size = 11, color = "primary" }), + ui.column({ gap = 0, flexGrow = 1, minWidth = 0, onClick = sel }, { + fav.name ~= "" and ui.label({ text = fav.name, fontSize = 11, fontWeight = "bold", color = "on_surface", maxLines = 1 }) or nil, + ui.label({ text = num, fontSize = fav.name ~= "" and 10 or 11, color = fav.name ~= "" and "on_surface_variant" or "on_surface", maxLines = 1 }), }), - ui.label({ text = t("panel.adb_hint"), fontSize = 11, color = "on_surface_variant" }), - }), - }), - }) + ui.button({ key = "fav-ren-" .. num, glyph = "pencil", variant = "ghost", controlSize = "sm", glyphSize = 10, tooltip = tr("panel.edit_name", "Edit contact name"), onClick = function() favNameEdits[num] = true; render() end }), + ui.button({ key = "fav-rm-" .. num, glyph = "x", variant = "ghost", controlSize = "sm", glyphSize = 10, onClick = function() + for i, f in ipairs(smsFavorites) do if f.number == num then table.remove(smsFavorites, i); break end end + persistence.saveFavorites(smsFavorites); render() + end }), + })) + end + end end - local items = {} - table.insert(items, mediaSection(d)) - if d.isReachable and d.isPaired then - table.insert(items, smsComposer(d)) + + local function doSend() + if notifyIfDisconnected(d) then return end + local df = draftFor(d.id) + if df.dest ~= "" and df.msg ~= "" then + local destNum = df.dest + for _, f in ipairs(smsFavorites) do + if f.name ~= "" and f.name:lower() == df.dest:lower() then destNum = f.number; break end + end + sendCmd({ op = "sms_send", device = d.id, destination = destNum, text = df.msg }) + df.msg = ""; render() + end end - return ui.column({ key = "left-media", flexGrow = 1, minWidth = 340 }, { - ui.scroll({ key = "left-media-scroll", flexGrow = 1, gap = 12, padding = 0 }, items), + + return ui.column({ key = "msgs", gap = 4, padding = 8, radius = 12, fill = "surface_variant/0.8", flexGrow = 1 }, { + ui.row({ gap = 4, align = "center" }, { + mkInput({ key = "sms-dest-" .. d.id .. "-" .. tostring(smsDestRev), placeholder = tr("panel.phone_placeholder", "1234567890"), + tooltip = tr("panel.sms_dest", "Phone number"), value = draft.dest, flexGrow = 1, onChange = function(v) draftFor(d.id).dest = v; render() end, + onSubmit = function(v) + local q = (v or draft.dest or ""):lower():gsub("^%s+", ""):gsub("%s+$", "") + for _, f in ipairs(smsFavorites) do + if q ~= "" and f.name ~= "" and (f.name:lower() == q or f.name:lower():find(q, 1, true)) then + draftFor(d.id).dest = f.number; smsDestRev = smsDestRev + 1; render(); return + end + end + end }), + draft.dest ~= "" and ui.button({ key = "sms-clear", glyph = "x", variant = "ghost", controlSize = "sm", glyphSize = 12, + tooltip = tr("panel.clear", "Clear"), onClick = function() draftFor(d.id).dest = ""; smsDestRev = smsDestRev + 1; render() end }) or nil, + ui.button({ key = "fav-btn", glyph = isFav and "star-filled" or "star", variant = isFav and "secondary" or "ghost", controlSize = "sm", glyphSize = 14, + tooltip = tr("panel.fav_add_tooltip", "Favorite this number"), onClick = function() + local dest = draft.dest:gsub("^%s+", ""):gsub("%s+$", "") + if dest == "" then return end + for i, f in ipairs(smsFavorites) do + if f.number == dest or (f.name ~= "" and f.name:lower() == dest:lower()) then + table.remove(smsFavorites, i); persistence.saveFavorites(smsFavorites); render(); return + end + end + table.insert(smsFavorites, { number = dest, name = "" }) + favNameEdits[dest] = true; persistence.saveFavorites(smsFavorites); render() + end }), + }), + ui.scroll({ key = "fav-scroll", flexGrow = 1, gap = 2 }, #favItems > 0 and favItems or { + ui.row({ align = "center", justify = "center", paddingV = 16, flexGrow = 1 }, { + ui.label({ text = query ~= "" and tr("panel.no_matches", "No matching contacts") or tr("panel.fav_empty", "No favorite numbers yet"), + fontSize = 11, color = "on_surface_variant", textAlign = "center" }), + }), + }), + ui.row({ gap = 4, align = "center" }, { + mkInput({ key = "sms-msg-" .. d.id, placeholder = tr("panel.sms_msg", "Message"), tooltip = tr("panel.sms_msg", "Message"), + value = draft.msg, flexGrow = 1, onChange = function(v) draftFor(d.id).msg = v end, onSubmit = doSend }), + ui.button({ key = "sms-send", glyph = "send", variant = "primary", controlSize = "sm", tooltip = tr("panel.sms_send", "Send"), onClick = doSend }), + }), }) end --- ── 页脚:设备地址 ──────────────────────────────────────────────────────────── -local function infoFooter(d) - local function cell(label, val) - return ui.column({ gap = 2, padding = 6, radius = 6, fill = "surface/0.5", - flexGrow = 1 }, { - ui.label({ text = label, fontSize = 9, color = "on_surface_variant" }), - ui.label({ text = val or "--", fontSize = 10, maxLines = 1, - color = val and "on_surface" or "on_surface_variant" }), - }) - end - if d.source == "adb" then - return ui.row({ gap = 8 }, { - cell("ADB ID", d.adbId), - cell("USB/WiFi", d.transport or "usb"), +-- ── Media playback bar ────────────────────────────────────────────────────── +local function mediaBar(d) + local connected = isDeviceConnected(d) + local title = connected and d.mediatitle or nil + local artist = connected and (d.mediaartist or "") or "" + local playing = connected and (d.mediaisPlaying == true) or false + local length = connected and (tonumber(d.medialength) or 0) or 0 + local position = connected and (tonumber(d.mediaposition) or 0) or 0 + local canSeek = connected and (d.mediacanSeek == true) or false + local artUrl = connected and d.mediaArtPath or nil + if artUrl and artUrl ~= "" and not noctalia.fileExists(artUrl) then artUrl = nil end + + if not connected or not title or title == "" then + return ui.row({ key = "media-bar", gap = 6, paddingV = 6, paddingH = 6, radius = 12, + fill = "surface_variant/0.8", align = "center" }, { + ui.glyph({ name = "music-off", size = 18, color = "on_surface_variant" }), + ui.label({ text = tr("panel.no_media", "No media playing"), fontSize = 12, + color = "on_surface_variant", flexGrow = 1 }), }) end - return ui.row({ gap = 8 }, { - cell("IPv4", d.ipv4), - cell("IPv6", d.ipv6), + + -- Transport buttons + local function mediaBtn(action) sendCmd({ op = "media", device = d.id, action = action }); sendCmd({ op = "refresh" }) end + local transport = ui.row({ gap = 2, align = "center" }, { + ui.button({ glyph = "player-skip-back", variant = "ghost", controlSize = "sm", tooltip = tr("media.previous", "Previous"), onClick = function() mediaBtn("Previous") end }), + ui.button({ glyph = playing and "player-pause" or "player-play", variant = "primary", controlSize = "sm", + tooltip = tr(playing and "media.pause" or "media.play", playing and "Pause" or "Play"), + onClick = function() d.mediaisPlaying = not playing; noctalia.setUpdateInterval(d.mediaisPlaying and 500 or 3000); render(); mediaBtn("PlayPause") end }), + ui.button({ glyph = "player-skip-forward", variant = "ghost", controlSize = "sm", tooltip = tr("media.next", "Next"), onClick = function() mediaBtn("Next") end }), }) -end --- ── adb 无线配对(折叠) ────────────────────────────────────────────────────── -local function pairSection() - if not pairExpanded then - return nil + -- Seek bar + local seekEl = nil + if canSeek and length > 0 then + local sv = frozenDragValue(mediaDragState, d.id, position) + seekEl = ui.row({ gap = 4, align = "center", flexGrow = 1, minWidth = 0 }, { + ui.label({ text = fmtTime(sv), fontSize = 9, color = "on_surface_variant", width = 30, textAlign = "end" }), + ui.slider({ key = "seek", min = 0, max = length, step = 1000, + value = sv, controlSize = "sm", flexGrow = 1, + onChange = function(v) + mediaDragState[d.id] = { dragging = true, position = tonumber(v) or position, at = os.clock() } + end, + onDragEnd = function() + local s = mediaDragState[d.id]; local tgt = (s and s.position) or position + mediaDragState[d.id] = nil + sendCmd({ op = "media_seek", device = d.id, offset = tostring(tgt) }) + end }), + ui.label({ text = fmtTime(length), fontSize = 9, color = "on_surface_variant", width = 30 }), + }) end - return ui.column({ key = "pair-expanded", gap = 8, padding = 10, radius = 8, fill = "surface/0.5", - border = "on_surface/0.1", borderWidth = 1 }, { - ui.row({ gap = 8 }, { - ui.input({ key = "pair-addr", placeholder = t("panel.pair_addr_placeholder"), - controlSize = "sm", - onChange = function(v) pairAddr = v end, flexGrow = 1 }), - ui.input({ key = "pair-code", placeholder = t("panel.pair_code_placeholder"), - controlSize = "sm", width = 140, - onChange = function(v) pairCode = v end }), - }), - ui.markdown({ text = t("panel.pair_hint") }), - ui.row({ gap = 8 }, { - ui.button({ text = t("panel.pair_btn"), glyph = "link", - variant = "secondary", controlSize = "sm", - onClick = function() - if pairAddr ~= "" and pairCode ~= "" then - sendCmd({ op = "adb_pair", address = pairAddr, code = pairCode }) - pairAddr, pairCode = "", "" - pairExpanded = false - render() - end - end, flexGrow = 1 }), - ui.button({ text = t("panel.cancel"), variant = "ghost", controlSize = "sm", - onClick = function() - pairExpanded = false - render() - end, flexGrow = 1 }), + + local dispTitle = truncate(title, 40) + local dispArtist = artist ~= "" and truncate(artist, 20) or "" + + local kids = {} + if artUrl then table.insert(kids, ui.image({ path = artUrl, width = 60, height = 60, radius = 8, fit = "cover" })) end + table.insert(kids, ui.column({ gap = 5, flexGrow = 1, minWidth = 0 }, { + ui.row({ gap = 6, align = "center", minWidth = 0 }, { + ui.label({ text = dispTitle, fontSize = 14, fontWeight = "bold", color = "on_surface", maxLines = 1 }), + dispArtist ~= "" and ui.label({ text = " • " .. dispArtist, fontSize = 12, color = "on_surface_variant", maxLines = 1 }) or nil, }), - }) + ui.row({ gap = 8, align = "center" }, { transport, seekEl }), + })) + return ui.row({ key = "media-bar", gap = 15, paddingV = 8, paddingH = 8, radius = 12, + fill = "surface_variant/0.8", align = "center" }, kids) end --- ── 主渲染 ─────────────────────────────────────────────────────────────────── +-- ── Main render ───────────────────────────────────────────────────────────── function render() - local backend = noctalia.state.get("pc.backend") or { available = false } local devices = noctalia.state.get("pc.devices") or {} local order = noctalia.state.get("pc.order") or {} - -- 过滤:被 KDE 设备覆盖的 adb 设备不显示独立卡,统一由 KDE 设备卡管理 local visibleOrder = {} for _, id in ipairs(order) do local d = devices[id] - if d and not common.adbCoveredByKde(d, devices) then - table.insert(visibleOrder, id) - end + if d and not common.adbCoveredByKde(d, devices) then table.insert(visibleOrder, id) end end local sel = noctalia.state.get("pc.selected") - if not sel or not devices[sel] or common.adbCoveredByKde(devices[sel], devices) then - sel = visibleOrder[1] - end + if not sel or not devices[sel] or common.adbCoveredByKde(devices[sel], devices) then sel = visibleOrder[1] end - -- 中间内容区(设备卡 + 两栏 + 页脚):包在 scroll 里,内容超高时可滚动, - -- 不会把底部的配对区挤出面板(修复投屏参数面板展开时配对区出界/不可见)。 - local middle - if not backend.available and #visibleOrder == 0 then - middle = ui.column({ gap = 8, padding = 40, align = "center", flexGrow = 1 }, { - ui.glyph({ name = "phone-off", size = 40, color = "on_surface_variant" }), - ui.label({ text = t("status.no_backend"), color = "on_surface_variant" }), - }) - elseif not sel or not devices[sel] then - middle = ui.column({ gap = 8, padding = 40, align = "center", flexGrow = 1 }, { - ui.glyph({ name = "phone-off", size = 40, color = "on_surface_variant" }), - ui.label({ text = t("panel.empty"), color = "on_surface_variant" }), - }) - else - local d = devices[sel] - middle = ui.scroll({ key = "body-scroll", flexGrow = 1, gap = 10 }, { - deviceCard(d), - -- 两栏最小高度:媒体/参数区内容少时也有足够高度,但不触发 - -- 滚动条(内容总高 = 设备卡 + 两栏需 ≤ viewport,否则右侧 - -- 出现无意义的滚动条)。viewport 约 476,扣设备卡约 78 得 370 - -- (留 28px 缓冲覆盖字体/缩放差异)。 - ui.row({ key = "main-row", gap = 14, minHeight = 370, - align = "stretch", justify = "center" }, { - leftColumn(d), - rightColumn(d), - }), - }) - end + local d = (sel and devices[sel]) or { id = "default", name = "Device", source = "kde", isPaired = false, isReachable = false } - local rootChildren = { - headerRow(visibleOrder, devices, sel), - middle, - } - -- 配对表单(展开时)在 IP 地址上方 - local pair = pairSection() - if pair then table.insert(rootChildren, pair) end - -- IP 地址固定在底部(scroll 之外),与底部只留一半间距 - if sel and devices[sel] then - table.insert(rootChildren, infoFooter(devices[sel])) + local upperKids = { dashboardCard(d) } + local cast = castCard(d) + if cast then table.insert(upperKids, cast) end + table.insert(upperKids, messagesCard(d)) + + panel.render(ui.column({ gap = 6, padding = 7, flexGrow = 1, align = "stretch" }, { + ui.row({ gap = 6, flexGrow = 1, align = "stretch" }, { + ui.column({ width = 220, gap = 6, align = "stretch" }, { deviceSidebar(visibleOrder, devices, sel), toolsCard(d) }), + ui.column({ flexGrow = 1, minWidth = 0, gap = 6 }, upperKids), + }), + mediaBar(d), + })) +end + +-- ── Lifecycle ─────────────────────────────────────────────────────────────── +local lastMediaSync = 0 +function update() + local sel = noctalia.state.get("pc.selected") + local d = sel and (noctalia.state.get("pc.devices") or {})[sel] + if d and isDeviceConnected(d) and d.mediaisPlaying == true then + noctalia.setUpdateInterval(500) + local len, pos = tonumber(d.medialength) or 0, tonumber(d.mediaposition) or 0 + local st = mediaDragState[d.id] + if not (st and st.dragging) and len > 0 then d.mediaposition = math.min(len, pos + 500); render() end + local now = os.clock() + if now - lastMediaSync >= 1.5 then lastMediaSync = now; sendCmd({ op = "refresh" }) end + else + noctalia.setUpdateInterval(3000) end +end - panel.render(ui.column({ gap = 5, padding = 12, flexGrow = 1 }, rootChildren)) +function onOpen() + local sel = noctalia.state.get("pc.selected") + local d = sel and (noctalia.state.get("pc.devices") or {})[sel] + noctalia.setUpdateInterval((d and d.mediaisPlaying == true) and 500 or 3000) + render() end -function onOpen(_context) render() end -function onClose() end +function onClose() noctalia.setUpdateInterval(3000) end noctalia.state.watch("pc.devices", render) noctalia.state.watch("pc.order", render) diff --git a/phone-operate/plugin.toml b/phone-operate/plugin.toml index 81f62feed..945d531ce 100644 --- a/phone-operate/plugin.toml +++ b/phone-operate/plugin.toml @@ -163,8 +163,8 @@ entry = "tile.luau" [[panel]] id = "main" entry = "panel.luau" -width = 570 -height = 600 +width = 700 +height = 620 placement = "attached" position = "auto" open_near_click = true @@ -173,8 +173,8 @@ keyboard_focus = "on_demand" [[panel]] id = "main_floating" entry = "panel.luau" -width = 570 -height = 600 +width = 700 +height = 620 placement = "floating" position = "center" keyboard_focus = "on_demand" @@ -182,8 +182,8 @@ keyboard_focus = "on_demand" [[panel]] id = "main_widget" entry = "panel.luau" -width = 570 -height = 600 +width = 700 +height = 620 placement = "floating" position = "auto" open_near_click = true diff --git a/phone-operate/service.luau b/phone-operate/service.luau index d60ebc033..cf1affab7 100644 --- a/phone-operate/service.luau +++ b/phone-operate/service.luau @@ -332,7 +332,6 @@ local function fetchMpris(id, cb) d2.mediatitle = p.title d2.mediaartist = p.artist d2.mediaalbum = p.album - d2.mediavolume = p.volume d2.medialocalAlbumArtUrl = p.localAlbumArtUrl d2.medialength = p.length d2.mediaposition = p.position @@ -819,16 +818,6 @@ local function handleCommand(cmd) function() noctalia.runAsync("sleep 0.3", function() refreshDevices() end) end) - elseif op == "media_set_volume" then - local vol = tonumber(cmd.volume) or 0 - local path = DAEMON_PATH .. "/devices/" .. dev .. "/mprisremote" - noctalia.runAsync( - "gdbus call --session --dest " .. SVC - .. " --object-path " .. shellQuote(path) - .. " --method " .. shellQuote(PROPS_IFACE .. ".Set") - .. " " .. shellQuote(MPRIS_IFACE) .. " volume " - .. shellQuote(""), - function() refreshDevices() end) -- ── scrcpy 操作(source="adb" 的设备) ── elseif op == "cast" then local adbId = cmd.device diff --git a/phone-operate/thumbnail.webp b/phone-operate/thumbnail.webp index 46e39eee573a98891cd58c7b003d26f90179460a..034ca9a9b6c8a4d817de51b749541449e840a127 100644 GIT binary patch literal 69772 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 z�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 ZfH=b)}e|a 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 l((SV|AwT!)ocXH5nq^c&=#`3&2CmhmR|dz6?H diff --git a/phone-operate/translations/en.json b/phone-operate/translations/en.json index 2477d6cd5..a66f041b3 100644 --- a/phone-operate/translations/en.json +++ b/phone-operate/translations/en.json @@ -3,6 +3,7 @@ "browse": "Browse", "cast": "Cast", "clipboard": "Clipboard", + "connect": "Connect", "disconnect": "Disconnect", "pair": "Pair", "ping": "Ping", @@ -10,79 +11,65 @@ "ring": "Ring", "share": "Share", "stop": "Stop", - "unpair": "Unpair", - "usb": "USB Mode" + "unpair": "Unpair" }, "error": { "browse_failed": "Failed to browse device", "cast_failed": "Cast failed", - "cli_failed": "Command failed", "conn_failed": "Wireless connection failed", "conn_hint": "Could not connect to the debug port. On your phone's Wireless debugging main screen (not the pairing popup), read the port under \"IP address & Port\" and enter it in the Debug port field, then retry.", "device_offline": "Device paired but offline. Keep the phone's screen on, confirm \"IP address & Port\" on the Wireless debugging main screen, enter that port in the Debug port field and retry.", + "device_offline_hint": "Device is offline.", + "no_device": "No device connected", + "no_device_hint": "Connect a device first.", "pair_failed": "Pairing failed", "pick_failed": "Failed to open file picker", "pick_in_progress": "A file picker is already open", "share_failed": "Failed to share" }, "media": { - "mute": "Mute", "next": "Next", "pause": "Pause", "play": "Play", - "previous": "Previous", - "stop": "Stop", - "unmute": "Unmute" + "previous": "Previous" }, "notify": { - "browse_failed": "Open browse failed", - "disconnected": "Disconnected: {name}", "file_shared": "Sending file to device...", - "network_recovered": "Network recovered, retrying auto-connect", "opening_browser": "Opening file browser...", "pair_success": "Paired successfully", - "retry_exhausted": "Failed to connect to {name} after 3 retries. Please confirm the phone is online.", "sms_sent": "SMS sent", "started": "Mirroring started: {name}", - "stopped": "Mirroring stopped: {name}", - "uninstalled": "Plugin uninstalled. Close any running scrcpy windows manually." + "stopped": "Mirroring stopped: {name}" }, "panel": { - "adb_hint": "ADB device — cast from the action panel.", - "bit_rate": "Bitrate", - "cancel": "Cancel", + "available": "AVAILABLE", + "bit_rate": "BIT", "cast_offline_hint": "Device is not reachable by adb. Check the USB cable / wireless debugging, then retry.", - "close": "Close", - "confirm": "OK", - "debug_port_placeholder": "Debug port (default 5555)", - "devices_connected": "{connected} connected", + "clear": "Clear", + "contact_name": "Contact name", + "debug_port_placeholder": "Debug port", + "devices": "DEVICES", + "edit_name": "Edit contact name", "empty": "No devices found. Pair a device in KDE Connect.", + "fav_add_tooltip": "Favorite this number", + "fav_empty": "No favorite numbers yet", "max_fps": "FPS", - "max_size": "Resolution", + "max_size": "RES", + "no_matches": "No matching contacts", "no_media": "No media playing", - "now_playing": "Now Playing", - "pair_add": "Pair new wireless device", - "pair_addr_placeholder": "IP:Port (e.g. 192.168.1.3:39001)", - "pair_btn": "Pair (ADB)", "pair_code_placeholder": "Pairing code (6 digits)", - "pair_first_hint": "On your phone's Wireless debugging main screen: the debug port is under \"IP address & Port\". If you can't find it, leave it at 5555 — the plugin will also try 5555 and the pairing port automatically. The pairing port + 6-digit code are in \"Pair device with pairing code\".", - "pair_first_title": "First-time wireless setup", - "pair_hint": "The **pairing port** is one-time — used by `adb pair` with the 6-digit code. The **debug port** is for long-term `adb connect` / scrcpy. After pairing, use the debug port to connect.", "pair_missing": "Enter both the pairing port and code first.", - "pair_port_placeholder": "Pairing port", - "params": "Cast Parameters", - "params_hint": "Applies to the selected device only", - "preset_custom": "Custom", + "pair_port_placeholder": "Pair port", + "phone_placeholder": "ex: 1234567890", + "preset_custom": "Cust", "preset_hd": "HD", - "preset_perf": "Balanced", - "preset_save": "Power save", + "preset_perf": "Bal", + "preset_save": "Save", "record": "Record", "record_desc": "Record the mirror to a file", - "sms": "Send SMS", "sms_dest": "Phone number", "sms_msg": "Message", "sms_send": "Send", - "start_cast": "Start Casting", "turn_screen_off": "Screen Off", "turn_screen_off_desc": "Phone screen off while mirroring" }, @@ -159,9 +146,9 @@ }, "status": { "connected": "Connected", - "mirroring": "Mirroring", + "disconnected": "Disconnected", "no_backend": "KDE Connect not running", "no_devices": "No devices", "offline": "Offline" } -} +} \ No newline at end of file diff --git a/phone-operate/translations/zh-Hans.json b/phone-operate/translations/zh-Hans.json index fcd4e4492..52c12b7fa 100644 --- a/phone-operate/translations/zh-Hans.json +++ b/phone-operate/translations/zh-Hans.json @@ -3,6 +3,7 @@ "browse": "浏览", "cast": "投屏", "clipboard": "剪贴板", + "connect": "Connect", "disconnect": "断开", "pair": "配对", "ping": "Ping", @@ -10,79 +11,65 @@ "ring": "响铃", "share": "分享", "stop": "停止", - "unpair": "取消配对", - "usb": "回 USB" + "unpair": "取消配对" }, "error": { "browse_failed": "浏览设备失败", "cast_failed": "投屏失败", - "cli_failed": "命令失败", "conn_failed": "无线连接失败", "conn_hint": "无法连接调试端口。请在手机「无线调试」主界面(不是配对弹窗)查看『IP 地址和端口』一行显示的端口,填入「调试端口」输入框后重试。", "device_offline": "设备已配对但处于离线状态(offline)。请保持手机亮屏、在「无线调试」主界面确认『IP 地址和端口』,把该端口填入「调试端口」框后重试。", + "device_offline_hint": "Device is offline.", + "no_device": "No device connected", + "no_device_hint": "Connect a device first.", "pair_failed": "配对失败", "pick_failed": "无法打开文件选择器", "pick_in_progress": "文件选择器已打开", "share_failed": "分享失败" }, "media": { - "mute": "静音", "next": "下一首", "pause": "暂停", "play": "播放", - "previous": "上一首", - "stop": "停止", - "unmute": "恢复音量" + "previous": "上一首" }, "notify": { - "browse_failed": "打开浏览失败", - "disconnected": "已断开连接:{name}", "file_shared": "正在发送文件到设备...", - "network_recovered": "网络已恢复,正在重新自动连接", "opening_browser": "正在打开文件浏览器...", "pair_success": "配对成功", - "retry_exhausted": "连接 {name} 失败,3 次重试均未成功,请确认手机在线", "sms_sent": "短信已发送", "started": "已开始投屏:{name}", - "stopped": "已停止投屏:{name}", - "uninstalled": "插件已卸载,正在运行的 scrcpy 窗口请手动关闭" + "stopped": "已停止投屏:{name}" }, "panel": { - "adb_hint": "ADB 设备——通过操作面板投屏。", + "available": "AVAILABLE", "bit_rate": "码率", - "cancel": "取消", "cast_offline_hint": "设备未被 adb 识别。请检查 USB 连接或无线调试,然后重试。", - "close": "关闭", - "confirm": "确定", - "debug_port_placeholder": "调试端口(默认 5555)", - "devices_connected": "已连接 {connected}", + "clear": "清空", + "contact_name": "联系人姓名", + "debug_port_placeholder": "Debug port", + "devices": "DEVICES", + "edit_name": "编辑姓名", "empty": "未找到设备。请在 KDE Connect 中配对设备。", + "fav_add_tooltip": "收藏此号码", + "fav_empty": "暂无常用联系人", "max_fps": "帧率", "max_size": "分辨率", + "no_matches": "无匹配联系人", "no_media": "无媒体播放", - "now_playing": "正在播放", - "pair_add": "配对新无线设备", - "pair_addr_placeholder": "IP:端口(如 192.168.1.3:39001)", - "pair_btn": "配对 (ADB)", "pair_code_placeholder": "配对码(6 位数字)", - "pair_first_hint": "手机「无线调试」主界面:调试端口在『IP 地址和端口』一行。找不到就留 5555——插件会自动再试 5555 和配对端口。配对端口和 6 位配对码在「使用配对码配对设备」弹窗里。", - "pair_first_title": "首次无线连接设置", - "pair_hint": "**配对端口**为一次性——用 `adb pair` 配 6 位配对码。**调试端口**用于长期 `adb connect` / scrcpy。配对后用调试端口连接。", "pair_missing": "请先输入配对端口和配对码。", - "pair_port_placeholder": "配对端口", - "params": "投屏参数", - "params_hint": "参数仅对选中设备生效", - "preset_custom": "自定义", + "pair_port_placeholder": "Pair port", + "phone_placeholder": "1234567890", + "preset_custom": "Cust", "preset_hd": "高清", - "preset_perf": "性能", - "preset_save": "省电", + "preset_perf": "Bal", + "preset_save": "Save", "record": "录屏", "record_desc": "将投屏录制到文件", - "sms": "发送短信", "sms_dest": "手机号码", "sms_msg": "短信内容", "sms_send": "发送", - "start_cast": "开始投屏", "turn_screen_off": "熄屏", "turn_screen_off_desc": "手机屏幕熄灭,继续投屏" }, @@ -159,7 +146,7 @@ }, "status": { "connected": "已连接", - "mirroring": "投屏中", + "disconnected": "Disconnected", "no_backend": "KDE Connect 未运行", "no_devices": "无设备", "offline": "离线" From 98abf141c1fb3da64d4751d55fbabea7d76330c5 Mon Sep 17 00:00:00 2001 From: brightestautumn Date: Wed, 9 Sep 2026 00:41:18 +0530 Subject: [PATCH 2/2] Bump version from 0.1.1 to 1.0.0 --- phone-operate/plugin.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phone-operate/plugin.toml b/phone-operate/plugin.toml index 945d531ce..d542e9870 100644 --- a/phone-operate/plugin.toml +++ b/phone-operate/plugin.toml @@ -1,6 +1,6 @@ id = "icefish/phone-operate" name = "Phone Operate" -version = "0.1.1" +version = "1.0.0" plugin_api = 22 author = "icefish" license = "MIT" @@ -194,4 +194,4 @@ keyboard_focus = "on_demand" id = "device" entry = "launcher.luau" prefix = "ph" -glyph = "device-mobile" \ No newline at end of file +glyph = "device-mobile"