From 6f6ee8c06ae639002be36d42c58cab20ed893f05 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 1 Jun 2025 22:47:44 -0500 Subject: [PATCH] Clean up after Copilot --- src/graphics/Screen.cpp | 13 +--- src/graphics/Screen.h | 12 +-- src/graphics/draw/DebugRenderer.cpp | 40 +++++----- src/graphics/draw/NotificationRenderer.cpp | 57 +++++++------- src/graphics/draw/UIRenderer.cpp | 5 +- src/modules/CannedMessageModule.cpp | 90 +++++++++++----------- 6 files changed, 97 insertions(+), 120 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index be6d22a27..33734116f 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -95,11 +95,6 @@ namespace graphics FrameCallback *normalFrames; static uint32_t targetFramerate = IDLE_FRAMERATE; // Global variables for alert banner - explicitly define with extern "C" linkage to prevent optimization -extern "C" { -static char alertBannerBuffer[256] = ""; -char *alertBannerMessage = alertBannerBuffer; -uint32_t alertBannerUntil = 0; -} uint32_t logo_timeout = 5000; // 4 seconds for EACH logo @@ -117,12 +112,6 @@ std::vector moduleFrames; std::vector functionSymbol; std::string functionSymbolString; -// Stores the last 4 of our hardware ID, to make finding the device for pairing easier -// FIXME: Needs refactoring and getMacAddr needs to be moved to a utility class -extern "C" { -char ourId[5]; -} - #if HAS_GPS // GeoCoord object for the screen GeoCoord geoCoord; @@ -1006,7 +995,7 @@ void Screen::setup() // === Generate device ID from MAC address === uint8_t dmac[6]; getMacAddr(dmac); - snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]); + snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]); #if ARCH_PORTDUINO handleSetOn(false); // Ensure proper init for Arduino targets diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 5f74f12aa..0175b7721 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -220,6 +220,13 @@ class Screen : public concurrency::OSThread meshtastic_Config_DisplayConfig_OledType model; OLEDDISPLAY_GEOMETRY geometry; + char alertBannerMessage[256] = {0}; + uint32_t alertBannerUntil = 0; + + // Stores the last 4 of our hardware ID, to make finding the device for pairing easier + // FIXME: Needs refactoring and getMacAddr needs to be moved to a utility class + char ourId[5]; + /// Initializes the UI, turns on the display, starts showing boot screen. // // Not thread safe - must be called before any other methods are called. @@ -698,11 +705,6 @@ class Screen : public concurrency::OSThread } // namespace graphics -extern "C" { -extern char *alertBannerMessage; -extern uint32_t alertBannerUntil; -} - // Extern declarations for function symbols used in UIRenderer extern std::vector functionSymbol; extern std::string functionSymbolString; diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 54fba7618..b4d90ebb3 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -41,9 +41,6 @@ extern PowerStatus *powerStatus; extern NodeStatus *nodeStatus; extern GPSStatus *gpsStatus; extern Channels channels; -extern "C" { -extern char ourId[5]; -} extern AirTime *airTime; // External functions from Screen.cpp @@ -116,25 +113,25 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16 #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, - imgQuestionL1); - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, - imgQuestionL2); + display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, + 8, imgQuestionL1); + display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 11 + FONT_HEIGHT_SMALL, 12, + 8, imgQuestionL2); #else - display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, - imgQuestion); + display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(screen->ourId), y + 2 + FONT_HEIGHT_SMALL, 8, + 8, imgQuestion); #endif } else { #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) - display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8, - imgSFL1); - display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8, - imgSFL2); + display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 16, + 8, imgSFL1); + display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(screen->ourId), y + 11 + FONT_HEIGHT_SMALL, 16, + 8, imgSFL2); #else - display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 11, 8, - imgSF); + display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(screen->ourId), y + 2 + FONT_HEIGHT_SMALL, 11, + 8, imgSF); #endif } #endif @@ -143,16 +140,17 @@ void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16 #if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \ defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \ !defined(DISPLAY_FORCE_SMALL_FONTS) - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, + display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL1); - display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, + display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(screen->ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8, imgInfoL2); #else - display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo); + display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(screen->ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, + imgInfo); #endif } - display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId); + display->drawString(x + SCREEN_WIDTH - display->getStringWidth(screen->ourId), y + FONT_HEIGHT_SMALL, screen->ourId); // Draw any log messages display->drawLogBuffer(x, y + (FONT_HEIGHT_SMALL * 2)); @@ -427,8 +425,8 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, uint8_t dmac[6]; char shortnameble[35]; getMacAddr(dmac); - snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]); - snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", ourId); + snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]); + snprintf(shortnameble, sizeof(shortnameble), "BLE: %s", screen->ourId); int textWidth = display->getStringWidth(shortnameble); int nameX = (SCREEN_WIDTH - textWidth); display->drawString(nameX, compactFirstLine, shortnameble); diff --git a/src/graphics/draw/NotificationRenderer.cpp b/src/graphics/draw/NotificationRenderer.cpp index 18c1c0d9f..e9d2eac55 100644 --- a/src/graphics/draw/NotificationRenderer.cpp +++ b/src/graphics/draw/NotificationRenderer.cpp @@ -76,7 +76,7 @@ void NotificationRenderer::drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUi void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) { // Exit if no message is active or duration has passed - if (strlen(alertBannerMessage) == 0 || (alertBannerUntil != 0 && millis() > alertBannerUntil)) + if (strlen(screen->alertBannerMessage) == 0 || (screen->alertBannerUntil != 0 && millis() > screen->alertBannerUntil)) return; // === Layout Configuration === @@ -84,45 +84,38 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp constexpr uint8_t lineSpacing = 1; // Extra space between lines // Search the message to determine if we need the bell added - bool needs_bell = (strstr(alertBannerMessage, "Alert Received") != nullptr); + bool needs_bell = (strstr(screen->alertBannerMessage, "Alert Received") != nullptr); // Setup font and alignment display->setFont(FONT_SMALL); display->setTextAlignment(TEXT_ALIGN_LEFT); // We will manually center per line - - // === Split the message into lines (supports multi-line banners) === const int MAX_LINES = 10; - char lines[MAX_LINES][256]; - int lineCount = 0; - // Create a working copy of the message to tokenize - char messageCopy[256]; - strncpy(messageCopy, alertBannerMessage, sizeof(messageCopy) - 1); - messageCopy[sizeof(messageCopy) - 1] = '\0'; - - char *line = strtok(messageCopy, "\n"); - while (line != nullptr && lineCount < MAX_LINES) { - strncpy(lines[lineCount], line, sizeof(lines[lineCount]) - 1); - lines[lineCount][sizeof(lines[lineCount]) - 1] = '\0'; - lineCount++; - line = strtok(nullptr, "\n"); - } - - // === Measure text dimensions === - uint16_t minWidth = (SCREEN_WIDTH > 128) ? 106 : 78; uint16_t maxWidth = 0; uint16_t lineWidths[MAX_LINES]; - for (int i = 0; i < lineCount; i++) { - uint16_t w = display->getStringWidth(lines[i], strlen(lines[i]), true); - lineWidths[i] = w; - if (w > maxWidth) - maxWidth = w; + char *lineStarts[MAX_LINES]; + uint16_t lineCount = 0; + char lineBuffer[40] = {0}; + uint16_t alertLength = strnlen(screen->alertBannerMessage, sizeof(screen->alertBannerMessage)); + lineStarts[lineCount] = screen->alertBannerMessage; + + // loop through lines finding \n characters + while (lineCount < 10 && lineStarts[lineCount] != screen->alertBannerMessage + alertLength) { + lineStarts[lineCount + 1] = std::find(lineStarts[lineCount], screen->alertBannerMessage + alertLength, '\n'); + lineWidths[lineCount] = + display->getStringWidth(lineStarts[lineCount], lineStarts[lineCount + 1] - lineStarts[lineCount], true); + if (lineWidths[lineCount] > maxWidth) { + maxWidth = lineWidths[lineCount]; + } + lineCount++; } + // set width from longest line uint16_t boxWidth = padding * 2 + maxWidth; - if (needs_bell && boxWidth < minWidth) + if (needs_bell && boxWidth < (SCREEN_WIDTH > 128) ? 106 : 78) boxWidth += (SCREEN_WIDTH > 128) ? 26 : 20; + // set height from line count uint16_t boxHeight = padding * 2 + lineCount * FONT_HEIGHT_SMALL + (lineCount - 1) * lineSpacing; int16_t boxLeft = (display->width() / 2) - (boxWidth / 2); @@ -137,18 +130,20 @@ void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisp // === Draw each line centered in the box === int16_t lineY = boxTop + padding; for (int i = 0; i < lineCount; i++) { + strncpy(lineBuffer, lineStarts[i], 40); + lineStarts[i][40] = '\0'; + int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2; - uint16_t line_width = display->getStringWidth(lines[i], strlen(lines[i]), true); if (needs_bell && i == 0) { int bellY = lineY + (FONT_HEIGHT_SMALL - 8) / 2; display->drawXbm(textX - 10, bellY, 8, 8, bell_alert); - display->drawXbm(textX + line_width + 2, bellY, 8, 8, bell_alert); + display->drawXbm(textX + lineWidths[i] + 2, bellY, 8, 8, bell_alert); } - display->drawString(textX, lineY, lines[i]); + display->drawString(textX, lineY, lineBuffer); if (SCREEN_WIDTH > 128) - display->drawString(textX + 1, lineY, lines[i]); // Faux bold + display->drawString(textX + 1, lineY, lineBuffer); // Faux bold lineY += FONT_HEIGHT_SMALL + lineSpacing; } diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index becc5347d..6e2b45810 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -21,9 +21,6 @@ // External variables extern graphics::Screen *screen; -extern "C" { -extern char ourId[5]; -} namespace graphics { @@ -669,7 +666,7 @@ void drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t uint8_t dmac[6]; char shortnameble[35]; getMacAddr(dmac); - snprintf(ourId, sizeof(ourId), "%02x%02x", dmac[4], dmac[5]); + snprintf(screen->ourId, sizeof(screen->ourId), "%02x%02x", dmac[4], dmac[5]); snprintf(shortnameble, sizeof(shortnameble), "%s", graphics::UIRenderer::haveGlyphs(owner.short_name) ? owner.short_name : ""); diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 254e417f9..753967aff 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -380,9 +380,8 @@ bool CannedMessageModule::handleTabSwitch(const InputEvent *event) if (event->kbchar != 0x09) return false; - runState = (runState == CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION) - ? CANNED_MESSAGE_RUN_STATE_FREETEXT - : CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION; + runState = (runState == CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION) ? CANNED_MESSAGE_RUN_STATE_FREETEXT + : CANNED_MESSAGE_RUN_STATE_DESTINATION_SELECTION; destIndex = 0; scrollIndex = 0; @@ -720,8 +719,8 @@ bool CannedMessageModule::handleSystemCommandInput(const InputEvent *event) if (event->inputEvent != static_cast(ANYKEY)) return false; - // Block ALL input if an alert banner is active - if (strlen(alertBannerMessage) > 0 && (alertBannerUntil == 0 || millis() <= alertBannerUntil)) { + // Block ALL input if an alert banner is active // TODO: Make an accessor function + if (strlen(screen->alertBannerMessage) > 0 && (screen->alertBannerUntil == 0 || millis() <= screen->alertBannerUntil)) { return true; } @@ -890,8 +889,7 @@ int32_t CannedMessageModule::runOnce() // Normal module disable/idle handling if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) || - (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || - (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) { + (this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) { temporaryMessage = ""; return INT32_MAX; } @@ -906,25 +904,23 @@ int32_t CannedMessageModule::runOnce() this->currentMessageIndex = -1; this->freetext = ""; this->cursor = 0; - #if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(SENSECAP_INDICATOR) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(SENSECAP_INDICATOR) int destSelect = 0; - #endif +#endif this->notifyObservers(&e); - } - else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && - !Throttle::isWithinTimespanMs(this->lastTouchMillis, INACTIVATE_AFTER_MS)) { + } else if (((this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) || (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT)) && + !Throttle::isWithinTimespanMs(this->lastTouchMillis, INACTIVATE_AFTER_MS)) { // Reset module on inactivity e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; this->currentMessageIndex = -1; this->freetext = ""; this->cursor = 0; - #if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) int destSelect = 0; - #endif +#endif this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE; this->notifyObservers(&e); - } - else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) { + } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_SELECT) { if (this->payload == CANNED_MESSAGE_RUN_STATE_FREETEXT) { if (this->freetext.length() > 0) { sendText(this->dest, this->channel, this->freetext.c_str(), true); @@ -969,8 +965,7 @@ int32_t CannedMessageModule::runOnce() this->currentMessageIndex = firstRealMsgIdx; e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; - } - else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) { + } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_UP) { if (this->messagesCount > 0) { this->currentMessageIndex = getPrevIndex(); this->freetext = ""; @@ -978,8 +973,7 @@ int32_t CannedMessageModule::runOnce() this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; LOG_DEBUG("MOVE UP (%d):%s", this->currentMessageIndex, this->getCurrentMessage()); } - } - else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_DOWN) { + } else if (this->runState == CANNED_MESSAGE_RUN_STATE_ACTION_DOWN) { if (this->messagesCount > 0) { this->currentMessageIndex = this->getNextIndex(); this->freetext = ""; @@ -987,8 +981,7 @@ int32_t CannedMessageModule::runOnce() this->runState = CANNED_MESSAGE_RUN_STATE_ACTIVE; LOG_DEBUG("MOVE DOWN (%d):%s", this->currentMessageIndex, this->getCurrentMessage()); } - } - else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) { + } else if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT || this->runState == CANNED_MESSAGE_RUN_STATE_ACTIVE) { switch (this->payload) { case INPUT_BROKER_MSG_LEFT: if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT && this->cursor > 0) { @@ -1012,7 +1005,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = this->freetext.substring(0, this->freetext.length() - 1); } else { this->freetext = this->freetext.substring(0, this->cursor - 1) + - this->freetext.substring(this->cursor, this->freetext.length()); + this->freetext.substring(this->cursor, this->freetext.length()); } this->cursor--; } @@ -1023,11 +1016,13 @@ int32_t CannedMessageModule::runOnce() case INPUT_BROKER_MSG_RIGHT: break; default: - if (this->highlight != 0x00) break; + if (this->highlight != 0x00) + break; if (this->cursor == this->freetext.length()) { this->freetext += this->payload; } else { - this->freetext = this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor); + this->freetext = + this->freetext.substring(0, this->cursor) + this->payload + this->freetext.substring(this->cursor); } this->cursor += 1; uint16_t maxChars = meshtastic_Constants_DATA_PAYLOAD_LEN - (moduleConfig.canned_message.send_bell ? 1 : 0); @@ -1346,7 +1341,8 @@ bool CannedMessageModule::interceptingKeyboardInput() } // Draw the node/channel selection screen -void CannedMessageModule::drawDestinationSelectionScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { +void CannedMessageModule::drawDestinationSelectionScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ requestFocus(); display->setColor(WHITE); // Always draw cleanly display->setTextAlignment(TEXT_ALIGN_LEFT); @@ -1380,32 +1376,32 @@ void CannedMessageModule::drawDestinationSelectionScreen(OLEDDisplay *display, O if (itemIndex >= totalEntries) break; - int xOffset = 0; - int yOffset = row * (FONT_HEIGHT_SMALL - 4) + rowYOffset; - char entryText[64]; + int xOffset = 0; + int yOffset = row * (FONT_HEIGHT_SMALL - 4) + rowYOffset; + char entryText[64]; - // Draw Channels First - if (itemIndex < numActiveChannels) { - uint8_t channelIndex = this->activeChannelIndices[itemIndex]; - snprintf(entryText, sizeof(entryText), "@%s", channels.getName(channelIndex)); - } - // Then Draw Nodes - else { - int nodeIndex = itemIndex - numActiveChannels; - if (nodeIndex >= 0 && nodeIndex < static_cast(this->filteredNodes.size())) { - meshtastic_NodeInfoLite *node = this->filteredNodes[nodeIndex].node; - if (node) { - if (node->is_favorite) { - snprintf(entryText, sizeof(entryText), "* %s", node->user.long_name); - } else { - snprintf(entryText, sizeof(entryText), "%s", node->user.long_name); - } + // Draw Channels First + if (itemIndex < numActiveChannels) { + uint8_t channelIndex = this->activeChannelIndices[itemIndex]; + snprintf(entryText, sizeof(entryText), "@%s", channels.getName(channelIndex)); + } + // Then Draw Nodes + else { + int nodeIndex = itemIndex - numActiveChannels; + if (nodeIndex >= 0 && nodeIndex < static_cast(this->filteredNodes.size())) { + meshtastic_NodeInfoLite *node = this->filteredNodes[nodeIndex].node; + if (node) { + if (node->is_favorite) { + snprintf(entryText, sizeof(entryText), "* %s", node->user.long_name); + } else { + snprintf(entryText, sizeof(entryText), "%s", node->user.long_name); } } } + } - if (strlen(entryText) == 0 || strcmp(entryText, "Unknown") == 0) - strcpy(entryText, "?"); + if (strlen(entryText) == 0 || strcmp(entryText, "Unknown") == 0) + strcpy(entryText, "?"); // === Highlight background (if selected) === if (itemIndex == destIndex) {