Files
flyradar/src/splash_screen.cpp
Eiswolf-BG 7137e50d66 v2.7.3: Flight logbook safety net, radar/clock/timezone fixes
New:
- Flight logbook safety net: disabled by default, requires confirming
  a full-screen warning before it can be turned on, and automatically
  switches off again after exactly 24 hours - survives restarts and
  power cycles (no valid enable timestamp = guaranteed off). Each
  activation now writes its own CSV file instead of endlessly
  appending to one growing file, and every file can be deleted
  individually from Logbook files.
- Adjustable display brightness (10-100% in 10% steps, Menu -> System
  -> "Brightness") with a live preview.
- About screen (Menu -> System -> "About") showing project name,
  description, and firmware version.

Fixed:
- Radar's red altitude band (>9100m/30000ft) no longer gets dimmed at
  night - the previous dim tone looked orange-brown and was hard to
  tell apart from yellow. Legend and markers are consistent again.
- Radius change no longer leaves a stale "tail" trail behind each
  aircraft between the old and new position.
- Splash screen no longer shows a time-of-day greeting that appeared
  too late in the boot sequence to be useful; the star animation now
  starts immediately instead of only near the end of boot.
- Clock stayed on raw UTC after the first boot instead of local time
  (missing DST handling in some timezones) because the location wait
  loop skipped the timezone lookup once a location was already saved.
- Header clock no longer leaves stale digit fragments behind the
  current time, most visible on the last minute digit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 14:02:01 +02:00

154 lines
5.4 KiB
C++

