mirror of
https://github.com/pelgraine/Meck.git
synced 2026-06-11 00:34:50 +02:00
Max - fix missing -D HAS_4G_MODEM=1 flags. Revised settingscreen so it uses a scroll bar instead of the heading total counter. New brightness scale in settings to control heart button brightness toggle strength, which also persists after reboot.
This commit is contained in:
@@ -197,6 +197,11 @@ void DataStore::loadPrefs(NodePrefs& prefs, double& node_lat, double& node_lon)
|
||||
savePrefs(prefs, node_lat, node_lon); // save to new filename
|
||||
_fs->remove("/node_prefs"); // remove old
|
||||
}
|
||||
// Fresh device (no prefs file) leaves backlight at memset 0; treat any
|
||||
// out-of-range value as the default so the heart button has a sane level.
|
||||
if (prefs.backlight_brightness_pct < 5 || prefs.backlight_brightness_pct > 100) {
|
||||
prefs.backlight_brightness_pct = 100;
|
||||
}
|
||||
}
|
||||
|
||||
void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& node_lat, double& node_lon) {
|
||||
@@ -295,6 +300,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
|
||||
if (file.read((uint8_t *)&_prefs.lora_antenna, sizeof(_prefs.lora_antenna)) != sizeof(_prefs.lora_antenna)) {
|
||||
_prefs.lora_antenna = 0; // default: internal antenna
|
||||
}
|
||||
if (file.read((uint8_t *)&_prefs.backlight_brightness_pct, sizeof(_prefs.backlight_brightness_pct)) != sizeof(_prefs.backlight_brightness_pct)) {
|
||||
_prefs.backlight_brightness_pct = 100; // default: full brightness
|
||||
}
|
||||
|
||||
// Clamp to valid ranges
|
||||
if (_prefs.dark_mode > 1) _prefs.dark_mode = 0;
|
||||
@@ -309,6 +317,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
|
||||
if (_prefs.channel_notif[i] > 2) _prefs.channel_notif[i] = 0;
|
||||
}
|
||||
if (_prefs.lora_antenna > 1) _prefs.lora_antenna = 0;
|
||||
if (_prefs.backlight_brightness_pct < 5 || _prefs.backlight_brightness_pct > 100) _prefs.backlight_brightness_pct = 100;
|
||||
// auto_lock_minutes: only accept known options (0, 2, 5, 10, 15, 30)
|
||||
{
|
||||
uint8_t alm = _prefs.auto_lock_minutes;
|
||||
@@ -370,6 +379,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
|
||||
file.write((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 137
|
||||
file.write((uint8_t *)_prefs.channel_notif, sizeof(_prefs.channel_notif)); // 153
|
||||
file.write((uint8_t *)&_prefs.lora_antenna, sizeof(_prefs.lora_antenna)); // 174
|
||||
file.write((uint8_t *)&_prefs.backlight_brightness_pct, sizeof(_prefs.backlight_brightness_pct)); // 175
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -69,6 +69,11 @@ struct NodePrefs { // persisted to file
|
||||
// Applied at boot in main.cpp and live on toggle in SettingsScreen.
|
||||
uint8_t lora_antenna; // 0 = internal (default), 1 = external
|
||||
|
||||
// --- Backlight (e-ink frontlight) brightness, T-Deck Pro MAX only ---
|
||||
// Percentage (5..100) the heart button toggles the frontlight on to.
|
||||
// 0 = unset/legacy; treated as the default 100 on load.
|
||||
uint8_t backlight_brightness_pct; // 5..100, default 100
|
||||
|
||||
// --- Font helpers (inline, no overhead) ---
|
||||
// Returns the DisplayDriver text-size index for "small/body" text.
|
||||
// T-Deck Pro: 0 = built-in 6×8 (or 7pt with custom fonts), 1 = 9pt.
|
||||
|
||||
@@ -1237,9 +1237,13 @@ static void lastHeardToggleContact() {
|
||||
Serial.printf("[key] id=%u pressed=%u\n", key_id, pressed ? 1u : 0u); // TEMP: confirm mapping
|
||||
if (!pressed) return;
|
||||
switch (key_id) {
|
||||
case 0: // heart -- toggle frontlight at full brightness
|
||||
if (board.isBacklightOn()) board.backlightOff();
|
||||
else board.backlightSetBrightness(255);
|
||||
case 0: // heart -- toggle frontlight at the user-set brightness
|
||||
if (board.isBacklightOn()) {
|
||||
board.backlightOff();
|
||||
} else {
|
||||
uint8_t _blPct = the_mesh.getNodePrefs()->backlight_brightness_pct;
|
||||
board.backlightSetBrightness((uint8_t)((_blPct * 255 + 50) / 100));
|
||||
}
|
||||
break;
|
||||
case 1: // speech bubble -- open channel picker (same as 'M')
|
||||
ui_task.gotoChannelPickerScreen();
|
||||
@@ -4170,7 +4174,10 @@ void loop() {
|
||||
lastTouchAccepted = now;
|
||||
if (smsScr->handleTouch(tx, ty)) {
|
||||
dialerNeedsRefresh = true;
|
||||
lastDialerRefresh = millis();
|
||||
// Don't reset the gate on touch: COMPOSE_REFRESH_INTERVAL is
|
||||
// measured from the last completed render (set at the render
|
||||
// site), so the first tap after a pause repaints immediately and
|
||||
// only rapid successive taps stay throttled (no overlap).
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -140,6 +140,7 @@ enum SettingsRowType : uint8_t {
|
||||
ROW_CR, // Coding rate (5-8)
|
||||
ROW_TX_POWER, // TX power (1-20 dBm)
|
||||
ROW_UTC_OFFSET, // UTC offset (-12 to +14)
|
||||
ROW_BACKLIGHT_BRIGHTNESS, // Backlight brightness % the heart button toggles to (MAX only)
|
||||
ROW_MSG_NOTIFY, // Keyboard flash on new msg toggle
|
||||
ROW_DARK_MODE, // Dark mode toggle (inverted display)
|
||||
ROW_LARGE_FONT, // Font size toggle: 0=tiny (default), 1=larger
|
||||
@@ -490,6 +491,9 @@ private:
|
||||
addRow(ROW_CR);
|
||||
addRow(ROW_TX_POWER);
|
||||
addRow(ROW_UTC_OFFSET);
|
||||
#if defined(LilyGo_TDeck_Pro_Max)
|
||||
addRow(ROW_BACKLIGHT_BRIGHTNESS);
|
||||
#endif
|
||||
addRow(ROW_MSG_NOTIFY);
|
||||
#if HAS_GPS
|
||||
addRow(ROW_GPS_BAUD);
|
||||
@@ -1751,10 +1755,7 @@ public:
|
||||
display.print("Settings");
|
||||
}
|
||||
|
||||
// Right side: row indicator
|
||||
snprintf(tmp, sizeof(tmp), "%d/%d", _cursor + 1, _numRows);
|
||||
display.setCursor(display.width() - display.getTextWidth(tmp) - 2, 0);
|
||||
display.print(tmp);
|
||||
// (Row indicator is now a scrollbar on the right of the list body.)
|
||||
|
||||
display.drawRect(0, 11, display.width(), 1);
|
||||
|
||||
@@ -1771,6 +1772,12 @@ public:
|
||||
_scrollTop = max(0, min(_cursor - maxVisible / 2, _numRows - maxVisible));
|
||||
int endIdx = min(_numRows, _scrollTop + maxVisible);
|
||||
|
||||
// Scrollbar: always shown on the top-level list; on sub-screens only when
|
||||
// the rows overflow the page. When shown, reserve a few px on the right so
|
||||
// the selection highlight isn't painted under it.
|
||||
bool showScrollbar = (_subScreen == SUB_NONE) || (_numRows > maxVisible);
|
||||
int sbW = showScrollbar ? 6 : 0;
|
||||
|
||||
int y = headerH;
|
||||
|
||||
for (int i = _scrollTop; i < endIdx && y + lineHeight <= maxY; i++) {
|
||||
@@ -1783,9 +1790,9 @@ public:
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
// FreeSans12pt: baseline at (y+5)*scale_y, ascent ~17px above.
|
||||
// Highlight needs to start above the baseline to cover ascenders.
|
||||
display.fillRect(0, y, display.width(), lineHeight);
|
||||
display.fillRect(0, y, display.width() - sbW, lineHeight);
|
||||
#else
|
||||
display.fillRect(0, y + _prefs->smallHighlightOff(), display.width(), lineHeight);
|
||||
display.fillRect(0, y + _prefs->smallHighlightOff(), display.width() - sbW, lineHeight);
|
||||
#endif
|
||||
display.setColor(DisplayDriver::DARK);
|
||||
} else {
|
||||
@@ -1877,6 +1884,15 @@ public:
|
||||
display.print(tmp);
|
||||
break;
|
||||
|
||||
case ROW_BACKLIGHT_BRIGHTNESS:
|
||||
if (editing && _editMode == EDIT_NUMBER) {
|
||||
snprintf(tmp, sizeof(tmp), "Brightness: %d%% " EDIT_ADJ_HINT, _editInt);
|
||||
} else {
|
||||
snprintf(tmp, sizeof(tmp), "Backlight Brightness: %d%%", _prefs->backlight_brightness_pct);
|
||||
}
|
||||
display.print(tmp);
|
||||
break;
|
||||
|
||||
case ROW_MSG_NOTIFY:
|
||||
snprintf(tmp, sizeof(tmp), "Msg LED Flash: %s",
|
||||
_prefs->kb_flash_notify ? "ON" : "OFF");
|
||||
@@ -2260,6 +2276,21 @@ public:
|
||||
y += lineHeight;
|
||||
}
|
||||
|
||||
// Scrollbar (track + proportional thumb), mirroring the notif-sound picker.
|
||||
if (showScrollbar) {
|
||||
int sbX = display.width() - 6;
|
||||
int sbTop = headerH;
|
||||
int sbH = maxY - headerH;
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.drawRect(sbX, sbTop, 3, sbH);
|
||||
int thumbH = max(4, (maxVisible * sbH) / _numRows);
|
||||
if (thumbH > sbH) thumbH = sbH;
|
||||
int maxScroll = _numRows - maxVisible;
|
||||
if (maxScroll < 1) maxScroll = 1;
|
||||
int thumbY = sbTop + (_scrollTop * (sbH - thumbH)) / maxScroll;
|
||||
display.fillRect(sbX + 1, thumbY + 1, 1, thumbH - 2);
|
||||
}
|
||||
|
||||
display.setTextSize(1);
|
||||
|
||||
// === Confirmation overlay ===
|
||||
@@ -3384,6 +3415,7 @@ public:
|
||||
case ROW_CR: if (_editInt < 8) _editInt++; break;
|
||||
case ROW_TX_POWER: if (_editInt < MAX_LORA_TX_POWER) _editInt++; break;
|
||||
case ROW_UTC_OFFSET: if (_editInt < 14) _editInt++; break;
|
||||
case ROW_BACKLIGHT_BRIGHTNESS: if (_editInt < 100) { _editInt += 5; if (_editInt > 100) _editInt = 100; } break;
|
||||
case ROW_PATH_HASH_SIZE: if (_editInt < 3) _editInt++; break;
|
||||
default: break;
|
||||
}
|
||||
@@ -3401,6 +3433,7 @@ public:
|
||||
case ROW_CR: if (_editInt > 5) _editInt--; break;
|
||||
case ROW_TX_POWER: if (_editInt > 1) _editInt--; break;
|
||||
case ROW_UTC_OFFSET: if (_editInt > -12) _editInt--; break;
|
||||
case ROW_BACKLIGHT_BRIGHTNESS: if (_editInt > 5) { _editInt -= 5; if (_editInt < 5) _editInt = 5; } break;
|
||||
case ROW_PATH_HASH_SIZE: if (_editInt > 1) _editInt--; break;
|
||||
default: break;
|
||||
}
|
||||
@@ -3429,6 +3462,10 @@ public:
|
||||
_prefs->utc_offset_hours = (int8_t)constrain(_editInt, -12, 14);
|
||||
the_mesh.savePrefs();
|
||||
break;
|
||||
case ROW_BACKLIGHT_BRIGHTNESS:
|
||||
_prefs->backlight_brightness_pct = (uint8_t)constrain(_editInt, 5, 100);
|
||||
the_mesh.savePrefs();
|
||||
break;
|
||||
case ROW_PATH_HASH_SIZE:
|
||||
_prefs->path_hash_mode = (uint8_t)constrain(_editInt - 1, 0, 2); // display 1-3, store 0-2
|
||||
the_mesh.savePrefs();
|
||||
@@ -3515,6 +3552,9 @@ public:
|
||||
case ROW_UTC_OFFSET:
|
||||
startEditInt(_prefs->utc_offset_hours);
|
||||
break;
|
||||
case ROW_BACKLIGHT_BRIGHTNESS:
|
||||
startEditInt(_prefs->backlight_brightness_pct);
|
||||
break;
|
||||
case ROW_MSG_NOTIFY:
|
||||
_prefs->kb_flash_notify = _prefs->kb_flash_notify ? 0 : 1;
|
||||
the_mesh.savePrefs();
|
||||
|
||||
@@ -717,7 +717,7 @@ public:
|
||||
display.setColor(DisplayDriver::YELLOW);
|
||||
display.drawTextCentered(display.width() / 2, y, "[R] Trace [J] Games ");
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
y += 14;
|
||||
y += 10;
|
||||
#if defined(HAS_4G_MODEM) && defined(MECK_AUDIO_VARIANT)
|
||||
// Phone on its own line below Trace/Games, centered like the "Press:" header
|
||||
display.drawTextCentered(display.width() / 2, y, "[T] Phone");
|
||||
|
||||
@@ -206,6 +206,7 @@ build_flags =
|
||||
-D OFFLINE_QUEUE_SIZE=256
|
||||
-D MECK_WEB_READER=1
|
||||
-D MECK_OTA_UPDATE=1
|
||||
-D HAS_4G_MODEM=1
|
||||
-D FIRMWARE_VERSION='"Meck v1.11.MAX.WiFi"'
|
||||
build_src_filter = ${LilyGo_TDeck_Pro_Max.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
@@ -220,7 +221,7 @@ lib_deps =
|
||||
bitbank2/PNGdec
|
||||
|
||||
; MAX standalone (no BLE/WiFi — maximum battery life, LoRa mesh only)
|
||||
; Contacts in PSRAM (1500 capacity). OTA enabled (WiFi AP on demand).
|
||||
; Contacts in PSRAM (2000 capacity). OTA enabled (WiFi AP on demand).
|
||||
[env:meck_max_standalone]
|
||||
extends = LilyGo_TDeck_Pro_Max
|
||||
build_flags =
|
||||
@@ -230,6 +231,8 @@ build_flags =
|
||||
-D MAX_GROUP_CHANNELS=40
|
||||
-D OFFLINE_QUEUE_SIZE=1
|
||||
-D MECK_OTA_UPDATE=1
|
||||
-D HAS_4G_MODEM=1
|
||||
-D MECK_WEB_READER=1
|
||||
-D FIRMWARE_VERSION='"Meck v1.11.MAX.SA"'
|
||||
build_src_filter = ${LilyGo_TDeck_Pro_Max.build_src_filter}
|
||||
+<helpers/esp32/*.cpp>
|
||||
@@ -239,5 +242,6 @@ build_src_filter = ${LilyGo_TDeck_Pro_Max.build_src_filter}
|
||||
+<helpers/ui/GxEPDDisplay.cpp>
|
||||
lib_deps =
|
||||
${LilyGo_TDeck_Pro_Max.lib_deps}
|
||||
bitbank2/PNGdec
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
densaugeo/base64 @ ~1.4.0
|
||||
bitbank2/JPEGDEC
|
||||
bitbank2/PNGdec
|
||||
Reference in New Issue
Block a user