feat(nav): offer Navigate / Save waypoint from the message list too

Previously a shared location was only actionable after opening the message
fullscreen; Hold Enter on a history row only ever offered Reply. Route the
DM and channel list context menus through the same buildFsMenu /
dispatchFsAction path as the fullscreen view, so Navigate / Save waypoint
appear directly on the list row when the selected message carries a
location (Navigate returns to the list on Back).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-06-04 11:57:29 +02:00
co-authored by Claude Opus 4.8
parent 75f9ccb34a
commit 54b07a5941
2 changed files with 12 additions and 12 deletions
@@ -48,7 +48,7 @@ Sensor placeholders appear automatically in the placeholder picker when the corr
Each entry in the history list shows the sender name and a compact age indicator (`3m`, `2h`, `>1d`) in the top-right corner. Each entry in the history list shows the sender name and a compact age indicator (`3m`, `2h`, `>1d`) in the top-right corner.
**Short Enter** on a message opens it in fullscreen. **Hold Enter** opens the context menu (Reply, plus Navigate / Save waypoint when the message contains a location see Fullscreen message view). **Short Enter** on a message opens it in fullscreen. **Hold Enter** — on a history row or in fullscreen — opens the same options menu: Reply, plus **Navigate** / **Save waypoint** when the message contains a location (see Fullscreen message view). You don't need to open the message first.
--- ---
@@ -1407,7 +1407,7 @@ public:
if (_ctx_menu.active) { if (_ctx_menu.active) {
auto res = _ctx_menu.handleInput(c); auto res = _ctx_menu.handleInput(c);
if (res == PopupMenu::SELECTED) { if (res == PopupMenu::SELECTED) {
startReply(false); dispatchFsAction(false);
} else if (res != PopupMenu::NONE) { } else if (res != PopupMenu::NONE) {
_ctx_menu.active = false; _ctx_menu.active = false;
} }
@@ -1452,11 +1452,13 @@ public:
} }
if (c == KEY_CONTEXT_MENU && _dm_hist_sel >= 0) { if (c == KEY_CONTEXT_MENU && _dm_hist_sel >= 0) {
int ring_pos = dmHistEntryForContact(_sel_contact.id.pub_key, _dm_hist_sel); int ring_pos = dmHistEntryForContact(_sel_contact.id.pub_key, _dm_hist_sel);
if (ring_pos >= 0 && !_dm_hist[ring_pos].outgoing) { if (ring_pos >= 0) {
char _tname[32]; DisplayDriver::translateUTF8Static(_tname, _sel_contact.name, sizeof(_tname)); bool reply_ok = !_dm_hist[ring_pos].outgoing;
snprintf(_reply_prefix, sizeof(_reply_prefix), "@[%.31s] ", _tname); if (reply_ok) {
_ctx_menu.begin("Options", 1); char _tname[32]; DisplayDriver::translateUTF8Static(_tname, _sel_contact.name, sizeof(_tname));
_ctx_menu.addItem("Reply"); snprintf(_reply_prefix, sizeof(_reply_prefix), "@[%.31s] ", _tname);
}
buildFsMenu(_dm_hist[ring_pos].text, reply_ok);
} }
return true; return true;
} }
@@ -1490,7 +1492,7 @@ public:
if (_ctx_menu.active) { if (_ctx_menu.active) {
auto res = _ctx_menu.handleInput(c); auto res = _ctx_menu.handleInput(c);
if (res == PopupMenu::SELECTED) { if (res == PopupMenu::SELECTED) {
startReply(true); dispatchFsAction(true);
} else if (res != PopupMenu::NONE) { } else if (res != PopupMenu::NONE) {
_ctx_menu.active = false; _ctx_menu.active = false;
} }
@@ -1525,10 +1527,8 @@ public:
} }
if (c == KEY_CONTEXT_MENU && _hist_sel >= 0) { if (c == KEY_CONTEXT_MENU && _hist_sel >= 0) {
int ring_pos = histEntryForChannel(_sel_channel_idx, _hist_sel); int ring_pos = histEntryForChannel(_sel_channel_idx, _hist_sel);
if (ring_pos >= 0 && buildChannelReplyPrefix(_hist[ring_pos].text)) { if (ring_pos >= 0)
_ctx_menu.begin("Options", 1); buildFsMenu(_hist[ring_pos].text, buildChannelReplyPrefix(_hist[ring_pos].text));
_ctx_menu.addItem("Reply");
}
return true; return true;
} }