feat(nav): navigate to a node from Nearby

Phase 6. In a node's detail view, Enter (when the ping popup is closed)
opens the shared NavView targeting that node's last-known advert position
— same To/Hdg/distance screen used by waypoints. Nodes with no position
report "No node GPS". This turns Nearby from a static snapshot into a
"walk toward this person" view and folds in the old compass-to-contact idea.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-06-03 08:32:32 +02:00
co-authored by Claude Opus 4.8
parent 6f7647481a
commit 6ca1c766ef
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <math.h> #include <math.h>
#include "../GeoUtils.h" #include "../GeoUtils.h"
#include "NavView.h"
#ifndef M_PI #ifndef M_PI
#define M_PI 3.14159265358979323846 #define M_PI 3.14159265358979323846
@@ -31,6 +32,7 @@ class NearbyScreen : public UIScreen {
int _sel; int _sel;
int _scroll; int _scroll;
bool _detail; bool _detail;
bool _nav = false; // full-screen navigate-to-node view (over detail)
int32_t _own_lat, _own_lon; int32_t _own_lat, _own_lon;
bool _own_gps; bool _own_gps;
uint8_t _filter; uint8_t _filter;
@@ -536,6 +538,7 @@ public:
void enter() { void enter() {
_sel = _scroll = 0; _sel = _scroll = 0;
_detail = false; _detail = false;
_nav = false;
_filter = 0; _filter = 0;
_discover_mode = false; _discover_mode = false;
_ddetail = false; _ddetail = false;
@@ -570,6 +573,15 @@ public:
_detail_refresh_ms = millis(); _detail_refresh_ms = millis();
} }
// ── navigate-to-node view ────────────────────────────────────────────────
if (_nav && _sel < _count) {
const Entry& e = _entries[_sel];
int cog; bool cogv = _task->currentCourse(cog);
navview::draw(display, _own_gps, _own_lat, _own_lon,
e.lat_e6, e.lon_e6, e.name, cogv, cog);
return 1000;
}
// ── detail view ────────────────────────────────────────────────────────── // ── detail view ──────────────────────────────────────────────────────────
if (_detail && _sel < _count) { if (_detail && _sel < _count) {
renderStoredDetail(display); renderStoredDetail(display);
@@ -632,6 +644,13 @@ public:
// ── discover sub-screen ────────────────────────────────────────────────── // ── discover sub-screen ──────────────────────────────────────────────────
if (_discover_mode) return handleInputDiscover(c); if (_discover_mode) return handleInputDiscover(c);
// ── navigate-to-node view — any nav key returns to detail ─────────────────
if (_nav) {
if (c == KEY_CANCEL || c == KEY_LEFT || c == KEY_PREV ||
c == KEY_RIGHT || c == KEY_NEXT) { _nav = false; }
return true;
}
// ── detail view ───────────────────────────────────────────────────────── // ── detail view ─────────────────────────────────────────────────────────
if (_detail) { if (_detail) {
if (c == KEY_CANCEL) { if (c == KEY_CANCEL) {
@@ -642,6 +661,13 @@ public:
uint8_t pub_key[PUB_KEY_SIZE]; uint8_t pub_key[PUB_KEY_SIZE];
if (selectedStoredPubKey(pub_key) && handlePingMenuInput(c, pub_key)) return true; if (selectedStoredPubKey(pub_key) && handlePingMenuInput(c, pub_key)) return true;
// Enter (ping menu closed) → navigate to this node's last-known position.
if (c == KEY_ENTER && _sel < _count) {
const Entry& e = _entries[_sel];
if (e.lat_e6 != 0 || e.lon_e6 != 0) _nav = true;
else _task->showAlert("No node GPS", 1000);
}
return true; return true;
} }