theme config, layout preview, container alignment
Server: ThemeConfig entity + CRUD (GET/PUT /theme), SQLite persistence, ThemeUpdate broadcast to ESP32 on save and initial connect. Client: render engine uses theme colors, full-screen redraw on theme change. SPA: theme page with color pickers + presets, layout preview with TS port of layout engine, justify/align controls on containers. DisplayHint refactored to struct (kind + h_align + v_align).
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use crate::error::TcpServerError;
|
||||
use domain::{BroadcastPort, DisplayHint, Layout, WidgetId, WidgetState};
|
||||
use protocol::{ServerMessage, WidgetDescriptor, WireLayoutNode, encode};
|
||||
use domain::{BroadcastPort, DisplayHint, Layout, ThemeConfig, WidgetId, WidgetState};
|
||||
use protocol::{ServerMessage, WidgetDescriptor, WireColor, WireLayoutNode, WireTheme, encode};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
pub struct TcpBroadcaster {
|
||||
@@ -70,4 +70,26 @@ impl BroadcastPort for TcpBroadcaster {
|
||||
let frame = encode(&msg).map_err(TcpServerError::Encode)?;
|
||||
self.send_frame(frame)
|
||||
}
|
||||
|
||||
async fn push_theme_update(&self, theme: &ThemeConfig) -> Result<(), Self::Error> {
|
||||
let wire_theme = domain_theme_to_wire(theme);
|
||||
let msg = ServerMessage::ThemeUpdate { theme: wire_theme };
|
||||
let frame = encode(&msg).map_err(TcpServerError::Encode)?;
|
||||
self.send_frame(frame)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn domain_theme_to_wire(t: &ThemeConfig) -> WireTheme {
|
||||
let c = |c: &domain::ThemeColor| WireColor {
|
||||
r: c.r,
|
||||
g: c.g,
|
||||
b: c.b,
|
||||
};
|
||||
WireTheme {
|
||||
primary: c(&t.primary),
|
||||
secondary: c(&t.secondary),
|
||||
accent: c(&t.accent),
|
||||
text: c(&t.text),
|
||||
background: c(&t.background),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::broadcaster::domain_theme_to_wire;
|
||||
use crate::client_tracker::ClientTracker;
|
||||
use crate::error::TcpServerError;
|
||||
use domain::{ConfigRepository, WidgetStateReader};
|
||||
@@ -103,11 +104,24 @@ where
|
||||
widgets: wire_widgets,
|
||||
};
|
||||
|
||||
match encode(&msg) {
|
||||
Ok(frame) => Some(frame),
|
||||
let mut combined = match encode(&msg) {
|
||||
Ok(frame) => frame,
|
||||
Err(e) => {
|
||||
error!(error = %e, "failed to encode initial screen update");
|
||||
None
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
if let Ok(Some(theme)) = config.get_theme().await {
|
||||
let wire_theme = domain_theme_to_wire(&theme);
|
||||
let theme_msg = ServerMessage::ThemeUpdate { theme: wire_theme };
|
||||
match encode(&theme_msg) {
|
||||
Ok(frame) => combined.extend_from_slice(&frame),
|
||||
Err(e) => {
|
||||
error!(error = %e, "failed to encode initial theme update");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(combined)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user