mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-16 08:31:35 +10:00
Full T-echo card support + Compact UI (#11342)
* T-echo card * Update NRF52I2SOutput.cpp * Update NRF52I2SOutput.h * cleanup * Update buzz.cpp * use consistent runtime compact-panel check instead of mixing with compile-time macro * Update NodeDB.cpp * Update ExternalNotificationModule.cpp * switched to Throttle::isWithinTimespanMs * Update SharedUIDisplay.h * trunk fix * last cleanup * ClockRenderer.cpp for OLED_COMPACT_UI and setup Unit C6L for new UI. * Fixed regressions in standard OLED and TFT --------- Co-authored-by: Jason P <applewiz@mac.com>
This commit is contained in:
@@ -69,6 +69,12 @@ void scrollDown()
|
||||
if (maxScroll < 0)
|
||||
maxScroll = 0;
|
||||
|
||||
if (graphics::isCompactPanel(screen->getDisplayDevice()) && scrollY >= maxScroll) {
|
||||
// Compact panels: scrolling past the bottom wraps back to the top.
|
||||
scrollY = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
scrollY += 12;
|
||||
if (scrollY > maxScroll)
|
||||
scrollY = maxScroll;
|
||||
@@ -427,9 +433,12 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
display->clear();
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
const int navHeight = FONT_HEIGHT_SMALL;
|
||||
const bool compactPanel = graphics::isCompactPanel(display);
|
||||
// Compact panels: no bottom nav row anymore (see UIRenderer::drawNavigationBar), full height available.
|
||||
const int navHeight = compactPanel ? 0 : FONT_HEIGHT_SMALL;
|
||||
const int scrollBottom = SCREEN_HEIGHT - navHeight;
|
||||
const int usableHeight = scrollBottom;
|
||||
const int contentTop = compactPanel ? 0 : getTextPositions(display)[1];
|
||||
const int usableHeight = compactPanel ? scrollBottom - contentTop : scrollBottom;
|
||||
constexpr int LEFT_MARGIN = 2;
|
||||
constexpr int RIGHT_MARGIN = 2;
|
||||
constexpr int SCROLLBAR_WIDTH = 3;
|
||||
@@ -440,7 +449,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
constexpr int BUBBLE_TEXT_INDENT = 2;
|
||||
|
||||
// Check if bubbles are enabled
|
||||
const bool showBubbles = config.display.enable_message_bubbles;
|
||||
const bool showBubbles = config.display.enable_message_bubbles && !compactPanel;
|
||||
const int textIndent = showBubbles ? (BUBBLE_PAD_X + BUBBLE_TEXT_INDENT) : LEFT_MARGIN;
|
||||
|
||||
// Derived widths
|
||||
@@ -616,13 +625,17 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
snprintf(senderName, sizeof(senderName), "(%08x)", m.dest);
|
||||
}
|
||||
|
||||
// Shrink Sender name if needed
|
||||
int availWidth = (mine ? rightTextWidth : leftTextWidth) - display->getStringWidth(timeBuf) -
|
||||
display->getStringWidth(chanType) - graphics::UIRenderer::measureStringWithEmotes(display, " *@...");
|
||||
// Shrink Sender name if needed; compact panels put it on its own line, so no sharing with timeBuf/chanType.
|
||||
int availWidth = compactPanel ? (mine ? rightTextWidth : leftTextWidth)
|
||||
: (mine ? rightTextWidth : leftTextWidth) - display->getStringWidth(timeBuf) -
|
||||
display->getStringWidth(chanType);
|
||||
// Compact panels hard-cut (no "...") so drop its width reservation too.
|
||||
availWidth -= graphics::UIRenderer::measureStringWithEmotes(display, compactPanel ? "*@" : " *@...");
|
||||
if (availWidth < 0)
|
||||
availWidth = 0;
|
||||
char truncatedSender[64];
|
||||
graphics::UIRenderer::truncateStringWithEmotes(display, senderName, truncatedSender, sizeof(truncatedSender), availWidth);
|
||||
graphics::UIRenderer::truncateStringWithEmotes(display, senderName, truncatedSender, sizeof(truncatedSender), availWidth,
|
||||
compactPanel ? "" : "...");
|
||||
|
||||
// Determine signed-message prefix before building the header line, since it needs to go
|
||||
// at the front of headerStr rather than appended after (strncat only appends at the end).
|
||||
@@ -634,28 +647,58 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
#endif
|
||||
|
||||
// Final header line
|
||||
char headerStr[128];
|
||||
if (mine) {
|
||||
if (currentMode == ThreadMode::ALL) {
|
||||
if (strcmp(chanType, "(DM)") == 0) {
|
||||
snprintf(headerStr, sizeof(headerStr), "%s to %s", timeBuf, truncatedSender);
|
||||
} else {
|
||||
snprintf(headerStr, sizeof(headerStr), "%s to %s", timeBuf, chanType);
|
||||
if (compactPanel) {
|
||||
// Time and sender don't fit on one line at this width - time first, name below.
|
||||
allLines.push_back(timeBuf);
|
||||
isMine.push_back(mine);
|
||||
isHeader.push_back(true);
|
||||
ackForLine.push_back(AckStatus::NONE); // ack mark shown on the name line instead
|
||||
|
||||
char nameLine[80] = "";
|
||||
if (mine) {
|
||||
if (currentMode == ThreadMode::ALL) {
|
||||
if (strcmp(chanType, "(DM)") == 0) {
|
||||
snprintf(nameLine, sizeof(nameLine), "to %s", truncatedSender);
|
||||
} else {
|
||||
snprintf(nameLine, sizeof(nameLine), "to %s", chanType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
snprintf(headerStr, sizeof(headerStr), "%s", timeBuf);
|
||||
snprintf(nameLine, sizeof(nameLine), chanType[0] ? "%s%s@%s" : "%s%s", signPrefix, truncatedSender, chanType);
|
||||
}
|
||||
|
||||
if (nameLine[0]) {
|
||||
allLines.push_back(nameLine);
|
||||
isMine.push_back(mine);
|
||||
isHeader.push_back(true);
|
||||
ackForLine.push_back(m.ackStatus);
|
||||
} else {
|
||||
// Nothing to show on a second line (e.g. "mine" in ALL mode) - move the ack mark back.
|
||||
ackForLine.back() = m.ackStatus;
|
||||
}
|
||||
} else {
|
||||
snprintf(headerStr, sizeof(headerStr), chanType[0] ? "%s %s@%s %s" : "%s %s@%s", timeBuf, signPrefix, truncatedSender,
|
||||
chanType);
|
||||
}
|
||||
// Final header line
|
||||
char headerStr[128];
|
||||
if (mine) {
|
||||
if (currentMode == ThreadMode::ALL) {
|
||||
if (strcmp(chanType, "(DM)") == 0) {
|
||||
snprintf(headerStr, sizeof(headerStr), "%s to %s", timeBuf, truncatedSender);
|
||||
} else {
|
||||
snprintf(headerStr, sizeof(headerStr), "%s to %s", timeBuf, chanType);
|
||||
}
|
||||
} else {
|
||||
snprintf(headerStr, sizeof(headerStr), "%s", timeBuf);
|
||||
}
|
||||
} else {
|
||||
snprintf(headerStr, sizeof(headerStr), chanType[0] ? "%s %s@%s %s" : "%s %s@%s", timeBuf, signPrefix,
|
||||
truncatedSender, chanType);
|
||||
}
|
||||
|
||||
// Push header line
|
||||
allLines.push_back(headerStr);
|
||||
isMine.push_back(mine);
|
||||
isHeader.push_back(true);
|
||||
ackForLine.push_back(m.ackStatus);
|
||||
allLines.push_back(headerStr);
|
||||
isMine.push_back(mine);
|
||||
isHeader.push_back(true);
|
||||
ackForLine.push_back(m.ackStatus);
|
||||
}
|
||||
|
||||
const char *msgText = MessageStore::getText(m);
|
||||
|
||||
@@ -679,6 +722,13 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
// Cache lines and heights
|
||||
cachedLines.swap(allLines);
|
||||
cachedHeights = calculateLineHeights(cachedLines, emotes, isHeader);
|
||||
if (compactPanel) {
|
||||
for (size_t i = 0; i < cachedHeights.size(); ++i) {
|
||||
if (isHeader[i]) {
|
||||
cachedHeights[i] = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<MessageBlock> blocks = buildMessageBlocks(isHeader, isMine);
|
||||
|
||||
@@ -728,8 +778,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
#endif
|
||||
|
||||
int finalScroll = (int)scrollY;
|
||||
int yOffset = -finalScroll + getTextPositions(display)[1];
|
||||
const int contentTop = getTextPositions(display)[1];
|
||||
int yOffset = -finalScroll + contentTop;
|
||||
const int contentBottom = scrollBottom; // already excludes nav line
|
||||
const int rightEdge = SCREEN_WIDTH - SCROLLBAR_WIDTH - RIGHT_MARGIN;
|
||||
const int bubbleGapY = std::max(1, MESSAGE_BLOCK_GAP / 2);
|
||||
@@ -907,18 +956,20 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
graphics::UIRenderer::drawStringWithEmotes(display, headerX, lineY, cachedLines[i].c_str(), FONT_HEIGHT_SMALL, 1,
|
||||
true);
|
||||
|
||||
// Draw underline just under header text
|
||||
int underlineY = lineY + FONT_HEIGHT_SMALL;
|
||||
if (!compactPanel) {
|
||||
// Draw underline just under header text
|
||||
int underlineY = lineY + FONT_HEIGHT_SMALL;
|
||||
|
||||
int underlineW = w;
|
||||
int maxW = rightEdge - headerX;
|
||||
if (maxW < 0)
|
||||
maxW = 0;
|
||||
if (underlineW > maxW)
|
||||
underlineW = maxW;
|
||||
int underlineW = w;
|
||||
int maxW = rightEdge - headerX;
|
||||
if (maxW < 0)
|
||||
maxW = 0;
|
||||
if (underlineW > maxW)
|
||||
underlineW = maxW;
|
||||
|
||||
for (int px = 0; px < underlineW; ++px) {
|
||||
display->setPixel(headerX + px, underlineY);
|
||||
for (int px = 0; px < underlineW; ++px) {
|
||||
display->setPixel(headerX + px, underlineY);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw ACK/NACK mark for our own messages
|
||||
@@ -958,8 +1009,10 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
}
|
||||
|
||||
// Draw scrollbar
|
||||
drawMessageScrollbar(display, usableHeight, totalHeight, finalScroll, getTextPositions(display)[1]);
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
drawMessageScrollbar(display, usableHeight, totalHeight, finalScroll, contentTop);
|
||||
if (!compactPanel) {
|
||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||
}
|
||||
graphics::drawCommonFooter(display, x, y);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user