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