feat(ui): mark-all-read context menu on MESSAGE mode-select

Hold Enter (context menu) on the DM / Channels / Rooms picker opens a
single-item "Mark all read" menu that clears every unread counter of
the highlighted type. Per-mode title is a static-const string because
PopupMenu stores the title pointer verbatim.

New UITask::clearAllDMUnread() resets the whole _dm_unread_table;
clearAllChannelUnread() and clearRoomUnread() already existed.

Also document the GPS breadcrumb storage decision in FEATURES.md:
RAM-only ring with explicit per-slot saves, no background flash writes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-24 22:43:31 +02:00
parent a4b4362b1b
commit 31cfbf4997
3 changed files with 245 additions and 0 deletions

View File

@@ -505,6 +505,7 @@ public:
}
}
display.setColor(DisplayDriver::LIGHT);
if (_ctx_menu.active) _ctx_menu.render(display);
} else if (_phase == CONTACT_PICK) {
display.drawTextCentered(display.width()/2, 0, _room_mode ? "SELECT ROOM" : "SELECT CONTACT");
@@ -860,9 +861,33 @@ public:
bool handleInput(char c) override {
if (_phase == MODE_SELECT) {
// Context menu (Mark-all-read) takes precedence while active.
if (_ctx_menu.active) {
auto res = _ctx_menu.handleInput(c);
if (res == PopupMenu::SELECTED) {
if (_mode_sel == 0) {
_task->clearAllDMUnread();
_task->showAlert("DMs marked read", 800);
} else if (_mode_sel == 1) {
clearAllChannelUnread();
_task->showAlert("Channels marked read", 800);
} else {
_task->clearRoomUnread();
_task->showAlert("Rooms marked read", 800);
}
}
return true;
}
if (c == KEY_CANCEL) { _task->gotoHomeScreen(); return true; }
if (c == KEY_UP && _mode_sel > 0) { _mode_sel--; return true; }
if (c == KEY_DOWN && _mode_sel < 2) { _mode_sel++; return true; }
if (c == KEY_CONTEXT_MENU) {
// PopupMenu stores the title pointer verbatim — use static strings.
static const char* MODE_TITLES[] = { "DM options", "Channel options", "Room options" };
_ctx_menu.begin(MODE_TITLES[_mode_sel < 3 ? _mode_sel : 0], 1);
_ctx_menu.addItem("Mark all read");
return true;
}
if (c == KEY_ENTER) {
if (_mode_sel == 1) {
_phase = CHANNEL_PICK;

View File

@@ -136,6 +136,7 @@ public:
if (_dm_unread_table[i].count > 0 && memcmp(_dm_unread_table[i].prefix, pub_key, 4) == 0)
{ _dm_unread_table[i].count = 0; return; }
}
void clearAllDMUnread() { memset(_dm_unread_table, 0, sizeof(_dm_unread_table)); }
bool hasDisplay() const { return _display != NULL; }
bool isButtonPressed() const;