From e87cef3fb33b7aa62408db6a04bdc4a736ec98db Mon Sep 17 00:00:00 2001 From: DeFiDude <59237470+DeFiDude@users.noreply.github.com> Date: Mon, 4 May 2026 02:11:30 -0600 Subject: [PATCH] ui: fix stale peer age display --- src/reticulum/AnnounceManager.cpp | 19 ++++++++++--------- src/ui/screens/LvContactsScreen.cpp | 16 ++++++---------- src/ui/screens/LvContactsScreen.h | 2 ++ src/ui/screens/LvNodesScreen.cpp | 17 ++++------------- src/ui/screens/LvNodesScreen.h | 1 + 5 files changed, 23 insertions(+), 32 deletions(-) diff --git a/src/reticulum/AnnounceManager.cpp b/src/reticulum/AnnounceManager.cpp index 89776a0..79204b4 100644 --- a/src/reticulum/AnnounceManager.cpp +++ b/src/reticulum/AnnounceManager.cpp @@ -150,7 +150,8 @@ void AnnounceManager::received_announce( auto it = _hashIndex.find(key); if (it != _hashIndex.end()) { auto& node = _nodes[it->second]; - if (now - node.lastSeen < ANNOUNCE_MIN_INTERVAL_MS) return; + if (node.lastSeen != 0 && now >= node.lastSeen && + now - node.lastSeen < ANNOUNCE_MIN_INTERVAL_MS) return; if (!name.empty()) node.name = name; if (!idHex.empty()) node.identityHex = idHex; node.lastSeen = now; @@ -253,7 +254,7 @@ int AnnounceManager::nodesOnlineSince(unsigned long maxAgeMs) const { unsigned long now = millis(); int count = 0; for (const auto& n : _nodes) { - if (now - n.lastSeen <= maxAgeMs) count++; + if (n.lastSeen != 0 && now >= n.lastSeen && now - n.lastSeen <= maxAgeMs) count++; } return count; } @@ -307,7 +308,7 @@ void AnnounceManager::evictStale(unsigned long maxAgeMs) { unsigned long now = millis(); _nodes.erase(std::remove_if(_nodes.begin(), _nodes.end(), [now, maxAgeMs](const DiscoveredNode& n) { - return !n.saved && (now - n.lastSeen > maxAgeMs); + return !n.saved && (n.lastSeen == 0 || now < n.lastSeen || now - n.lastSeen > maxAgeMs); }), _nodes.end()); rebuildIndex(); } @@ -343,8 +344,6 @@ void AnnounceManager::saveContact(const DiscoveredNode& node) { std::string hexHash = node.hash.toHex(); JsonDocument doc; doc["hash"] = hexHash; doc["name"] = node.name; - doc["rssi"] = node.rssi; doc["snr"] = node.snr; - doc["hops"] = node.hops; doc["lastSeen"] = node.lastSeen; String json; serializeJson(doc, json); String filename = hexHash.substr(0, 16).c_str(); @@ -392,10 +391,12 @@ void AnnounceManager::loadContacts() { node.hash = hash; node.name = sanitizeName(doc["name"] | ""); if (node.name.empty()) node.name = hexHash.substr(0, 12); - node.rssi = doc["rssi"] | 0; - node.snr = doc["snr"] | 0.0f; - node.hops = doc["hops"] | 0; - node.lastSeen = doc["lastSeen"] | (unsigned long)millis(); + // Contacts persist address-book data only. Radio/path state + // is boot-relative and becomes misleading after restart. + node.rssi = 0; + node.snr = 0.0f; + node.hops = 0; + node.lastSeen = 0; node.saved = true; _hashIndex[key] = (int)_nodes.size(); _nodes.push_back(node); diff --git a/src/ui/screens/LvContactsScreen.cpp b/src/ui/screens/LvContactsScreen.cpp index e2c5d6f..7f8bcf4 100644 --- a/src/ui/screens/LvContactsScreen.cpp +++ b/src/ui/screens/LvContactsScreen.cpp @@ -50,14 +50,8 @@ std::string compactAge(unsigned long ageMs) { return buf; } -std::string contactMetaFor(const DiscoveredNode& node, unsigned long ageMs) { - std::string age = compactAge(ageMs); - if (node.hops > 0 && node.hops < 128) { - char buf[24]; - snprintf(buf, sizeof(buf), "%uH %s", (unsigned)node.hops, age.c_str()); - return buf; - } - return age; +std::string contactMetaFor(unsigned long ageMs) { + return compactAge(ageMs); } lv_obj_t* createEmptyState(lv_obj_t* parent) { @@ -132,15 +126,17 @@ void LvContactsScreen::onEnter() { void LvContactsScreen::refreshUI() { if (!_am) return; + unsigned long now = millis(); int contacts = 0; for (const auto& n : _am->nodes()) { if (n.saved) contacts++; } - if (contacts != _lastContactCount) { + if (contacts != _lastContactCount || now - _lastRebuild >= REBUILD_INTERVAL_MS) { rebuildList(); } } void LvContactsScreen::rebuildList() { if (!_am || !_list) return; + _lastRebuild = millis(); _contactIndices.clear(); lv_obj_clean(_list); @@ -224,7 +220,7 @@ void LvContactsScreen::rebuildList() { lv_obj_set_style_text_align(metaLbl, LV_TEXT_ALIGN_RIGHT, 0); lv_label_set_long_mode(metaLbl, LV_LABEL_LONG_CLIP); lv_obj_set_width(metaLbl, 64); - std::string meta = contactMetaFor(node, age); + std::string meta = contactMetaFor(age); lv_label_set_text(metaLbl, meta.c_str()); lv_obj_set_pos(metaLbl, Theme::CONTENT_W - 72, 5); diff --git a/src/ui/screens/LvContactsScreen.h b/src/ui/screens/LvContactsScreen.h index a53bca7..98a3f76 100644 --- a/src/ui/screens/LvContactsScreen.h +++ b/src/ui/screens/LvContactsScreen.h @@ -33,6 +33,8 @@ private: bool _focusActive = false; int _deleteIdx = -1; int _lastContactCount = -1; + unsigned long _lastRebuild = 0; + static constexpr unsigned long REBUILD_INTERVAL_MS = 30000; std::vector _contactIndices; std::vector> _avatarBuffers; diff --git a/src/ui/screens/LvNodesScreen.cpp b/src/ui/screens/LvNodesScreen.cpp index ca5a365..327c9c3 100644 --- a/src/ui/screens/LvNodesScreen.cpp +++ b/src/ui/screens/LvNodesScreen.cpp @@ -48,19 +48,8 @@ std::string compactAge(unsigned long ageMs) { return buf; } -std::string hopTextFor(const DiscoveredNode& node) { - if (node.hops > 0 && node.hops < 128) { - char buf[12]; - snprintf(buf, sizeof(buf), "%uhop", (unsigned)node.hops); - return buf; - } - return ""; -} - std::string peerMetaFor(const DiscoveredNode& node, unsigned long ageMs, bool devMode) { - std::string meta = hopTextFor(node); - if (!meta.empty()) meta += " "; - meta += compactAge(ageMs); + std::string meta = compactAge(ageMs); if (devMode && node.rssi != 0) { char buf[14]; snprintf(buf, sizeof(buf), " %ddB", node.rssi); @@ -242,7 +231,8 @@ void LvNodesScreen::refreshUI() { for (const auto& n : _am->nodes()) { if (n.saved) contacts++; } int countDelta = abs(_am->nodeCount() - _lastNodeCount); int contactDelta = abs(contacts - _lastContactCount); - if (countDelta > 0 || contactDelta > 0) { + bool ageRefresh = now - _lastRebuild >= AGE_REBUILD_INTERVAL_MS; + if (countDelta > 0 || contactDelta > 0 || ageRefresh) { _lastRebuild = now; rebuildList(); } @@ -250,6 +240,7 @@ void LvNodesScreen::refreshUI() { void LvNodesScreen::rebuildList() { if (!_am || !_list) return; + _lastRebuild = millis(); // Preserve scroll position across rebuilds lv_coord_t scrollY = lv_obj_get_scroll_y(_list); lv_obj_clean(_list); diff --git a/src/ui/screens/LvNodesScreen.h b/src/ui/screens/LvNodesScreen.h index d212e73..b2453f3 100644 --- a/src/ui/screens/LvNodesScreen.h +++ b/src/ui/screens/LvNodesScreen.h @@ -71,6 +71,7 @@ private: unsigned long _lastRebuild = 0; static constexpr unsigned long REBUILD_INTERVAL_MS = 5000; + static constexpr unsigned long AGE_REBUILD_INTERVAL_MS = 30000; lv_obj_t* _list = nullptr; lv_obj_t* _emptyState = nullptr;