implement dashboard on wake
This commit is contained in:
@@ -16,12 +16,12 @@
|
||||
|
||||
// Tile color themes
|
||||
static const uint16_t tileBG[] = {
|
||||
COL_RED, // LAST_ALERT — red
|
||||
COL_ORANGE, // STATS — orange
|
||||
COL_CYAN, // NETWORK — cyan
|
||||
COL_PURPLE, // MUTE — purple
|
||||
COL_DARK_TILE, // HISTORY — dark
|
||||
COL_DARK_TILE // SYSTEM — dark
|
||||
COL_RED, // LAST_ALERT
|
||||
COL_ORANGE, // STATS
|
||||
COL_CYAN, // NETWORK
|
||||
COL_PURPLE, // MUTE
|
||||
COL_DARK_TILE, // HISTORY
|
||||
COL_DARK_TILE // SYSTEM
|
||||
};
|
||||
|
||||
static const uint16_t tileFG[] = {
|
||||
@@ -31,13 +31,12 @@ static const uint16_t tileFG[] = {
|
||||
Dashboard::Dashboard(TFT_eSPI& tft)
|
||||
: _tft(tft), _sprite(&tft)
|
||||
{
|
||||
// Initialize tile metadata
|
||||
_tiles[TILE_LAST_ALERT] = { "!", "LAST ALERT", "none", "", 0, 0, true };
|
||||
_tiles[TILE_STATS] = { "#", "TODAY", "0 alerts", "", 0, 0, true };
|
||||
_tiles[TILE_NETWORK] = { "~", "NETWORK", "---", "", 0, 0, true };
|
||||
_tiles[TILE_MUTE] = { "M", "MUTE", "OFF", "", 0, 0, true };
|
||||
_tiles[TILE_LAST_ALERT] = { "!", "LAST ALERT", "none", "", 0, 0, true };
|
||||
_tiles[TILE_STATS] = { "#", "TODAY", "0 alerts", "", 0, 0, true };
|
||||
_tiles[TILE_NETWORK] = { "~", "NETWORK", "---", "", 0, 0, true };
|
||||
_tiles[TILE_MUTE] = { "M", "MUTE", "OFF", "", 0, 0, true };
|
||||
_tiles[TILE_HISTORY] = { ">", "HISTORY", "tap to view","", 0, 0, true };
|
||||
_tiles[TILE_SYSTEM] = { "*", "SYSTEM", "---", "", 0, 0, true };
|
||||
_tiles[TILE_SYSTEM] = { "*", "SYSTEM", "---", "", 0, 0, true };
|
||||
|
||||
for (int i = 0; i < TILE_COUNT; i++) {
|
||||
_tiles[i].bgColor = tileBG[i];
|
||||
@@ -46,10 +45,16 @@ Dashboard::Dashboard(TFT_eSPI& tft)
|
||||
}
|
||||
|
||||
void Dashboard::begin() {
|
||||
// Create sprite sized to one tile (reused for each)
|
||||
_sprite.createSprite(TILE_W, TILE_H);
|
||||
_sprite.setTextDatum(MC_DATUM);
|
||||
}
|
||||
|
||||
void Dashboard::drawAll() {
|
||||
_tft.fillScreen(COL_BG);
|
||||
drawTopBar("--:--", 0, false);
|
||||
for (int i = 0; i < TILE_COUNT; i++) {
|
||||
drawTile((TileID)i);
|
||||
}
|
||||
}
|
||||
|
||||
void Dashboard::tilePosition(TileID id, int& x, int& y) {
|
||||
@@ -64,10 +69,7 @@ void Dashboard::drawTile(TileID id) {
|
||||
int tx, ty;
|
||||
tilePosition(id, tx, ty);
|
||||
|
||||
// Draw into sprite (off-screen)
|
||||
_sprite.fillSprite(t.bgColor);
|
||||
|
||||
// Rounded corner effect — draw border pixels
|
||||
_sprite.drawRoundRect(0, 0, TILE_W, TILE_H, 8, COL_GRAY);
|
||||
|
||||
// Icon — large character at top
|
||||
@@ -77,27 +79,25 @@ void Dashboard::drawTile(TileID id) {
|
||||
_sprite.setTextDatum(TC_DATUM);
|
||||
_sprite.drawString(t.icon, TILE_W / 2, 8);
|
||||
|
||||
// Label — below icon
|
||||
// Label
|
||||
_sprite.setTextSize(1);
|
||||
_sprite.setTextFont(2);
|
||||
_sprite.setTextDatum(MC_DATUM);
|
||||
_sprite.drawString(t.label, TILE_W / 2, TILE_H / 2 + 5);
|
||||
|
||||
// Value — bottom area
|
||||
// Value
|
||||
_sprite.setTextFont(2);
|
||||
_sprite.setTextDatum(BC_DATUM);
|
||||
_sprite.drawString(t.value, TILE_W / 2, TILE_H - 25);
|
||||
|
||||
// Sub text — very bottom
|
||||
// Sub text
|
||||
if (strlen(t.sub) > 0) {
|
||||
_sprite.setTextFont(1);
|
||||
_sprite.setTextDatum(BC_DATUM);
|
||||
_sprite.drawString(t.sub, TILE_W / 2, TILE_H - 8);
|
||||
}
|
||||
|
||||
// Push sprite to screen in one operation — no flicker
|
||||
_sprite.pushSprite(tx, ty);
|
||||
|
||||
t.dirty = false;
|
||||
}
|
||||
|
||||
@@ -108,15 +108,13 @@ void Dashboard::drawTopBar(const char* time, int rssi, bool wifiOk) {
|
||||
_tft.setTextFont(4);
|
||||
_tft.setTextSize(1);
|
||||
|
||||
// Title — left
|
||||
_tft.setTextDatum(ML_DATUM);
|
||||
_tft.drawString("KLUBHAUS ALERT", DASH_MARGIN, DASH_TOP_BAR / 2);
|
||||
|
||||
// Time — right
|
||||
_tft.setTextDatum(MR_DATUM);
|
||||
_tft.drawString(time, 470, DASH_TOP_BAR / 2);
|
||||
|
||||
// WiFi indicator — signal bars
|
||||
// WiFi signal bars
|
||||
int bars = 0;
|
||||
if (wifiOk) {
|
||||
if (rssi > -50) bars = 4;
|
||||
@@ -125,26 +123,28 @@ void Dashboard::drawTopBar(const char* time, int rssi, bool wifiOk) {
|
||||
else bars = 1;
|
||||
}
|
||||
|
||||
int barX = 370;
|
||||
int barW = 6;
|
||||
int barGap = 3;
|
||||
int barX = 370, barW = 6, barGap = 3;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int barH = 6 + i * 5;
|
||||
int barY = DASH_TOP_BAR - 8 - barH;
|
||||
uint16_t col = (i < bars) ? COL_GREEN : COL_GRAY;
|
||||
_tft.fillRect(barX + i * (barW + barGap), barY, barW, barH, col);
|
||||
}
|
||||
}
|
||||
|
||||
void Dashboard::drawAll() {
|
||||
drawTopBar("--:--", 0, false);
|
||||
for (int i = 0; i < TILE_COUNT; i++) {
|
||||
drawTile((TileID)i);
|
||||
}
|
||||
// Cache values
|
||||
strncpy(_barTime, time, sizeof(_barTime) - 1);
|
||||
_barRSSI = rssi;
|
||||
_barWifiOk = wifiOk;
|
||||
}
|
||||
|
||||
void Dashboard::updateTile(TileID id, const char* value, const char* sub) {
|
||||
TileData& t = _tiles[id];
|
||||
|
||||
// Dirty check — skip redraw if nothing changed
|
||||
bool changed = (strcmp(t.value, value) != 0);
|
||||
if (sub && strcmp(t.sub, sub) != 0) changed = true;
|
||||
if (!changed && !t.dirty) return;
|
||||
|
||||
strncpy(t.value, value, 31);
|
||||
t.value[31] = '\0';
|
||||
if (sub) {
|
||||
@@ -152,7 +152,7 @@ void Dashboard::updateTile(TileID id, const char* value, const char* sub) {
|
||||
t.sub[31] = '\0';
|
||||
}
|
||||
t.dirty = true;
|
||||
drawTile(id); // immediate redraw of just this tile
|
||||
drawTile(id);
|
||||
}
|
||||
|
||||
int Dashboard::handleTouch(int x, int y) {
|
||||
@@ -167,3 +167,64 @@ int Dashboard::handleTouch(int x, int y) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// Refresh all tiles from ScreenState — only redraws changed tiles
|
||||
// =====================================================================
|
||||
void Dashboard::refreshFromState(const ScreenState& state) {
|
||||
// Top bar — only redraw if changed
|
||||
bool barChanged = (strcmp(_barTime, state.timeString) != 0) ||
|
||||
(_barRSSI != state.wifiRSSI) ||
|
||||
(_barWifiOk != state.wifiConnected);
|
||||
if (barChanged) {
|
||||
drawTopBar(state.timeString, state.wifiRSSI, state.wifiConnected);
|
||||
}
|
||||
|
||||
// LAST ALERT tile
|
||||
if (state.alertHistoryCount > 0) {
|
||||
updateTile(TILE_LAST_ALERT,
|
||||
state.alertHistory[0].message,
|
||||
state.alertHistory[0].timestamp);
|
||||
} else {
|
||||
updateTile(TILE_LAST_ALERT, "none", "");
|
||||
}
|
||||
|
||||
// STATS tile
|
||||
char statsBuf[32];
|
||||
snprintf(statsBuf, sizeof(statsBuf), "%d alert%s",
|
||||
state.alertHistoryCount,
|
||||
state.alertHistoryCount == 1 ? "" : "s");
|
||||
updateTile(TILE_STATS, statsBuf, "this session");
|
||||
|
||||
// NETWORK tile
|
||||
if (state.wifiConnected) {
|
||||
char rssiBuf[16];
|
||||
snprintf(rssiBuf, sizeof(rssiBuf), "%d dBm", state.wifiRSSI);
|
||||
updateTile(TILE_NETWORK, rssiBuf, state.wifiSSID);
|
||||
} else {
|
||||
updateTile(TILE_NETWORK, "DOWN", "reconnecting...");
|
||||
}
|
||||
|
||||
// MUTE tile (placeholder)
|
||||
updateTile(TILE_MUTE, "OFF", "tap to mute");
|
||||
|
||||
// HISTORY tile — show 2nd and 3rd alerts
|
||||
if (state.alertHistoryCount > 1) {
|
||||
char histBuf[48];
|
||||
snprintf(histBuf, sizeof(histBuf), "%s %.20s",
|
||||
state.alertHistory[1].timestamp,
|
||||
state.alertHistory[1].message);
|
||||
const char* sub = (state.alertHistoryCount > 2)
|
||||
? state.alertHistory[2].message : "";
|
||||
updateTile(TILE_HISTORY, histBuf, sub);
|
||||
} else {
|
||||
updateTile(TILE_HISTORY, "no history", "");
|
||||
}
|
||||
|
||||
// SYSTEM tile
|
||||
char heapBuf[16];
|
||||
snprintf(heapBuf, sizeof(heapBuf), "%lu KB", state.freeHeapKB);
|
||||
char uptimeBuf[20];
|
||||
snprintf(uptimeBuf, sizeof(uptimeBuf), "up %lum", state.uptimeMinutes);
|
||||
updateTile(TILE_SYSTEM, heapBuf, uptimeBuf);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user