From 8c9c72fcba653a0c942416c51d1f40ccfd6fe9c7 Mon Sep 17 00:00:00 2001 From: HenryDu8133 <813367384@qq.com> Date: Mon, 17 Aug 2026 19:17:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(display):=20=E4=BC=98=E5=8C=96=E5=A4=96?= =?UTF-8?q?=E6=8E=A5=E6=98=BE=E7=A4=BA=E5=99=A8=E5=B0=8F=E5=B1=8F=E8=87=AA?= =?UTF-8?q?=E9=80=82=E5=BA=94=E6=98=BE=E7=A4=BA=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 textScale 自动分级:根据显示器实际尺寸在 1.0/0.75/0.5 间自适应选择 - 实现 L/M/S 三档布局模式:L(大屏双栏完整)、M(中屏单栏精简)、S(小屏极简核心信息) - 小屏模式隐藏日志、即将到达列车等次要信息,优先展示当前列车和发车倒计时 - 音频状态标签在小屏下进一步压缩缩写 (Sta Ann / Sp Ann) - 版本升级至 v1.0.113 --- station_broadcast.lua | 184 +++++++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 45 deletions(-) diff --git a/station_broadcast.lua b/station_broadcast.lua index 09d0d89..ee8aceb 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -1,6 +1,6 @@ -- 1. Configuration & Constants -local APP_VERSION_TEXT = "v1.0.112" +local APP_VERSION_TEXT = "v1.0.113" local CONFIG = { CLOUD_URL = "ws://stabadmin.fse-media.group", @@ -125,7 +125,23 @@ function Peripherals.init() local monitors = { peripheral.find("monitor") } if #monitors > 0 then Peripherals.primaryMonitor = monitors[1] - Peripherals.primaryMonitor.setTextScale(0.5) + local mw, mh = Peripherals.primaryMonitor.getSize() + local scale = 0.5 + if mw >= 80 and mh >= 25 then + scale = 1.0 + elseif mw >= 55 and mh >= 18 then + scale = 0.75 + elseif mw >= 38 and mh >= 13 then + scale = 0.5 + else + scale = 0.5 + pcall(function() Peripherals.primaryMonitor.setTextScale(1) end) + local testW, testH = Peripherals.primaryMonitor.getSize() + if testW >= 26 and testH >= 9 then + scale = 1 + end + end + pcall(function() Peripherals.primaryMonitor.setTextScale(scale) end) State.hasPrimaryMonitor = true else Peripherals.primaryMonitor = nil @@ -3089,16 +3105,23 @@ function Display.render() local w, h = mon.getSize() mon.clear() - local hasSchedulePanel = State.currentTrain ~= nil + local layoutMode = "S" + if w >= 38 and h >= 16 then + layoutMode = "L" + elseif w >= 26 and h >= 10 then + layoutMode = "M" + end + + local hasSchedulePanel = State.currentTrain ~= nil and layoutMode == "L" local leftW = w local sepX = nil local rightX = nil local rightW = 0 - if hasSchedulePanel and w >= 30 then + if hasSchedulePanel then rightW = math.min(math.max(math.floor(w * 0.38), 18), 40) leftW = w - rightW - 1 - if leftW < 12 then + if leftW < 14 then leftW = w rightW = 0 else @@ -3107,14 +3130,14 @@ function Display.render() end end - Utils.log("DEBUG", string.format("Monitor size W=%d H=%d, schedulePanel=%s leftW=%d rightW=%d", w, h, tostring(rightX ~= nil), leftW, rightW)) + Utils.log("DEBUG", string.format("Monitor W=%d H=%d Mode=%s Panel=%s LW=%d RW=%d", w, h, layoutMode, tostring(rightX ~= nil), leftW, rightW)) local function classifyAudioSource(source, priority) local s = tostring(source or ""):lower() - if s == "train" or s == "station" or s == "broadcast" then return "Station Announcement" end - if s ~= "" then return "Special Announcement(" .. tostring(source) .. ")" end - if (tonumber(priority) or 0) >= 2 then return "Special Announcement" end - return "Special Announcement" + if s == "train" or s == "station" or s == "broadcast" then return "Sta Ann" end + if s ~= "" then return "Sp Ann(" .. tostring(source) .. ")" end + if (tonumber(priority) or 0) >= 2 then return "Sp Ann" end + return "Sp Ann" end local function truncL(str) @@ -3151,14 +3174,30 @@ function Display.render() end end - drawLeft(1, "STATION: " .. State.stationName .. " " .. APP_VERSION_TEXT, COLORS.INFO) - drawLeft(2, "CODE: " .. tostring(State.stationCode) .. " P:" .. tostring(State.stationPlatform) .. " " .. tostring(State.stationIdentityMode), COLORS.INFO) - drawLeft(3, "TIME: " .. os.date("%H:%M:%S"), COLORS.INFO) + local y = 1 + if layoutMode == "L" then + drawLeft(y, "STATION: " .. State.stationName .. " " .. APP_VERSION_TEXT, COLORS.INFO) + y = y + 1 + drawLeft(y, "CODE: " .. tostring(State.stationCode) .. " P:" .. tostring(State.stationPlatform) .. " " .. tostring(State.stationIdentityMode), COLORS.INFO) + y = y + 1 + drawLeft(y, "TIME: " .. os.date("%H:%M:%S"), COLORS.INFO) + y = y + 1 + elseif layoutMode == "M" then + drawLeft(y, State.stationName .. " [" .. tostring(State.stationCode) .. "/P" .. tostring(State.stationPlatform) .. "] " .. os.date("%H:%M:%S"), COLORS.INFO) + y = y + 1 + else + drawLeft(y, tostring(State.stationCode) .. "/P" .. tostring(State.stationPlatform) .. " " .. os.date("%H:%M"), COLORS.INFO) + y = y + 1 + end + + local audioLine = "AUDIO: FREE(Q" .. tostring(#State.audioQueue) .. ")" + local audioColor = COLORS.INFO if State.currentPlaying then local p = tonumber(State.currentPlaying.priority) or 0 local kind = classifyAudioSource(State.currentPlaying.source, p) - drawLeft(4, "AUDIO: " .. kind .. " Playing (P=" .. tostring(p) .. ", Q=" .. tostring(#State.audioQueue) .. ")", COLORS.SUCCESS) + audioLine = "PLAY: " .. kind .. "(P" .. tostring(p) .. " Q" .. tostring(#State.audioQueue) .. ")" + audioColor = COLORS.SUCCESS elseif State.audioRx then local p = tonumber(State.audioRx.priority) or 0 local kind = classifyAudioSource(State.audioRx.source, p) @@ -3166,28 +3205,54 @@ function Display.render() local total = tonumber(State.audioRx.expectedBytes) or 0 local pct = "" if total > 0 then pct = " " .. tostring(math.floor((rx / total) * 100)) .. "%" end - drawLeft(4, "AUDIO: " .. kind .. " Receiving" .. pct .. " (Q=" .. tostring(#State.audioQueue) .. ")", COLORS.DEBUG) - else - drawLeft(4, "AUDIO: FREE (Q=" .. tostring(#State.audioQueue) .. ")", COLORS.INFO) + audioLine = "RX: " .. kind .. pct .. "(Q" .. tostring(#State.audioQueue) .. ")" + audioColor = COLORS.DEBUG end + if layoutMode == "S" then + audioLine = audioLine:gsub("AUDIO: ", ""):gsub("PLAY: ", ">"):gsub("RX: ", ">>") + end + drawLeft(y, audioLine, audioColor) + y = y + 1 - local contentBottom = 4 + local contentBottom = y - 1 if State.currentTrain then - drawLeft(5, "CURRENT TRAIN:", COLORS.SUCCESS) - drawLeft(6, State.currentTrain.id, COLORS.INFO) - drawLeft(7, "Dest: " .. State.currentTrain.dest, COLORS.INFO) + if layoutMode == "L" then + drawLeft(y, "CURRENT TRAIN:", COLORS.SUCCESS) + y = y + 1 + drawLeft(y, State.currentTrain.id, COLORS.INFO) + y = y + 1 + drawLeft(y, "Dest: " .. State.currentTrain.dest, COLORS.INFO) + y = y + 1 + elseif layoutMode == "M" then + drawLeft(y, "TRAIN: " .. State.currentTrain.id, COLORS.SUCCESS) + y = y + 1 + drawLeft(y, ">> " .. State.currentTrain.dest, COLORS.INFO) + y = y + 1 + else + drawLeft(y, State.currentTrain.id, COLORS.SUCCESS) + y = y + 1 + drawLeft(y, ">" .. Utils.sanitizeDisplay(State.currentTrain.dest), COLORS.INFO) + y = y + 1 + end if State.currentTrain.departureTime then local remaining = math.max(0, State.currentTrain.departureTime - os.epoch("utc") / 1000) if remaining > 0 then - drawLeft(9, string.format("Departing in: %02d:%02d", math.floor(remaining/60), math.floor(remaining%60)), COLORS.WARNING) + local mm = math.floor(remaining / 60) + local ss = math.floor(remaining % 60) + if layoutMode == "S" then + drawLeft(y, string.format("DEP %02d:%02d", mm, ss), COLORS.WARNING) + else + drawLeft(y, string.format("Departing in: %02d:%02d", mm, ss), COLORS.WARNING) + end else - drawLeft(9, "Departing...", COLORS.ERROR) + drawLeft(y, "DEPARTING...", COLORS.ERROR) end - contentBottom = 9 + y = y + 1 + contentBottom = y - 1 else - contentBottom = 7 + contentBottom = y - 1 end if rightX then @@ -3313,40 +3378,57 @@ function Display.render() end end else - if Peripherals.station then - drawLeft(5, "NO TRAIN AT PLATFORM", COLORS.WARNING) + if layoutMode == "S" then + if Peripherals.station then + drawLeft(y, "NO TRAIN", COLORS.WARNING) + else + drawLeft(y, "SLAVE MODE", COLORS.WARNING) + end else - drawLeft(5, "SLAVE NODE MODE", COLORS.WARNING) + if Peripherals.station then + drawLeft(y, "NO TRAIN AT PLATFORM", COLORS.WARNING) + else + drawLeft(y, "SLAVE NODE MODE", COLORS.WARNING) + end end - contentBottom = 5 + y = y + 1 + contentBottom = y - 1 end local logsStartY = h local upcomingStartY = contentBottom + 1 - if Peripherals.blockReader or Peripherals.createTarget then + local allowUpcoming = (Peripherals.blockReader or Peripherals.createTarget) + + if allowUpcoming and layoutMode ~= "S" then local hasUpcoming = State.upcomingTrains and #State.upcomingTrains > 0 - drawLeft(upcomingStartY, "UPCOMING TRAINS:", COLORS.DEBUG) + local upcomingLabel = "UPCOMING:" + if layoutMode == "M" then upcomingLabel = "NEXT:" end + drawLeft(upcomingStartY, upcomingLabel, COLORS.DEBUG) if hasUpcoming then - local visibleCount = math.min(3, #State.upcomingTrains) + local maxUpcoming = 3 + if layoutMode == "M" then maxUpcoming = 2 end + local visibleCount = math.min(maxUpcoming, #State.upcomingTrains) for i = 1, visibleCount do local lineY = upcomingStartY + i if lineY > h then break end local t = State.upcomingTrains[i] local suffix = "" if t.cancelled then - suffix = " [CANCEL]" + suffix = " [X]" elseif (tonumber(t.delay) or 0) > 0 then - local reason = t.reason and (" " .. tostring(t.reason)) or "" - suffix = " [+" .. tostring(t.delay) .. "m" .. reason .. "]" - elseif t.reason then - suffix = " [" .. tostring(t.reason) .. "]" + suffix = " [+" .. tostring(t.delay) .. "m]" end local pfx = "" if t.platform and tostring(t.platform) ~= "" then pfx = "P" .. tostring(t.platform) .. " " end local etaLabel = tostring(t.etaLabel or (tostring(t.eta or 0) .. "s")) - local lineText = string.format("%s%s->%s ETA:%s%s", pfx, t.trainName, t.dest, etaLabel, suffix) + local lineText + if layoutMode == "M" then + lineText = string.format("%s%s>%s %s%s", pfx, Utils.sanitizeDisplay(t.trainName), Utils.sanitizeDisplay(t.dest), etaLabel, suffix) + else + lineText = string.format("%s%s->%s ETA:%s%s", pfx, t.trainName, t.dest, etaLabel, suffix) + end drawLeft(lineY, lineText, COLORS.INFO) end logsStartY = math.max(logsStartY, upcomingStartY + visibleCount + 1) @@ -3359,13 +3441,25 @@ function Display.render() end end - local maxLogLines = math.min(3, math.max(0, h - logsStartY + 1)) - for i = 1, maxLogLines do - local logIdx = i + State.logScrollOffset - local entry = State.logs[logIdx] - if entry then - local lineY = logsStartY + i - 1 - drawLeft(lineY, Utils.sanitizeDisplay(entry.text), COLORS[entry.level] or colors.white) + if layoutMode == "L" then + local maxLogLines = math.min(3, math.max(0, h - logsStartY + 1)) + for i = 1, maxLogLines do + local logIdx = i + State.logScrollOffset + local entry = State.logs[logIdx] + if entry then + local lineY = logsStartY + i - 1 + drawLeft(lineY, Utils.sanitizeDisplay(entry.text), COLORS[entry.level] or colors.white) + end + end + elseif layoutMode == "M" then + local maxLogLines = math.min(1, math.max(0, h - logsStartY + 1)) + for i = 1, maxLogLines do + local logIdx = i + State.logScrollOffset + local entry = State.logs[logIdx] + if entry then + local lineY = logsStartY + i - 1 + drawLeft(lineY, Utils.sanitizeDisplay(entry.text), COLORS[entry.level] or colors.white) + end end end end