v3.3.0: Welcome screen, factory reset, calibration/touch fixes, flash partition fix

## New
- "Welcome" screen shown on first-time setup (before touch
  calibration), with the splash screen's animated radar graphic and a
  Start button.
- The "Setup complete" screen now counts down 7 seconds with a button
  matching the Welcome screen's style, then automatically continues
  into the app (previously required a tap).
- System menu "Backup & Reset" page (Backup, Restore, and a new
  "Reset settings" option that wipes the on-device data and re-runs
  first-time setup - useful for testing or handing the device to
  someone else).
- Touch calibration targets are now green mini radar reticles instead
  of red crosshairs.

## Improved
- The SD card's data folder is now only created after tapping Start
  on the Welcome screen, instead of on every boot regardless.
- Flash partition layout changed to free up roughly 850 KB of
  firmware space (no OTA update slot needed, since firmware is always
  flashed via cable/USB) - lowers flash usage from ~95% to ~59%.

## Fixed
- The Start button and the WiFi scanning screen now show a loading
  indicator instead of appearing frozen during SD-card/WiFi
  operations.
- A touch-input bug during first-time setup that could corrupt touch
  calibration and cause taps to land on the wrong on-screen element
  afterward (most noticeable in the WiFi network selection list).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Eiswolf-BG
2026-08-12 06:57:48 +02:00
parent ba1c062ef1
commit a7f14b3125
10 changed files with 394 additions and 84 deletions

View File

@@ -36,16 +36,28 @@ namespace {
return y;
}
void drawStartButton(TFT_eSPI& tft, const Rect& r) {
tft.fillRoundRect(r.x, r.y, r.w, r.h, 6, TFT_GREEN);
tft.drawRoundRect(r.x, r.y, r.w, r.h, 6, TFT_GREEN);
// Button frame in the same style as the Start button on the Welcome
// screen (first_run_welcome_screen.cpp::drawButtonFrame) - black fill,
// thin green border, rounded corners. Deliberately no longer fully
// green-filled like the old version of this button, so both first-run
// screens look consistent.
void drawButtonFrame(TFT_eSPI& tft, const Rect& r) {
tft.fillRoundRect(r.x, r.y, r.w, r.h, 8, TFT_BLACK);
tft.drawRoundRect(r.x, r.y, r.w, r.h, 8, TFT_GREEN);
}
// Big, bold (1px-offset technique, same as the "Start" text on the
// Welcome screen) countdown digit in the middle of the button -
// replaces the previous "Flightradar" text.
void drawCountdownText(TFT_eSPI& tft, const Rect& r, const String& text) {
tft.fillRect((int16_t)(r.x + 2), (int16_t)(r.y + 2), (int16_t)(r.w - 4), (int16_t)(r.h - 4), TFT_BLACK);
tft.setTextDatum(MC_DATUM);
tft.setTextColor(TFT_BLACK, TFT_GREEN);
tft.setTextSize(2);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setTextSize(3);
int16_t cx = r.x + r.w / 2;
int16_t cy = r.y + r.h / 2;
tft.drawString("Flightradar", cx, cy);
tft.drawString("Flightradar", (int16_t)(cx + 1), cy);
tft.drawString(text, cx, cy);
tft.drawString(text, (int16_t)(cx + 1), cy);
tft.setTextSize(1);
tft.setTextDatum(TL_DATUM);
}
@@ -70,12 +82,32 @@ void run(TFT_eSPI& tft) {
if (btnY > maxBtnY) btnY = maxBtnY;
Rect startBtn = {10, btnY, (int16_t)(Config::SCREEN_WIDTH - 20), BTN_H};
drawStartButton(tft, startBtn);
drawButtonFrame(tft, startBtn);
while (true) {
TouchInput::Point tap;
if (!TouchInput::wasTapped(tap)) { MenuStars::update(tft); delay(20); continue; }
if (startBtn.contains(tap.x, tap.y)) return;
// Automatic countdown in the button instead of a tappable
// "Flightradar" text - continues automatically into the splash
// screen/app afterward. Tapping the button during the countdown
// skips the wait immediately (same expectation as other buttons in
// the app). 7 seconds total (7-6-5-4-3-2-1, 1 second each) instead of
// the original 3 seconds - a bit more time to read the message above
// before it automatically continues.
constexpr uint32_t COUNTDOWN_STEP_MS = 1000;
constexpr int8_t COUNTDOWN_START = 7;
for (int8_t count = COUNTDOWN_START; count >= 1; count--) {
drawCountdownText(tft, startBtn, String(count));
uint32_t stepStart = millis();
bool skipped = false;
while (millis() - stepStart < COUNTDOWN_STEP_MS) {
TouchInput::Point tap;
if (TouchInput::wasTapped(tap) && startBtn.contains(tap.x, tap.y)) {
skipped = true;
break;
}
MenuStars::update(tft);
delay(20);
}
if (skipped) break;
}
}