v2.7.1: Fix layout collisions on Watchlist screens and empty-sky timer

Three small layout bugs found after v2.7.0:
- Watchlist info screen title now wraps word-by-word via
  layoutWrapped() instead of println(), which cut it off mid-word.
- Watchlist overview screen draws the "?" info button first, so the
  title and two description lines start below it instead of running
  underneath and getting obscured.
- The radar's "empty sky for..." timer now shows only whole minutes
  once past the first minute (e.g. "2min" instead of "2min 05s"),
  since the seconds suffix collided with the range button.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Eiswolf-BG
2026-08-06 21:12:41 +02:00
parent 27e56484a6
commit b65e45c3d4
2 changed files with 30 additions and 11 deletions

View File

@@ -164,7 +164,12 @@ namespace {
constexpr int16_t textMaxWidth = Config::SCREEN_WIDTH - 20;
constexpr int16_t LINE_H = 16;
constexpr int16_t VIEW_TOP = 36;
// VIEW_TOP haengt davon ab, wie viele Zeilen der Titel tatsaechlich
// braucht (je nach Sprache 1 oder 2 Zeilen) - vorher "trocken"
// (draw=false) berechnen, damit der Fliesstext nicht in eine
// zweizeilige Titelueberschrift hineinlaeuft.
int16_t titleEndY = layoutWrapped(tft, 10, 14, textMaxWidth, LINE_H, I18n::t(StringId::WATCHLIST_INFO_TITLE), 0, 0, 0, false);
const int16_t VIEW_TOP = titleEndY + 4;
constexpr int16_t VIEW_BOTTOM = Config::SCREEN_HEIGHT - 60;
int16_t totalH = VIEW_TOP;
@@ -187,8 +192,11 @@ namespace {
auto redraw = [&]() {
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(10, 14);
tft.println(I18n::t(StringId::WATCHLIST_INFO_TITLE));
// Titel kann laenger als eine Zeile sein - ueber denselben
// layoutWrapped()-Mechanismus wie den Fliesstext zeichnen, statt
// println() (das keinen wortweisen Umbruch macht und mitten im
// Wort abschneidet/umbricht).
layoutWrapped(tft, 10, 14, textMaxWidth, LINE_H, I18n::t(StringId::WATCHLIST_INFO_TITLE), 0, 0, Config::SCREEN_HEIGHT, true);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
int16_t y = VIEW_TOP;
@@ -234,18 +242,23 @@ void run(TFT_eSPI& tft) {
MenuStars::reset();
while (!done) {
tft.fillScreen(TFT_BLACK);
// Kleiner "?"-Info-Button oben rechts, gleiches Muster wie bei den
// Standort-Presets/dem WLAN-Manager. ZUERST zeichnen, damit Titel/
// Beschreibung bewusst unterhalb davon beginnen (der Titel + zwei
// Beschreibungszeilen liefen vorher UNTER dem Button durch und
// wurden dadurch teilweise verdeckt/abgeschnitten).
Rect infoBtn = {(int16_t)(Config::SCREEN_WIDTH - 40), 2, 30, 24};
drawButton(tft, infoBtn, "?");
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(10, 14);
tft.println(I18n::t(StringId::WATCHLIST_TITLE));
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(10, 26);
tft.setCursor(10, 40);
tft.println(I18n::t(StringId::WATCHLIST_DESC1));
tft.setCursor(10, 38);
tft.setCursor(10, 52);
tft.println(I18n::t(StringId::WATCHLIST_DESC2));
Rect infoBtn = {(int16_t)(Config::SCREEN_WIDTH - 40), 2, 30, 24};
drawButton(tft, infoBtn, "?");
uint8_t count = AircraftWatchlist::count();
int16_t y = 56;

View File

@@ -622,11 +622,17 @@ void render(TFT_eSPI& tft, int16_t top) {
// antippen"-Hinweises (der hier ohnehin ins Leere liefe) zeigen
// wir an, wie lange der Himmel schon leer ist.
uint32_t emptySec = (millis() - lastAircraftSeenMs) / 1000;
char buf[24];
char buf[16];
if (emptySec < 60) {
snprintf(buf, sizeof(buf), "%lus", (unsigned long)emptySec);
} else {
snprintf(buf, sizeof(buf), "%lum %02lus", (unsigned long)(emptySec / 60), (unsigned long)(emptySec % 60));
// Ab der ersten vollen Minute NUR noch Minuten anzeigen (ohne
// Sekunden) - "1min 05s" war zu lang und stiess an den
// Reichweiten-Button rechts daneben. Abgerundet (60-119s =
// "1min", 120-179s = "2min", usw.) - intuitiv wie eine
// normale Stoppuhr-Minutenanzeige.
unsigned long minutes = emptySec / 60;
snprintf(buf, sizeof(buf), "%lumin", minutes);
}
tft.print(String(I18n::t(StringId::RADAR_EMPTY_SKY_PREFIX)) + buf);
} else {