1
0

fix: restart periodic keys on device page switch, render display output in UI grid

- daemon.go: call stopPeriodicKeys/startPeriodicKeys after page switch
  from device gesture and auto-switch (was missing, causing goroutines
  to never restart for the correct page)
- app.js: forward display output background to /api/render preview URL
- index.html: show preview image and text from display output when key
  has no configured background/icon/label
This commit is contained in:
Maksim Totmin 2026-06-17 11:12:00 +07:00
parent b075b72eea
commit e3eb1a9174
3 changed files with 22 additions and 12 deletions

View File

@ -114,8 +114,9 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error {
if a.Type == "page" { if a.Type == "page" {
asm.NotifyManualPage(a.Page) asm.NotifyManualPage(a.Page)
} }
for _, pm := range pageMgrs[1:] { for _, pm := range pageMgrs {
pm.ActivatePage(newPage) pm.stopPeriodicKeys()
pm.startPeriodicKeys()
} }
web.BroadcastPageChange(newPage) web.BroadcastPageChange(newPage)
} }
@ -195,6 +196,7 @@ func Run(ctx context.Context, cfg *config.Config, opts RunOptions) error {
if err := pm.ActivatePage(page); err != nil { if err := pm.ActivatePage(page); err != nil {
slog.Warn("auto-switch: activate page", "error", err) slog.Warn("auto-switch: activate page", "error", err)
} }
pm.stopPeriodicKeys()
pm.startPeriodicKeys() pm.startPeriodicKeys()
} }
web.BroadcastPageChange(page) web.BroadcastPageChange(page)

View File

@ -116,7 +116,7 @@ document.addEventListener('alpine:init', () => {
syncSettings() { syncSettings() {
this.settingsForm = { this.settingsForm = {
brightness: this.config.devices?.[0]?.brightness || 75, brightness: this.getDeviceConfig(this.activeDeckSerial)?.brightness ?? 75,
font: this.config.font || 'medium', font: this.config.font || 'medium',
screensaver_enabled: this.config.screensaver?.enabled || false, screensaver_enabled: this.config.screensaver?.enabled || false,
screensaver_idle: this.config.screensaver?.idle_seconds || 30, screensaver_idle: this.config.screensaver?.idle_seconds || 30,
@ -141,6 +141,10 @@ document.addEventListener('alpine:init', () => {
|| { keys_x: 5, keys_y: 3, num_keys: 15 } || { keys_x: 5, keys_y: 3, num_keys: 15 }
}, },
getDeviceConfig(serial) {
return this.config.devices?.find(d => d.serial === serial)
},
// ── Grid ── // ── Grid ──
get gridKeys() { get gridKeys() {
const page = this.currentPage const page = this.currentPage
@ -183,7 +187,8 @@ document.addEventListener('alpine:init', () => {
if (label) url += `&label=${encodeURIComponent(label)}` if (label) url += `&label=${encodeURIComponent(label)}`
if (k.icon_scale != null) url += `&icon_scale=${k.icon_scale}` if (k.icon_scale != null) url += `&icon_scale=${k.icon_scale}`
if (k.font_size != null) url += `&font_size=${k.font_size}` if (k.font_size != null) url += `&font_size=${k.font_size}`
if (k.background) url += `&background=${encodeURIComponent(k.background)}` const bg = dout?.background || k.background
if (bg) url += `&background=${encodeURIComponent(bg)}`
return url return url
}, },
@ -584,10 +589,13 @@ document.addEventListener('alpine:init', () => {
// ── Settings ── // ── Settings ──
async saveSettings() { async saveSettings() {
if (!this.config.devices || this.config.devices.length === 0) { if (!this.config.devices) this.config.devices = []
this.config.devices = [{ serial: '', brightness: 75 }] let dev = this.config.devices.find(d => d.serial === this.activeDeckSerial)
if (!dev) {
dev = { serial: this.activeDeckSerial, brightness: 75 }
this.config.devices.push(dev)
} }
this.config.devices[0].brightness = parseInt(this.settingsForm.brightness) dev.brightness = parseInt(this.settingsForm.brightness)
this.config.font = this.settingsForm.font || 'medium' this.config.font = this.settingsForm.font || 'medium'
this.config.screensaver = { this.config.screensaver = {
enabled: this.settingsForm.screensaver_enabled, enabled: this.settingsForm.screensaver_enabled,

View File

@ -59,15 +59,15 @@
:style="key.displayBg ? { backgroundColor: key.displayBg } : {}" :style="key.displayBg ? { backgroundColor: key.displayBg } : {}"
:class="{ empty: !key.configured }" :class="{ empty: !key.configured }"
@click="editKey(key.index)"> @click="editKey(key.index)">
<img x-show="key.configured && key.background" <img x-show="key.configured && (key.background || key.displayBg)"
:src="key.previewUrl" alt=""> :src="key.previewUrl" alt="">
<i x-show="key.configured && !key.background && isFAIcon(key.icon)" <i x-show="key.configured && !key.background && !key.displayBg && isFAIcon(key.icon)"
:class="faClass(key.icon)" class="fa-preview"></i> :class="faClass(key.icon)" class="fa-preview"></i>
<img x-show="key.configured && !key.background && !isFAIcon(key.icon) && key.icon" <img x-show="key.configured && !key.background && !key.displayBg && !isFAIcon(key.icon) && key.icon"
:src="key.previewUrl" alt=""> :src="key.previewUrl" alt="">
<span x-show="key.configured && !key.background && !key.icon && key.label" <span x-show="key.configured && !key.background && !key.displayBg && !key.icon && (key.label || key.displayText)"
style="font-size:12px;color:#fff;opacity:0.75;text-align:center;line-height:1.2;padding:4px;" style="font-size:12px;color:#fff;opacity:0.75;text-align:center;line-height:1.2;padding:4px;"
x-text="key.label"></span> x-text="key.displayText || key.label"></span>
<span x-show="!key.configured" style="color:var(--text-muted);font-size:24px;opacity:0.5;line-height:1;">+</span> <span x-show="!key.configured" style="color:var(--text-muted);font-size:24px;opacity:0.5;line-height:1;">+</span>
<div class="action-icons" x-show="key.hasAction"> <div class="action-icons" x-show="key.hasAction">
<template x-for="(t, ti) in key.actionTypes.slice(0,3)" :key="ti"> <template x-for="(t, ti) in key.actionTypes.slice(0,3)" :key="ti">