mirror of
https://github.com/skoelle/wt32sc01-dashboard.git
synced 2026-09-17 17:30:25 +00:00
Phase 4: home screen with three touch tiles
- weather tile (big, top, accent blue): temperature + description + rain hint badge, tap -> weather detail - calendar tile (big, middle, accent purple): first 2 events as preview (summary + DateUtils::formatShortDE incl. all_day handling), tap -> calendar detail - mvg tile (small, bottom, accent green): label only, no preview, tap -> mvg screen - 10-minute refresh timer + tick() check (ported from old home_screen.cpp) - data logic reused verbatim: doFetch/weatherOk/calendarOk pattern, willRainSoon threshold, sanitizeGermanText + formatShortDE formatting - placeholder glyphs (LV_SYMBOL_IMAGE/LIST/FILE) until bitmap icons land in Phase 6
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
#include "home_screen.h"
|
||||
#include "ui/widgets/tile_button.h"
|
||||
#include "api/weather_api.h"
|
||||
#include "api/calendar_api.h"
|
||||
#include <theme.h>
|
||||
#include <text_utils.h>
|
||||
#include <date_utils.h>
|
||||
#include <lvgl.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// --- navigation callback target (set by main.cpp) ---
|
||||
ScreenId (*g_navigate)(ScreenId) = nullptr;
|
||||
|
||||
void on_weather_tile(lv_event_t *) { if (g_navigate) g_navigate(ScreenId::WEATHER_DETAIL); }
|
||||
void on_calendar_tile(lv_event_t *) { if (g_navigate) g_navigate(ScreenId::CALENDAR_DETAIL); }
|
||||
void on_mvg_tile(lv_event_t *) { if (g_navigate) g_navigate(ScreenId::MVG); }
|
||||
|
||||
// --- cached data + refresh timer (ported from old home_screen.cpp) ---
|
||||
WeatherData lastWeather;
|
||||
CalendarData lastCalendar;
|
||||
bool weatherOk = false;
|
||||
bool calendarOk = false;
|
||||
unsigned long lastFetchMs = 0;
|
||||
const unsigned long REFRESH_INTERVAL_MS = 10UL * 60UL * 1000UL;
|
||||
|
||||
// --- tile handles (value labels, for updating without rebuild) ---
|
||||
TileButton weatherTile{};
|
||||
TileButton calendarTile{};
|
||||
TileButton mvgTile{};
|
||||
bool widgetsBuilt = false;
|
||||
|
||||
void doFetch() {
|
||||
WeatherData w = fetchWeather();
|
||||
weatherOk = w.valid;
|
||||
if (w.valid) lastWeather = w;
|
||||
CalendarData c = fetchCalendar();
|
||||
calendarOk = c.valid;
|
||||
if (c.valid) lastCalendar = c;
|
||||
lastFetchMs = millis();
|
||||
}
|
||||
|
||||
// --- formatting helpers (ported from old home_screen.cpp rendering) ---
|
||||
|
||||
String weatherIconGlyph(const String &symbol) {
|
||||
// Phase 4 placeholder: map symbol condition to a unicode glyph until
|
||||
// bitmap icons land in Phase 6. m=night, condition char = symbol[1].
|
||||
(void)symbol;
|
||||
return LV_SYMBOL_IMAGE; // cloud/weather placeholder; bitmaps come in Phase 6
|
||||
}
|
||||
|
||||
String formatWeatherValue(const WeatherData &w) {
|
||||
if (!w.valid) return "Wetter n.a.";
|
||||
String s = String(w.current.temperature) + " C";
|
||||
s += "\n" + sanitizeGermanText(w.current.description);
|
||||
if (willRainSoon(w, 8)) s += "\n[Regen moeglich]";
|
||||
return s;
|
||||
}
|
||||
|
||||
String formatCalendarPreview(const CalendarData &c) {
|
||||
if (!c.valid) return "Kalender n.a.";
|
||||
String s;
|
||||
int shown = 0;
|
||||
for (const auto &ev : c.events) {
|
||||
if (shown >= 2) break;
|
||||
if (shown > 0) s += "\n";
|
||||
s += sanitizeGermanText(ev.summary.substring(0, 22));
|
||||
s += "\n" + DateUtils::formatShortDE(ev.startAt, ev.allDay);
|
||||
++shown;
|
||||
}
|
||||
if (s.length() == 0) s = "Keine Termine";
|
||||
return s;
|
||||
}
|
||||
|
||||
void updateWidgets() {
|
||||
if (!widgetsBuilt) return;
|
||||
tile_button_set_value(weatherTile, formatWeatherValue(lastWeather).c_str());
|
||||
tile_button_set_icon(weatherTile, weatherIconGlyph(lastWeather.current.symbol).c_str());
|
||||
tile_button_set_value(calendarTile, formatCalendarPreview(lastCalendar).c_str());
|
||||
tile_button_set_icon(calendarTile, LV_SYMBOL_FILE);
|
||||
tile_button_set_value(mvgTile, "");
|
||||
tile_button_set_icon(mvgTile, LV_SYMBOL_LIST);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Screen homeScreen;
|
||||
|
||||
void homeScreen_setNavigator(Navigator nav) {
|
||||
g_navigate = nav;
|
||||
}
|
||||
|
||||
void homeScreen_create(Screen &s) {
|
||||
// Layout (portrait 320x480):
|
||||
// weather tile x=12 y=12 w=296 h=170 (big, top)
|
||||
// calendar tile x=12 y=194 w=296 h=170 (big, middle, with 2-event preview)
|
||||
// mvg tile x=12 y=376 w=296 h=92 (small, bottom, no preview)
|
||||
weatherTile = tile_button_create(s.root, 12, 12, 296, 170,
|
||||
Theme::accentWeather(), "Wetter",
|
||||
on_weather_tile, nullptr);
|
||||
calendarTile = tile_button_create(s.root, 12, 194, 296, 170,
|
||||
Theme::accentCalendar(), "Termine",
|
||||
on_calendar_tile, nullptr);
|
||||
mvgTile = tile_button_create(s.root, 12, 376, 296, 92,
|
||||
Theme::accentMvg(), "MVG",
|
||||
on_mvg_tile, nullptr);
|
||||
widgetsBuilt = true;
|
||||
}
|
||||
|
||||
void homeScreen_refresh(Screen &) {
|
||||
doFetch();
|
||||
updateWidgets();
|
||||
}
|
||||
|
||||
void homeScreen_tick(Screen &) {
|
||||
if (lastFetchMs == 0 || millis() - lastFetchMs >= REFRESH_INTERVAL_MS) {
|
||||
doFetch();
|
||||
updateWidgets();
|
||||
}
|
||||
}
|
||||
|
||||
Screen homeScreen_make() {
|
||||
Screen s;
|
||||
s.create_fn = homeScreen_create;
|
||||
s.refresh_fn = homeScreen_refresh;
|
||||
s.tick_fn = homeScreen_tick;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "ui/screen_base.h"
|
||||
|
||||
// Home screen: three touch tiles (weather big, calendar big w/ 2 events,
|
||||
// mvg small). Tap navigates to the respective detail screen.
|
||||
|
||||
// Navigation callback type: called with the target ScreenId, returns the
|
||||
// actually-shown ScreenId (so main.cpp can drive transitions + inactivity).
|
||||
using Navigator = ScreenId (*)(ScreenId);
|
||||
|
||||
// Build the home screen object (does not create widgets until show()).
|
||||
Screen homeScreen_make();
|
||||
|
||||
// Set the navigation callback (called by main.cpp once at startup).
|
||||
void homeScreen_setNavigator(Navigator nav);
|
||||
|
||||
extern Screen homeScreen;
|
||||
Reference in New Issue
Block a user