feat: add 12h/24h clock format setting (default 24h)

Toggle in Settings > Display > Format. In 12h mode the clock shows
h:mm AM/PM (or h:mm:ss AM/PM with seconds, no space before AM/PM).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-21 21:04:43 +02:00
parent e0312c2b6b
commit 38cd0fada3
4 changed files with 31 additions and 5 deletions

View File

@@ -285,6 +285,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
file.read((uint8_t *)_prefs.dm_melody, sizeof(_prefs.dm_melody));
if (file.available()) {
file.read((uint8_t *)&_prefs.auto_lock, sizeof(_prefs.auto_lock));
if (file.available()) {
file.read((uint8_t *)&_prefs.clock_12h, sizeof(_prefs.clock_12h));
}
}
}
}
@@ -375,6 +378,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.ch_notif_melody_2, sizeof(_prefs.ch_notif_melody_2));
file.write((uint8_t *)_prefs.dm_melody, sizeof(_prefs.dm_melody));
file.write((uint8_t *)&_prefs.auto_lock, sizeof(_prefs.auto_lock));
file.write((uint8_t *)&_prefs.clock_12h, sizeof(_prefs.clock_12h));
file.close();
}

View File

@@ -57,6 +57,7 @@ struct NodePrefs { // persisted to file
char bot_reply_dm[140]; // auto-reply text for DM
char bot_reply_ch[140]; // auto-reply text for channel
uint8_t clock_hide_seconds; // 0=show HH:MM:SS/refresh 1s (default), 1=hide/refresh 60s
uint8_t clock_12h; // 0=24h (default), 1=12h with AM/PM
uint8_t buzzer_auto; // 0=manual (default), 1=auto-mute when BT connected
struct DmNotifEntry { uint8_t prefix[4]; uint8_t state; }; // state: 0=default,1=muted,2=force-on
static const int DM_NOTIF_TABLE_MAX = 16;

View File

@@ -13,6 +13,7 @@ class SettingsScreen : public UIScreen {
AUTO_LOCK,
BATT_DISPLAY,
CLOCK_SECONDS,
CLOCK_FORMAT,
// Sound section
SECTION_SOUND,
BUZZER,
@@ -311,6 +312,10 @@ class SettingsScreen : public UIScreen {
display.print("Seconds");
display.setCursor(VAL_X, y);
display.print((p && p->clock_hide_seconds) ? "OFF" : "ON");
} else if (item == CLOCK_FORMAT) {
display.print("Format");
display.setCursor(VAL_X, y);
display.print((p && p->clock_12h) ? "12h" : "24h");
} else if (item == DM_FILTER) {
display.print("DM");
display.setCursor(VAL_X, y);
@@ -496,6 +501,11 @@ public:
_dirty = true;
return true;
}
if (_selected == CLOCK_FORMAT && p && (left || right || enter)) {
p->clock_12h ^= 1;
_dirty = true;
return true;
}
if (_selected == DM_FILTER && p && (left || right || enter)) {
p->dm_show_all = p->dm_show_all ? 0 : 1;
_dirty = true;

View File

@@ -389,10 +389,16 @@ public:
display.setColor(DisplayDriver::LIGHT);
display.setTextSize(2);
bool show_sec = !_node_prefs || !_node_prefs->clock_hide_seconds;
if (show_sec)
sprintf(buf, "%02d:%02d:%02d", ti->tm_hour, ti->tm_min, ti->tm_sec);
else
sprintf(buf, "%02d:%02d", ti->tm_hour, ti->tm_min);
bool h12 = _node_prefs && _node_prefs->clock_12h;
if (h12) {
int h = ti->tm_hour % 12; if (h == 0) h = 12;
const char* ap = ti->tm_hour < 12 ? "AM" : "PM";
if (show_sec) sprintf(buf, "%d:%02d:%02d%s", h, ti->tm_min, ti->tm_sec, ap);
else sprintf(buf, "%d:%02d %s", h, ti->tm_min, ap);
} else {
if (show_sec) sprintf(buf, "%02d:%02d:%02d", ti->tm_hour, ti->tm_min, ti->tm_sec);
else sprintf(buf, "%02d:%02d", ti->tm_hour, ti->tm_min);
}
display.drawTextCentered(display.width() / 2, 0, buf);
display.setTextSize(1);
@@ -1334,7 +1340,12 @@ void UITask::loop() {
struct tm* ti = gmtime(&t);
char buf[12];
_display->setTextSize(2);
sprintf(buf, "%02d:%02d", ti->tm_hour, ti->tm_min);
if (_node_prefs && _node_prefs->clock_12h) {
int h = ti->tm_hour % 12; if (h == 0) h = 12;
sprintf(buf, "%d:%02d %s", h, ti->tm_min, ti->tm_hour < 12 ? "AM" : "PM");
} else {
sprintf(buf, "%02d:%02d", ti->tm_hour, ti->tm_min);
}
_display->drawTextCentered(_display->width() / 2, 8, buf);
_display->setTextSize(1);
static const char* wd[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};