#include "splash_screen.h"
#include "menu_stars.h"
#include <math.h>
namespace SplashScreen {
namespace {
constexpr uint32_t MIN_DISPLAY_MS = 5000;
uint32_t startMs = 0;
constexpr int16_t STATUS_LINE_H = 18;
constexpr int16_t STATUS_START_Y = 260;
constexpr uint8_t MAX_STATUS_LINES = 3;
void drawRadarReticle(TFT_eSPI& tft, int16_t cx, int16_t cy) {
uint16_t dim = 0x0320;
tft.drawCircle(cx, cy, 80, dim);
tft.drawCircle(cx, cy, 54, dim);
tft.drawCircle(cx, cy, 29, dim);
tft.drawFastHLine(cx - 80, cy, 160, dim);
tft.drawFastVLine(cx, cy - 80, 160, dim);
}
// Dreht einen Punkt (px, py) im lokalen Koordinatensystem der kleinen
// Deko-Symbole um angleDeg und verschiebt ihn nach (x, y).
void rotatePoint(int16_t x, int16_t y, float sinA, float cosA,
float px, float py, int16_t& outX, int16_t& outY) {
outX = x + (int16_t)lroundf(px * cosA - py * sinA);
outY = y + (int16_t)lroundf(px * sinA + py * cosA);
}
// Kleines Flugzeug-Silhouette aus gefuellten Dreiecken (Rumpf, Tragflaechen,
// Leitwerk), analog zum grossen Flugzeug in der Mitte, aber schlichter und
// in beliebiger Richtung (angleDeg, 0 = Nase zeigt nach oben).
void drawMiniJet(TFT_eSPI& tft, int16_t x, int16_t y, uint16_t color, float angleDeg) {
float rad = angleDeg * (PI / 180.0f);
float s = sinf(rad), c = cosf(rad);
int16_t nx, ny, flx, fly, frx, fry;
rotatePoint(x, y, s, c, 0, -11, nx, ny);
rotatePoint(x, y, s, c, -3, 11, flx, fly);
rotatePoint(x, y, s, c, 3, 11, frx, fry);
tft.fillTriangle(nx, ny, flx, fly, frx, fry, color);
int16_t wlx, wly, wrx, wry, wcx, wcy;
rotatePoint(x, y, s, c, -13, 3, wlx, wly);
rotatePoint(x, y, s, c, 13, 3, wrx, wry);
rotatePoint(x, y, s, c, 0, -3, wcx, wcy);
tft.fillTriangle(wlx, wly, wrx, wry, wcx, wcy, color);
int16_t tlx, tly, trx, try_, ttx, tty;
rotatePoint(x, y, s, c, -5, 8, tlx, tly);
rotatePoint(x, y, s, c, 5, 8, trx, try_);
rotatePoint(x, y, s, c, 0, 13, ttx, tty);
tft.fillTriangle(tlx, tly, trx, try_, ttx, tty, color);
}
// Kleiner Helikopter: Rotorkreis mit Blaettern, gefuellter Rumpf, Heckausleger
// mit Leitwerk. angleDeg bestimmt die Flugrichtung (0 = Nase nach oben).
void drawMiniHeli(TFT_eSPI& tft, int16_t x, int16_t y, uint16_t color, float angleDeg) {
float rad = angleDeg * (PI / 180.0f);
float s = sinf(rad), c = cosf(rad);
int16_t rcx, rcy;
rotatePoint(x, y, s, c, 0, -7, rcx, rcy);
tft.drawCircle(rcx, rcy, 6, color);
int16_t b1x, b1y, b2x, b2y;
rotatePoint(x, y, s, c, -7, -7, b1x, b1y);
rotatePoint(x, y, s, c, 7, -7, b2x, b2y);
tft.drawLine(b1x, b1y, b2x, b2y, color);
rotatePoint(x, y, s, c, 0, -13, b1x, b1y);
rotatePoint(x, y, s, c, 0, -1, b2x, b2y);
tft.drawLine(b1x, b1y, b2x, b2y, color);
int16_t cx1, cy1, cx2, cy2, cx3, cy3;
rotatePoint(x, y, s, c, 0, -6, cx1, cy1);
rotatePoint(x, y, s, c, -4, 4, cx2, cy2);
rotatePoint(x, y, s, c, 4, 4, cx3, cy3);
tft.fillTriangle(cx1, cy1, cx2, cy2, cx3, cy3, color);
int16_t tbx1, tby1, tbx2, tby2;
rotatePoint(x, y, s, c, 0, 4, tbx1, tby1);
rotatePoint(x, y, s, c, 0, 12, tbx2, tby2);
tft.drawLine(tbx1, tby1, tbx2, tby2, color);
int16_t fx1, fy1, fx2, fy2, fx3, fy3;
rotatePoint(x, y, s, c, -3, 10, fx1, fy1);
rotatePoint(x, y, s, c, 3, 10, fx2, fy2);
rotatePoint(x, y, s, c, 0, 15, fx3, fy3);
tft.fillTriangle(fx1, fy1, fx2, fy2, fx3, fy3, color);
}
void drawAirplane(TFT_eSPI& tft, int16_t cx) {
uint16_t color = TFT_GREEN;
tft.drawTriangle(cx + 15, 142, cx - 15, 200, cx - 10, 202, color);
tft.drawTriangle(cx + 5, 164, cx - 47, 175, cx - 3, 179, color);
tft.drawTriangle(cx + 5, 164, cx + 30, 211, cx - 3, 179, color);
tft.drawTriangle(cx - 11, 198, cx - 23, 201, cx - 6, 210, color);
}
}
void begin(TFT_eSPI& tft) {
startMs = millis();
MenuStars::reset();
int16_t cx = tft.width() / 2;
tft.fillScreen(TFT_BLACK);
drawRadarReticle(tft, cx, 174);
uint16_t dimGreen = 0x0320;
drawMiniJet(tft, cx - 45, 135, dimGreen, 25.0f);
drawMiniJet(tft, cx + 50, 160, dimGreen, 160.0f);
drawMiniHeli(tft, cx - 35, 215, dimGreen, 250.0f);
drawMiniHeli(tft, cx + 45, 115, dimGreen, 100.0f);
drawAirplane(tft, cx);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setTextSize(2);
tft.drawString("Eiswolfs", cx, 28);
tft.drawString("Flightradar", cx, 60);
tft.setTextDatum(TL_DATUM);
tft.setTextSize(1);
}
void setStatusLine(TFT_eSPI& tft, uint8_t slot, const String& text, uint16_t color) {
if (slot >= MAX_STATUS_LINES) return;
int16_t y = STATUS_START_Y + slot * STATUS_LINE_H;
tft.fillRect(0, y, tft.width(), STATUS_LINE_H, TFT_BLACK);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(color, TFT_BLACK);
tft.drawString(text, tft.width() / 2, y + STATUS_LINE_H / 2);
tft.setTextDatum(TL_DATUM);
}
void waitRemaining(TFT_eSPI& tft) {
uint32_t elapsed = millis() - startMs;
while (elapsed < MIN_DISPLAY_MS) {
MenuStars::update(tft);
delay(20);
elapsed = millis() - startMs;
}
}
}