tdpro lock screen stage 2 - auto lock settings preferences implemented

This commit is contained in:
pelgraine
2026-03-17 17:42:10 +11:00
parent cd69ea546f
commit 148f8cea4f
4 changed files with 92 additions and 0 deletions

View File

@@ -37,4 +37,5 @@ struct NodePrefs { // persisted to file
uint8_t interference_threshold; // Interference threshold in dB (0=disabled, 14+=enabled)
uint8_t dark_mode; // 0=off (white bg), 1=on (black bg)
uint8_t portrait_mode; // 0=landscape, 1=portrait — T5S3 only
uint8_t auto_lock_minutes; // 0=disabled, 2/5/10/15/30=auto-lock after idle
};

View File

@@ -70,6 +70,24 @@ static inline int findGpsBaudIndex(uint32_t baud) {
return 0;
}
// Auto-lock timeout options (minutes, 0=disabled)
static const uint8_t AUTO_LOCK_OPTIONS[] = { 0, 2, 5, 10, 15, 30 };
#define AUTO_LOCK_OPTION_COUNT 6
static inline const char* autoLockLabel(uint8_t minutes) {
if (minutes == 0) return "None";
static char buf[8];
snprintf(buf, sizeof(buf), "%d min", minutes);
return buf;
}
static inline int findAutoLockIndex(uint8_t minutes) {
for (int i = 0; i < AUTO_LOCK_OPTION_COUNT; i++) {
if (AUTO_LOCK_OPTIONS[i] == minutes) return i;
}
return 0;
}
// ---------------------------------------------------------------------------
// Settings row types
// ---------------------------------------------------------------------------
@@ -86,6 +104,9 @@ enum SettingsRowType : uint8_t {
ROW_DARK_MODE, // Dark mode toggle (inverted display)
#if defined(LilyGo_T5S3_EPaper_Pro)
ROW_PORTRAIT_MODE, // Portrait orientation toggle
#endif
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
ROW_AUTO_LOCK, // Auto-lock timeout picker (None/2/5/10/15/30 min)
#endif
ROW_GPS_BAUD, // GPS baud rate picker (requires reboot)
ROW_PATH_HASH_SIZE, // Path hash size (1, 2, or 3 bytes per hop)
@@ -312,6 +333,9 @@ private:
addRow(ROW_DARK_MODE);
#if defined(LilyGo_T5S3_EPaper_Pro)
addRow(ROW_PORTRAIT_MODE);
#endif
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
addRow(ROW_AUTO_LOCK);
#endif
#ifdef MECK_WIFI_COMPANION
addRow(ROW_WIFI_SETUP);
@@ -873,6 +897,19 @@ public:
break;
#endif
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
case ROW_AUTO_LOCK:
if (editing && _editMode == EDIT_PICKER) {
snprintf(tmp, sizeof(tmp), "< Auto Lock: %s >",
autoLockLabel(AUTO_LOCK_OPTIONS[_editPickerIdx]));
} else {
snprintf(tmp, sizeof(tmp), "Auto Lock: %s",
autoLockLabel(_prefs->auto_lock_minutes));
}
display.print(tmp);
break;
#endif
#ifdef MECK_WIFI_COMPANION
case ROW_WIFI_SETUP:
if (WiFi.status() == WL_CONNECTED) {
@@ -1493,6 +1530,9 @@ public:
} else if (type == ROW_GPS_BAUD) {
_editPickerIdx--;
if (_editPickerIdx < 0) _editPickerIdx = GPS_BAUD_OPTION_COUNT - 1;
} else if (type == ROW_AUTO_LOCK) {
_editPickerIdx--;
if (_editPickerIdx < 0) _editPickerIdx = AUTO_LOCK_OPTION_COUNT - 1;
} else {
// Radio preset
_editPickerIdx--;
@@ -1507,6 +1547,9 @@ public:
} else if (type == ROW_GPS_BAUD) {
_editPickerIdx++;
if (_editPickerIdx >= GPS_BAUD_OPTION_COUNT) _editPickerIdx = 0;
} else if (type == ROW_AUTO_LOCK) {
_editPickerIdx++;
if (_editPickerIdx >= AUTO_LOCK_OPTION_COUNT) _editPickerIdx = 0;
} else {
// Radio preset
_editPickerIdx++;
@@ -1524,6 +1567,12 @@ public:
_editMode = EDIT_NONE;
Serial.printf("Settings: GPS baud set to %lu (reboot to apply)\n",
(unsigned long)_prefs->gps_baudrate);
} else if (type == ROW_AUTO_LOCK) {
_prefs->auto_lock_minutes = AUTO_LOCK_OPTIONS[_editPickerIdx];
the_mesh.savePrefs();
_editMode = EDIT_NONE;
Serial.printf("Settings: Auto lock = %s\n",
autoLockLabel(_prefs->auto_lock_minutes));
} else {
// Apply radio preset
if (_editPickerIdx >= 0 && _editPickerIdx < (int)NUM_RADIO_PRESETS) {
@@ -1719,6 +1768,11 @@ public:
Serial.printf("Settings: Portrait mode = %s\n",
_prefs->portrait_mode ? "ON" : "OFF");
break;
#endif
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
case ROW_AUTO_LOCK:
startEditPicker(findAutoLockIndex(_prefs->auto_lock_minutes));
break;
#endif
#ifdef MECK_WIFI_COMPANION
case ROW_WIFI_SETUP: {

View File

@@ -1164,6 +1164,9 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
ui_started_at = millis();
_alert_expiry = 0;
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
_lastInputMillis = millis();
#endif
splash = new SplashScreen(this);
home = new HomeScreen(this, &rtc_clock, sensors, node_prefs);
@@ -1494,6 +1497,9 @@ void UITask::loop() {
curr->handleInput(c);
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
_next_refresh = 100; // trigger refresh
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
_lastInputMillis = millis(); // Reset auto-lock idle timer
#endif
}
userLedHandler();
@@ -1642,6 +1648,20 @@ if (curr) curr->poll();
#endif
}
// Auto-lock idle timer — runs regardless of display on/off state
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
if (_node_prefs && _node_prefs->auto_lock_minutes > 0 && !_locked) {
uint8_t alm = _node_prefs->auto_lock_minutes;
// Only act on valid option values (guards against garbage from uninitialised prefs)
if (alm == 2 || alm == 5 || alm == 10 || alm == 15 || alm == 30) {
unsigned long lock_timeout = (unsigned long)alm * 60000UL;
if (millis() - _lastInputMillis >= lock_timeout) {
lockScreen();
}
}
}
#endif
#ifdef PIN_VIBRATION
vibration.loop();
#endif
@@ -1683,6 +1703,9 @@ char UITask::checkDisplayOn(char c) {
}
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
_next_refresh = 0; // trigger refresh
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
_lastInputMillis = millis(); // Reset auto-lock idle timer
#endif
}
return c;
}
@@ -1755,6 +1778,10 @@ void UITask::lockScreen() {
_locked = true;
_screenBeforeLock = curr;
setCurrScreen(lock_screen);
// Ensure display is on so lock screen renders (auto-off may have turned it off)
if (_display != NULL && !_display->isOn()) {
_display->turnOn();
}
#if defined(LilyGo_T5S3_EPaper_Pro)
board.setBacklight(false); // Save power (T5S3 backlight)
#endif
@@ -1772,7 +1799,12 @@ void UITask::unlockScreen() {
gotoHomeScreen();
}
_screenBeforeLock = nullptr;
// Ensure display is on so unlocked screen renders
if (_display != NULL && !_display->isOn()) {
_display->turnOn();
}
_auto_off = millis() + AUTO_OFF_MILLIS;
_lastInputMillis = millis(); // Reset auto-lock idle timer
_next_refresh = 0;
Serial.println("[UI] Screen unlocked");
}
@@ -2007,6 +2039,9 @@ void UITask::injectKey(char c) {
}
curr->handleInput(c);
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
#if defined(LilyGo_T5S3_EPaper_Pro) || defined(LilyGo_TDeck_Pro)
_lastInputMillis = millis(); // Reset auto-lock idle timer
#endif
// Debounce refresh when editing UTC offset - e-ink takes 644ms per refresh
// so don't queue another render until the current one could have finished
if (isEditingHomeScreen()) {

View File

@@ -95,6 +95,7 @@ class UITask : public AbstractUITask {
UIScreen* lock_screen; // Lock screen (big clock + battery + unread)
UIScreen* _screenBeforeLock = nullptr;
bool _locked = false;
unsigned long _lastInputMillis = 0; // Auto-lock idle tracking
VirtualKeyboard _vkb;
bool _vkbActive = false;
@@ -104,6 +105,7 @@ class UITask : public AbstractUITask {
UIScreen* lock_screen; // Lock screen (big clock + battery + unread)
UIScreen* _screenBeforeLock = nullptr;
bool _locked = false;
unsigned long _lastInputMillis = 0; // Auto-lock idle tracking
#endif
void userLedHandler();