Compare commits

...

3 Commits

9 changed files with 292 additions and 43 deletions
+8
View File
@@ -289,6 +289,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
if (file.read((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)) != sizeof(_prefs.default_scope_key)) {
memset(_prefs.default_scope_key, 0, sizeof(_prefs.default_scope_key));
}
if (file.read((uint8_t *)_prefs.channel_notif, sizeof(_prefs.channel_notif)) != sizeof(_prefs.channel_notif)) {
memset(_prefs.channel_notif, 0, sizeof(_prefs.channel_notif)); // default: NOTIF_ALL
}
// Clamp to valid ranges
if (_prefs.dark_mode > 1) _prefs.dark_mode = 0;
@@ -298,6 +301,10 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
if (_prefs.ui_font_style > 2) _prefs.ui_font_style = 0;
if (_prefs.tx_fail_reset_threshold > 10) _prefs.tx_fail_reset_threshold = 3;
if (_prefs.rx_fail_reboot_threshold > 10) _prefs.rx_fail_reboot_threshold = 3;
// Clamp channel notification preferences to valid range
for (int i = 0; i < (int)sizeof(_prefs.channel_notif); i++) {
if (_prefs.channel_notif[i] > 2) _prefs.channel_notif[i] = 0;
}
// auto_lock_minutes: only accept known options (0, 2, 5, 10, 15, 30)
{
uint8_t alm = _prefs.auto_lock_minutes;
@@ -357,6 +364,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.ui_font_style, sizeof(_prefs.ui_font_style)); // 105
file.write((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 106
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.close();
}
+2 -2
View File
@@ -8,11 +8,11 @@
#define FIRMWARE_VER_CODE 11
#ifndef FIRMWARE_BUILD_DATE
#define FIRMWARE_BUILD_DATE "7 May 2026"
#define FIRMWARE_BUILD_DATE "12 May 2026"
#endif
#ifndef FIRMWARE_VERSION
#define FIRMWARE_VERSION "Meck v1.9"
#define FIRMWARE_VERSION "Meck v1.10"
#endif
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
+11
View File
@@ -8,6 +8,11 @@
#define ADVERT_LOC_NONE 0
#define ADVERT_LOC_SHARE 1
// Per-channel notification preferences (stored in channel_notif[])
#define NOTIF_ALL 0 // Notify on all messages (default)
#define NOTIF_MENTIONS 1 // Notify only when @nodename appears in message
#define NOTIF_NONE 2 // No notifications (muted)
struct NodePrefs { // persisted to file
float airtime_factor;
char node_name[32];
@@ -53,6 +58,12 @@ struct NodePrefs { // persisted to file
char default_scope_name[31]; // e.g. "au-nsw", empty = unscoped
uint8_t default_scope_key[16]; // TransportKey derived from "#" + name
// --- Per-channel notification preferences ---
// Index 0..MAX_GROUP_CHANNELS-1 for group channels, index MAX_GROUP_CHANNELS for DMs.
// Values: NOTIF_ALL (0), NOTIF_MENTIONS (1), NOTIF_NONE (2).
// Defaults to NOTIF_ALL for all channels.
uint8_t channel_notif[21]; // 20 group channels + 1 DM slot
// --- 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.
+5
View File
@@ -1751,6 +1751,11 @@ static void lastHeardToggleContact() {
return KEY_ENTER; // Not editing: toggle/edit selected row
}
// Channel picker: long press = delete message history for highlighted channel
if (ui_task.isOnChannelPickerScreen()) {
return 'x';
}
// Default: enter/select
return KEY_ENTER;
}
@@ -148,8 +148,10 @@ public:
// Add a new message to the history
// peer_name: for DMs, the contact this message belongs to (sender for received, recipient for sent)
// suppressUnread: if true, do not increment the unread counter for this message
void addMessage(uint8_t channel_idx, uint8_t path_len, const char* sender, const char* text,
const uint8_t* path_bytes = nullptr, int8_t snr = 0, const char* peer_name = nullptr) {
const uint8_t* path_bytes = nullptr, int8_t snr = 0, const char* peer_name = nullptr,
bool suppressUnread = false) {
// Move to next slot in circular buffer
_newestIdx = (_newestIdx + 1) % CHANNEL_MSG_HISTORY_SIZE;
@@ -191,8 +193,9 @@ public:
_replySelectPos = -1;
// Track unread count for this channel (only for received messages, not sent)
// path_len == 0 means locally sent
if (path_len != 0) {
// path_len == 0 means locally sent.
// suppressUnread: per-channel notification preference says not to count this message.
if (path_len != 0 && !suppressUnread) {
int unreadSlot = (channel_idx == 0xFF) ? MAX_GROUP_CHANNELS : channel_idx;
if (unreadSlot >= 0 && unreadSlot <= MAX_GROUP_CHANNELS) {
_unread[unreadSlot]++;
@@ -397,6 +400,42 @@ public:
return pos;
}
// -----------------------------------------------------------------------
// Per-channel history deletion
// -----------------------------------------------------------------------
// Clear all stored messages for a specific channel (or all DMs if 0xFF).
// Invalidates matching slots in the circular buffer and persists to SD.
// Does NOT alter _newestIdx -- gaps are naturally overwritten as new
// messages arrive.
int clearHistoryForChannel(uint8_t channel_idx) {
int cleared = 0;
for (int i = 0; i < CHANNEL_MSG_HISTORY_SIZE; i++) {
if (_messages[i].valid && _messages[i].channel_idx == channel_idx) {
_messages[i].valid = false;
cleared++;
}
}
if (cleared > 0) {
// Reset unread counter for the cleared channel
markChannelRead(channel_idx);
// Reset scroll if we're viewing the cleared channel
if (_viewChannelIdx == channel_idx) {
_scrollPos = 0;
}
// Reset DM inbox state if clearing DMs
if (channel_idx == 0xFF) {
_dmInboxScroll = 0;
_dmFilterName[0] = '\0';
_dmInboxMode = true;
}
saveToSD();
Serial.printf("ChannelScreen: Cleared %d messages for channel %d\n",
cleared, (int)channel_idx);
}
return cleared;
}
// -----------------------------------------------------------------------
// SD card persistence
// -----------------------------------------------------------------------
@@ -32,7 +32,13 @@ extern MyMesh the_mesh;
// T-Deck Pro / MAX : vertical list with "> " cursor, unread badge, right-
// aligned. Same highlight/tap convention as Contacts.
//
// Navigation signals use a wantsExit() flag (same pattern as PathEditor) —
// Delete history:
// Press X on a highlighted channel to enter delete confirmation mode.
// Confirmation overlay asks the user to press Enter to confirm or Q to
// cancel. On confirm, all messages for that channel are invalidated in
// the circular buffer and persisted to SD.
//
// Navigation signals use a wantsExit() flag (same pattern as PathEditor) --
// UITask is only forward-declared, so the picker cannot call UITask methods
// directly. main.cpp / UITask.cpp check the flag after injectKey().
// ---------------------------------------------------------------------------
@@ -50,12 +56,15 @@ class ChannelPickerScreen : public UIScreen {
int _cursor;
int _scrollTop; // Scroll offset (T-Deck Pro list only)
// Grid layout cache (T5S3) set in render(), consumed by touch hit test
// Grid layout cache (T5S3) -- set in render(), consumed by touch hit test
int _cellW;
int _cellH;
int _gridTop;
int _gridCols;
// Delete confirmation sub-menu
bool _confirmDelete; // True when showing "Delete history?" overlay
// Rebuild the items list from MyMesh. O(20), safe every render.
void rebuildItems() {
int n = 0;
@@ -100,13 +109,14 @@ public:
: _task(task), _channelScreen(nullptr),
_itemCount(0), _cursor(0), _scrollTop(0),
_cellW(40), _cellH(12), _gridTop(14), _gridCols(3),
_confirmDelete(false),
_wantExit(false) {
_items[0] = 0xFF;
}
void setChannelScreen(ChannelScreen* cs) { _channelScreen = cs; }
// --- wantsExit flag checked by main.cpp / UITask after injectKey() ---
// --- wantsExit flag -- checked by main.cpp / UITask after injectKey() ---
bool _wantExit;
bool wantsExit() const { return _wantExit; }
@@ -118,6 +128,7 @@ public:
if (_items[i] == currentChannelIdx) { _cursor = i; break; }
}
_scrollTop = 0;
_confirmDelete = false;
_wantExit = false;
}
@@ -171,7 +182,7 @@ public:
_cellW = bubbleW;
_cellH = bubbleH + gap;
_gridTop = headerH;
_gridCols = 1; // Single column list mode
_gridCols = 1; // Single column -- list mode
// Centre scroll window on cursor
_scrollTop = max(0, min(_cursor - maxVisible / 2, _itemCount - maxVisible));
@@ -200,7 +211,7 @@ public:
display.drawRect(x + 1, y + 1, w - 2, h - 2);
}
// Channel name left-aligned with inner padding
// Channel name -- left-aligned with inner padding
char name[32];
getItemName(i, name, sizeof(name));
char filtered[32];
@@ -229,7 +240,7 @@ public:
display.drawTextEllipsized(textX, textY, nameMaxW, filtered);
}
// Unread badge right-aligned inside bubble
// Unread badge -- right-aligned inside bubble
if (unread > 0) {
int bx = x + w - badgeW;
display.setCursor(bx, textY);
@@ -329,6 +340,47 @@ public:
}
#endif
// =================================================================
// Delete confirmation overlay
// Drawn on top of the list when _confirmDelete is active.
// =================================================================
if (_confirmDelete) {
// Clear a centred box and draw a border
int boxW = display.width() - 16;
int boxH = 42;
int boxX = 8;
int boxY = (display.height() - boxH) / 2;
// Clear the box area
display.setColor(DisplayDriver::DARK);
display.fillRect(boxX, boxY, boxW, boxH);
display.setColor(DisplayDriver::LIGHT);
display.drawRect(boxX, boxY, boxW, boxH);
display.drawRect(boxX + 1, boxY + 1, boxW - 2, boxH - 2);
// Channel name
display.setTextSize(1);
char name[32];
getItemName(_cursor, name, sizeof(name));
char filtered[32];
display.translateUTF8ToBlocks(filtered, name, sizeof(filtered));
display.setColor(DisplayDriver::GREEN);
display.drawTextEllipsized(boxX + 4, boxY + 5, boxW - 8, filtered);
// "Delete history?" prompt
display.setColor(DisplayDriver::LIGHT);
const char* prompt = "Delete message history?";
display.setCursor(boxX + 4, boxY + 17);
display.print(prompt);
// Key hints
display.setColor(DisplayDriver::YELLOW);
const char* hints = "Enter:Yes Q:Cancel";
display.setCursor(boxX + 4, boxY + 29);
display.print(hints);
}
// === Footer ===
display.setTextSize(1);
int footerY = display.height() - 12;
@@ -337,20 +389,31 @@ public:
display.setCursor(0, footerY);
#if defined(LilyGo_T5S3_EPaper_Pro)
display.print("Tap:Open");
const char* rt = "Boot:Back";
display.setCursor(display.width() - display.getTextWidth(rt) - 2, footerY);
display.print(rt);
if (_confirmDelete) {
display.print("Tap:Yes");
const char* rt = "Boot:Cancel";
display.setCursor(display.width() - display.getTextWidth(rt) - 2, footerY);
display.print(rt);
} else {
display.print("Tap:Open");
const char* rt = "Hold:Del Boot:Back";
display.setCursor(display.width() - display.getTextWidth(rt) - 2, footerY);
display.print(rt);
}
#elif defined(LILYGO_TECHO_LITE)
display.print("Q:Bk");
const char* rt = "Ent:Open";
display.setCursor(display.width() - display.getTextWidth(rt) - 2, footerY);
display.print(rt);
#else
display.print("W/S:Nav Q:Back");
const char* rt = "Ent:Open";
display.setCursor(display.width() - display.getTextWidth(rt) - 2, footerY);
display.print(rt);
if (_confirmDelete) {
display.print("Enter:Yes Q:Cancel");
} else {
display.print("W/S:Nav Q:Back");
const char* rt = "Ent:Open";
display.setCursor(display.width() - display.getTextWidth(rt) - 2, footerY);
display.print(rt);
}
#endif
#ifdef USE_EINK
@@ -364,6 +427,30 @@ public:
// Input
// -----------------------------------------------------------------------
bool handleInput(char c) override {
// --- Delete confirmation mode ---
if (_confirmDelete) {
// Enter -- confirm deletion
if (c == '\r' || c == 13 || c == KEY_ENTER || c == KEY_SELECT) {
if (_channelScreen && _cursor >= 0 && _cursor < _itemCount) {
int cleared = _channelScreen->clearHistoryForChannel(_items[_cursor]);
char name[32];
getItemName(_cursor, name, sizeof(name));
Serial.printf("ChannelPicker: Deleted %d messages for '%s'\n", cleared, name);
}
_confirmDelete = false;
return true;
}
// Q / backspace -- cancel
if (c == 'q' || c == 'Q' || c == '\b' || c == KEY_CANCEL) {
_confirmDelete = false;
return true;
}
// Consume all other keys while confirmation is showing
return true;
}
// --- Normal picker mode ---
// W / UP
if (c == 'w' || c == 'W' || c == 0xF2 || c == KEY_UP) {
if (_cursor > 0) { _cursor--; return true; }
@@ -376,7 +463,7 @@ public:
return false;
}
// A / D consumed (no channel cycling from picker)
// A / D -- consumed (no channel cycling from picker)
if (c == 'a' || c == 'A' || c == KEY_LEFT) {
return true;
}
@@ -384,16 +471,24 @@ public:
return true;
}
// Enter — select the highlighted channel and signal exit
// X -- delete message history for highlighted channel
if (c == 'x' || c == 'X') {
if (_cursor >= 0 && _cursor < _itemCount) {
_confirmDelete = true;
}
return true;
}
// Enter -- select the highlighted channel and signal exit
if (c == '\r' || c == 13 || c == KEY_ENTER || c == KEY_SELECT) {
if (_channelScreen && _cursor >= 0 && _cursor < _itemCount) {
_channelScreen->setViewChannelIdx(_items[_cursor]);
}
_wantExit = true;
return true; // Consumed caller checks wantsExit() and navigates
return true; // Consumed -- caller checks wantsExit() and navigates
}
// Q / backspace cancel without changing channel, signal exit
// Q / backspace -- cancel without changing channel, signal exit
if (c == 'q' || c == 'Q' || c == '\b' || c == KEY_CANCEL) {
_wantExit = true;
return true;
@@ -405,10 +500,22 @@ public:
// -----------------------------------------------------------------------
// Touch hit test (virtual coordinates)
// Returns: 0=miss, 1=cursor moved, 2=activate.
// T5S3 bubbles: any tap on a bubble 2 (direct open).
// T-Deck Pro list: 1st tap 1 (highlight), 2nd tap same row 2.
// T5S3 bubbles: any tap on a bubble -> 2 (direct open).
// T-Deck Pro list: 1st tap -> 1 (highlight), 2nd tap same row -> 2.
// -----------------------------------------------------------------------
int selectAtVxVy(int vx, int vy) {
// If delete confirmation is showing:
// T5S3: tap = confirm (return 2 → KEY_ENTER → handleInput confirms)
// T-Deck Pro: tap = cancel (dismiss overlay, stay on picker)
if (_confirmDelete) {
#if defined(LilyGo_T5S3_EPaper_Pro)
return 2; // Confirm — maps to KEY_ENTER in mapTouchTap
#else
_confirmDelete = false;
return 1; // Cancel — redraw without activating
#endif
}
#if defined(LilyGo_T5S3_EPaper_Pro)
// Vertical bubble list hit test
if (vy < _gridTop || _cellH == 0) return 0;
@@ -420,7 +527,7 @@ public:
_cursor = idx;
return 2; // Direct open on tap
#else
// T-Deck Pro / MAX list hit test uses NodePrefs for large_font compatibility
// T-Deck Pro / MAX list hit test -- uses NodePrefs for large_font compatibility
NodePrefs* prefs = the_mesh.getNodePrefs();
int lineH = prefs->smallLineH();
const int headerH = 14;
@@ -1930,15 +1930,27 @@ public:
snprintf(tmp, sizeof(tmp), " %s [*]", ch.name);
}
if (selected) {
// Show edit/delete hints on right
// Build hint with notification state + actions
uint8_t nPref = _prefs->channel_notif[chIdx];
const char* nTag = (nPref == NOTIF_NONE) ? "Off" :
(nPref == NOTIF_MENTIONS) ? "@" : "All";
char hintBuf[40];
#if defined(LilyGo_T5S3_EPaper_Pro)
const char* hint = chIdx > 0 ? "Ent:Region Hold:Del" : "Ent:Region";
if (chIdx > 0) {
snprintf(hintBuf, sizeof(hintBuf), "Notif:%s Ent:Region Hold:Del", nTag);
} else {
snprintf(hintBuf, sizeof(hintBuf), "Notif:%s Ent:Region", nTag);
}
#else
const char* hint = chIdx > 0 ? "Ent:Region X:Del" : "Ent:Region";
if (chIdx > 0) {
snprintf(hintBuf, sizeof(hintBuf), "N:%s Ent:Region X:Del", nTag);
} else {
snprintf(hintBuf, sizeof(hintBuf), "N:%s Ent:Region", nTag);
}
#endif
int hintW = display.getTextWidth(hint);
int hintW = display.getTextWidth(hintBuf);
display.setCursor(display.width() - hintW - 2, y);
display.print(hint);
display.print(hintBuf);
display.setCursor(0, y);
}
}
@@ -3286,6 +3298,20 @@ public:
}
}
// N: cycle notification preference (All -> Mentions -> None -> All)
if (c == 'n' || c == 'N') {
if (_rows[_cursor].type == ROW_CHANNEL) {
uint8_t chIdx = _rows[_cursor].param;
uint8_t cur = _prefs->channel_notif[chIdx];
_prefs->channel_notif[chIdx] = (cur + 1) % 3;
the_mesh.savePrefs();
const char* labels[] = {"All", "Mentions", "Off"};
Serial.printf("Settings: Channel %d notif -> %s\n",
chIdx, labels[_prefs->channel_notif[chIdx]]);
return true;
}
}
// Q: back -- if in sub-screen, return to top level; else exit settings
if (c == 'q' || c == 'Q') {
if (_subScreen != SUB_NONE) {
+61 -8
View File
@@ -66,6 +66,12 @@
#include "ModemManager.h"
#endif
// Per-channel notification suppression flag.
// Set by newMsg() based on channel_notif preference, checked by notify()
// to suppress buzzer/vibration. Safe because both are called sequentially
// from the same mesh callback on the same thread.
static bool s_lastMsgSuppressed = false;
class SplashScreen : public UIScreen {
UITask* _task;
unsigned long dismiss_after;
@@ -1454,6 +1460,15 @@ void UITask::dismissBootHint() {
}
void UITask::notify(UIEventType t) {
// Per-channel notification gating: if the last message was from a
// muted channel (or mentions-only without an @mention), suppress
// buzzer and vibration. Ack events are never suppressed.
if (s_lastMsgSuppressed && t != UIEventType::ack) {
s_lastMsgSuppressed = false; // Consume the flag
return;
}
s_lastMsgSuppressed = false;
#if defined(PIN_BUZZER)
switch(t){
case UIEventType::contactMessage:
@@ -1520,6 +1535,44 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
break;
}
}
// --- Per-channel notification preference check ---
// Determines whether to suppress toast, buzzer, keyboard flash, vibration,
// display wake, and unread counter for this message. Messages are ALWAYS
// stored in history regardless -- only alerts and unread badges are gated.
bool suppressNotif = false;
{
int notifSlot = (channel_idx == 0xFF) ? MAX_GROUP_CHANNELS : (int)channel_idx;
if (notifSlot >= 0 && notifSlot < (int)sizeof(_node_prefs->channel_notif)) {
uint8_t pref = _node_prefs->channel_notif[notifSlot];
if (pref == NOTIF_NONE) {
suppressNotif = true;
} else if (pref == NOTIF_MENTIONS) {
// Check for @nodename or @[nodename] in message text (case-insensitive).
// MeshCore companion app sends mentions as @[node name] with brackets.
suppressNotif = true; // Suppress unless mention found
if (_node_prefs->node_name[0] != '\0') {
char tagPlain[36];
char tagBracket[38];
snprintf(tagPlain, sizeof(tagPlain), "@%s", _node_prefs->node_name);
snprintf(tagBracket, sizeof(tagBracket), "@[%s]", _node_prefs->node_name);
int lenPlain = strlen(tagPlain);
int lenBracket = strlen(tagBracket);
const char* p = text;
while (*p) {
if (strncasecmp(p, tagBracket, lenBracket) == 0 ||
strncasecmp(p, tagPlain, lenPlain) == 0) {
suppressNotif = false; // Mentioned -- notify
break;
}
p++;
}
}
}
}
}
// Set the flag for notify() which is called immediately after newMsg()
s_lastMsgSuppressed = suppressNotif;
// Add to channel history screen with channel index, path data, and SNR
// For DMs (channel_idx == 0xFF):
@@ -1541,15 +1594,15 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
if (isRoomMsg) {
// Room server: text already has "Poster: message" format — store as-is
// Tag with room server name for conversation filtering
((ChannelScreen *) channel_screen)->addMessage(channel_idx, path_len, from_name, text, path, snr, from_name);
((ChannelScreen *) channel_screen)->addMessage(channel_idx, path_len, from_name, text, path, snr, from_name, suppressNotif);
} else {
// Regular DM: prefix with sender name
char dmFormatted[CHANNEL_MSG_TEXT_LEN];
snprintf(dmFormatted, sizeof(dmFormatted), "%s: %s", from_name, text);
((ChannelScreen *) channel_screen)->addMessage(channel_idx, path_len, from_name, dmFormatted, path, snr);
((ChannelScreen *) channel_screen)->addMessage(channel_idx, path_len, from_name, dmFormatted, path, snr, nullptr, suppressNotif);
}
} else {
((ChannelScreen *) channel_screen)->addMessage(channel_idx, path_len, from_name, text, path, snr);
((ChannelScreen *) channel_screen)->addMessage(channel_idx, path_len, from_name, text, path, snr, nullptr, suppressNotif);
}
// If user is currently viewing this channel on the device, or companion
@@ -1572,11 +1625,11 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
}
}
}
// Don't interrupt user with popup - just show brief notification
// Messages are stored in channel history, accessible via tile/key
// Suppress toasts for room server messages (bulk sync would spam toasts)
if (!isOnRepeaterAdmin() && !isRoomMsg) {
if (!isOnRepeaterAdmin() && !isRoomMsg && !suppressNotif) {
char alertBuf[40];
snprintf(alertBuf, sizeof(alertBuf), "New: %s", from_name);
showAlert(alertBuf, 2000);
@@ -1586,7 +1639,7 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
forceRefresh();
}
if (_display != NULL) {
if (_display != NULL && !suppressNotif) {
if (!_display->isOn() && !hasConnection()) {
_display->turnOn();
}
@@ -1602,9 +1655,9 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i
}
}
// Keyboard flash notification (suppress for room sync)
// Keyboard flash notification (suppress for room sync and muted channels)
#ifdef KB_BL_PIN
if (_node_prefs->kb_flash_notify && !isRoomMsg) {
if (_node_prefs->kb_flash_notify && !isRoomMsg && !suppressNotif) {
digitalWrite(KB_BL_PIN, HIGH);
_kb_flash_off_at = millis() + 200; // 200ms flash
}
+4 -4
View File
@@ -159,7 +159,7 @@ build_flags =
-D MECK_AUDIO_VARIANT
-D MECK_WEB_READER=1
-D MECK_OTA_UPDATE=1
-D FIRMWARE_VERSION='"Meck v1.9.WiFi"'
-D FIRMWARE_VERSION='"Meck v1.10.WiFi"'
build_src_filter = ${LilyGo_TDeck_Pro.build_src_filter}
+<helpers/esp32/*.cpp>
-<helpers/esp32/SerialBLEInterface.cpp>
@@ -226,7 +226,7 @@ build_flags =
-D HAS_4G_MODEM=1
-D MECK_WEB_READER=1
-D MECK_OTA_UPDATE=1
-D FIRMWARE_VERSION='"Meck v1.9.4G"'
-D FIRMWARE_VERSION='"Meck v1.10.4G"'
build_src_filter = ${LilyGo_TDeck_Pro.build_src_filter}
+<helpers/esp32/*.cpp>
+<helpers/ui/MomentaryButton.cpp>
@@ -262,7 +262,7 @@ build_flags =
-D HAS_4G_MODEM=1
-D MECK_WEB_READER=1
-D MECK_OTA_UPDATE=1
-D FIRMWARE_VERSION='"Meck v1.9.4G.WiFi"'
-D FIRMWARE_VERSION='"Meck v1.10.4G.WiFi"'
build_src_filter = ${LilyGo_TDeck_Pro.build_src_filter}
+<helpers/esp32/*.cpp>
-<helpers/esp32/SerialBLEInterface.cpp>
@@ -296,7 +296,7 @@ build_flags =
-D HAS_4G_MODEM=1
-D MECK_WEB_READER=1
-D MECK_OTA_UPDATE=1
-D FIRMWARE_VERSION='"Meck v1.9.4G.SA"'
-D FIRMWARE_VERSION='"Meck v1.10.4G.SA"'
build_src_filter = ${LilyGo_TDeck_Pro.build_src_filter}
+<helpers/esp32/*.cpp>
-<helpers/esp32/SerialBLEInterface.cpp>