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>
93 lines
3.1 KiB
C++
93 lines
3.1 KiB
C++
#include "brightness_screen.h"
|
|
#include "settings_store.h"
|
|
#include "touch_input.h"
|
|
#include "menu_stars.h"
|
|
#include "config.h"
|
|
#include "i18n.h"
|
|
|
|
namespace BrightnessScreen {
|
|
|
|
namespace {
|
|
struct Rect {
|
|
int16_t x, y, w, h;
|
|
bool contains(int16_t px, int16_t py) const {
|
|
return px >= x && px < x + w && py >= y && py < y + h;
|
|
}
|
|
};
|
|
|
|
void drawButton(TFT_eSPI& tft, const Rect& r, const String& label) {
|
|
tft.fillRoundRect(r.x, r.y, r.w, r.h, 4, TFT_BLACK);
|
|
tft.drawRoundRect(r.x, r.y, r.w, r.h, 4, TFT_GREEN);
|
|
tft.setTextDatum(MC_DATUM);
|
|
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
|
tft.drawString(label, r.x + r.w / 2, r.y + r.h / 2);
|
|
tft.setTextDatum(TL_DATUM);
|
|
}
|
|
|
|
// Gleicher PWM-Kanal wie in main.cpp (dort in setup() mit ledcSetup()
|
|
// initialisiert) - hier bewusst als eigene Konstante dupliziert statt
|
|
// geteilt, siehe CLAUDE.md-Konvention ("jeder Screen unabhaengig").
|
|
constexpr uint8_t BACKLIGHT_PWM_CHANNEL = 0;
|
|
|
|
void applyLive(uint8_t percent) {
|
|
uint8_t pwm = (uint8_t)((uint16_t)percent * 255 / 100);
|
|
ledcWrite(BACKLIGHT_PWM_CHANNEL, pwm);
|
|
}
|
|
}
|
|
|
|
void run(TFT_eSPI& tft) {
|
|
bool done = false;
|
|
MenuStars::reset();
|
|
|
|
while (!done) {
|
|
uint8_t percent = SettingsStore::brightnessPercent();
|
|
|
|
tft.fillScreen(TFT_BLACK);
|
|
tft.setTextColor(TFT_GREEN, TFT_BLACK);
|
|
tft.setCursor(10, 14);
|
|
tft.println(I18n::t(StringId::BRIGHTNESS_TITLE));
|
|
|
|
char buf[8];
|
|
snprintf(buf, sizeof(buf), "%d%%", percent);
|
|
tft.setTextDatum(MC_DATUM);
|
|
tft.setTextSize(3);
|
|
tft.drawString(buf, Config::SCREEN_WIDTH / 2, 130);
|
|
tft.setTextSize(1);
|
|
tft.setTextDatum(TL_DATUM);
|
|
|
|
Rect minusBtn = {10, 190, 100, 60};
|
|
Rect plusBtn = {(int16_t)(Config::SCREEN_WIDTH - 110), 190, 100, 60};
|
|
drawButton(tft, minusBtn, "-");
|
|
drawButton(tft, plusBtn, "+");
|
|
|
|
Rect backBtn = {10, (int16_t)(Config::SCREEN_HEIGHT - 50),
|
|
(int16_t)(Config::SCREEN_WIDTH - 20), 40};
|
|
drawButton(tft, backBtn, I18n::t(StringId::BACK));
|
|
|
|
TouchInput::Point tap;
|
|
while (true) {
|
|
if (TouchInput::wasTapped(tap)) break;
|
|
MenuStars::update(tft);
|
|
delay(20);
|
|
}
|
|
|
|
if (minusBtn.contains(tap.x, tap.y)) {
|
|
uint8_t next = (percent > Config::BRIGHTNESS_MIN_PERCENT + Config::BRIGHTNESS_STEP_PERCENT - 1)
|
|
? (uint8_t)(percent - Config::BRIGHTNESS_STEP_PERCENT)
|
|
: Config::BRIGHTNESS_MIN_PERCENT;
|
|
SettingsStore::setBrightnessPercent(next);
|
|
applyLive(next);
|
|
} else if (plusBtn.contains(tap.x, tap.y)) {
|
|
uint8_t next = (percent + Config::BRIGHTNESS_STEP_PERCENT <= Config::BRIGHTNESS_MAX_PERCENT)
|
|
? (uint8_t)(percent + Config::BRIGHTNESS_STEP_PERCENT)
|
|
: Config::BRIGHTNESS_MAX_PERCENT;
|
|
SettingsStore::setBrightnessPercent(next);
|
|
applyLive(next);
|
|
} else if (backBtn.contains(tap.x, tap.y)) {
|
|
done = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|