From 4b770ceade261806be76852e7d8811006c4db353 Mon Sep 17 00:00:00 2001 From: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> Date: Sun, 11 May 2025 01:43:56 -0400 Subject: [PATCH] Mute symbol on Header --- src/graphics/SharedUIDisplay.cpp | 109 +++++++++++------- src/graphics/SharedUIDisplay.h | 1 + src/modules/CannedMessageModule.cpp | 28 +++-- .../Telemetry/EnvironmentTelemetry.cpp | 3 +- 4 files changed, 85 insertions(+), 56 deletions(-) diff --git a/src/graphics/SharedUIDisplay.cpp b/src/graphics/SharedUIDisplay.cpp index 4b37a1a8c..63edcc19e 100644 --- a/src/graphics/SharedUIDisplay.cpp +++ b/src/graphics/SharedUIDisplay.cpp @@ -12,6 +12,7 @@ namespace graphics // === Shared External State === bool hasUnreadMessage = false; +bool isMuted = false; // === Internal State === bool isBoltVisibleShared = true; @@ -24,13 +25,16 @@ uint32_t lastMailBlink = 0; // ********************************* void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, int16_t h, int16_t r) { - display->fillRect(x + r, y, w - 2 * r, h); - display->fillRect(x, y + r, r, h - 2 * r); - display->fillRect(x + w - r, y + r, r, h - 2 * r); - display->fillCircle(x + r + 1, y + r, r); - display->fillCircle(x + w - r - 1, y + r, r); - display->fillCircle(x + r + 1, y + h - r - 1, r); - display->fillCircle(x + w - r - 1, y + h - r - 1, r); + // Draw the center and side rectangles + display->fillRect(x + r, y, w - 2 * r, h); // center bar + display->fillRect(x, y + r, r, h - 2 * r); // left edge + display->fillRect(x + w - r, y + r, r, h - 2 * r); // right edge + + // Draw the rounded corners using filled circles + display->fillCircle(x + r + 1, y + r, r); // top-left + display->fillCircle(x + w - r - 1, y + r, r); // top-right + display->fillCircle(x + r + 1, y + h - r - 1, r); // bottom-left + display->fillCircle(x + w - r - 1, y + h - r - 1, r); // bottom-right } // ************************* @@ -52,13 +56,17 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y) const int screenW = display->getWidth(); const int screenH = display->getHeight(); + // === Draw background highlight if inverted === if (isInverted) { drawRoundedHighlight(display, x, y, screenW, highlightHeight, 2); display->setColor(BLACK); } + // === Get battery charge percentage and charging status === int chargePercent = powerStatus->getBatteryChargePercent(); bool isCharging = powerStatus->getIsCharging() == meshtastic::OptionalBool::OptTrue; + + // === Animate lightning bolt blinking if charging === uint32_t now = millis(); if (isCharging && now - lastBlinkShared > 500) { isBoltVisibleShared = !isBoltVisibleShared; @@ -68,8 +76,9 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y) bool useHorizontalBattery = (screenW > 128 && screenW > screenH); const int textY = y + (highlightHeight - FONT_HEIGHT_SMALL) / 2; - // === Battery Icons === + // === Draw battery icon === if (useHorizontalBattery) { + // Wide screen battery layout int batteryX = 2; int batteryY = HEADER_OFFSET_Y + 2; display->drawXbm(batteryX, batteryY, 29, 15, batteryBitmap_h); @@ -81,10 +90,11 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y) display->fillRect(batteryX + 1, batteryY + 1, fillWidth, 13); } } else { + // Tall screen battery layout int batteryX = 1; int batteryY = HEADER_OFFSET_Y + 1; #ifdef USE_EINK - batteryY += 2; + batteryY += 2; // Extra spacing on E-Ink #endif display->drawXbm(batteryX, batteryY, 7, 11, batteryBitmap_v); if (isCharging && isBoltVisibleShared) { @@ -114,53 +124,72 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y) display->drawString(percentX + chargeNumWidth, textY, "%"); } - // === Time and Mail Icon === + // === Handle time display and alignment === uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); + char timeStr[10] = ""; + int alignX; + if (rtc_sec > 0) { + // Format time string (12h or 24h) long hms = (rtc_sec % SEC_PER_DAY + SEC_PER_DAY) % SEC_PER_DAY; int hour = hms / SEC_PER_HOUR; int minute = (hms % SEC_PER_HOUR) / SEC_PER_MIN; - char timeStr[10]; snprintf(timeStr, sizeof(timeStr), "%d:%02d", hour, minute); if (config.display.use_12h_clock) { bool isPM = hour >= 12; hour %= 12; - if (hour == 0) - hour = 12; + if (hour == 0) hour = 12; snprintf(timeStr, sizeof(timeStr), "%d:%02d%s", hour, minute, isPM ? "p" : "a"); } int timeStrWidth = display->getStringWidth(timeStr); - int timeX = screenW - xOffset - timeStrWidth + 4; - - if (hasUnreadMessage) { - if (now - lastMailBlink > 500) { - isMailIconVisible = !isMailIconVisible; - lastMailBlink = now; - } - - if (isMailIconVisible) { - if (useHorizontalBattery) { - int iconW = 16, iconH = 12; - int iconX = timeX - iconW - 4; - int iconY = textY + (FONT_HEIGHT_SMALL - iconH) / 2 - 1; - display->drawRect(iconX, iconY, iconW + 1, iconH); - display->drawLine(iconX, iconY, iconX + iconW / 2, iconY + iconH - 4); - display->drawLine(iconX + iconW, iconY, iconX + iconW / 2, iconY + iconH - 4); - } else { - int iconX = timeX - mail_width; - int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2; - display->drawXbm(iconX, iconY, mail_width, mail_height, mail); - } - } - } - - display->drawString(timeX, textY, timeStr); - if (isBold) - display->drawString(timeX - 1, textY, timeStr); + alignX = screenW - xOffset - timeStrWidth + 4; + } else { + // If time is not valid, reserve space for alignment anyway + int fallbackWidth = display->getStringWidth("12:34"); + alignX = screenW - xOffset - fallbackWidth + 4; } + // === Determine if mail icon should blink === + bool showMail = false; + if (hasUnreadMessage) { + if (now - lastMailBlink > 500) { + isMailIconVisible = !isMailIconVisible; + lastMailBlink = now; + } + showMail = isMailIconVisible; + } + + // === Draw Mail or Mute icon in the top-right corner === + if (showMail) { + if (useHorizontalBattery) { + int iconW = 16, iconH = 12; + int iconX = screenW - xOffset - iconW; + int iconY = textY + (FONT_HEIGHT_SMALL - iconH) / 2 - 1; + display->drawRect(iconX, iconY, iconW + 1, iconH); + display->drawLine(iconX, iconY, iconX + iconW / 2, iconY + iconH - 4); + display->drawLine(iconX + iconW, iconY, iconX + iconW / 2, iconY + iconH - 4); + } else { + int iconX = screenW - xOffset - mail_width; + int iconY = textY + (FONT_HEIGHT_SMALL - mail_height) / 2; + display->drawXbm(iconX, iconY, mail_width, mail_height, mail); + } + } else if (isMuted) { + const char* muteStr = "M"; + int mWidth = display->getStringWidth(muteStr); + int mX = screenW - xOffset - mWidth; + display->drawString(mX, textY, muteStr); + if (isBold) + display->drawString(mX + 1, textY, muteStr); + } else if (rtc_sec > 0) { + // Only draw the time if nothing else is shown + display->drawString(alignX, textY, timeStr); + if (isBold) + display->drawString(alignX - 1, textY, timeStr); + } + + // === Reset color back to white for following content === display->setColor(WHITE); } diff --git a/src/graphics/SharedUIDisplay.h b/src/graphics/SharedUIDisplay.h index 99508efde..3454d3c54 100644 --- a/src/graphics/SharedUIDisplay.h +++ b/src/graphics/SharedUIDisplay.h @@ -27,6 +27,7 @@ namespace graphics { // Shared state (declare inside namespace) extern bool hasUnreadMessage; +extern bool isMuted; // Rounded highlight (used for inverted headers) void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, int16_t h, int16_t r); diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 5e0645f24..a91163482 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -14,6 +14,7 @@ #include "input/ScanAndSelect.h" #include "mesh/generated/meshtastic/cannedmessages.pb.h" #include "modules/AdminModule.h" +#include "graphics/SharedUIDisplay.h" #include "main.h" // for cardkb_found #include "modules/ExternalNotificationModule.h" // for buzzer control @@ -35,6 +36,7 @@ #define INACTIVATE_AFTER_MS 20000 extern ScanI2C::DeviceAddress cardkb_found; +extern bool graphics::isMuted; static const char *cannedMessagesConfigFile = "/prefs/cannedConf.proto"; @@ -463,23 +465,19 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) break; // mute (switch off/toggle) external notifications on fn+m case INPUT_BROKER_MSG_MUTE_TOGGLE: - if (moduleConfig.external_notification.enabled == true) { - if (externalNotificationModule->getMute()) { - externalNotificationModule->setMute(false); - if (screen) { - screen->removeFunctionSymbol("M"); - screen->showOverlayBanner("Notifications\nEnabled", 3000); - } - } else { - externalNotificationModule->stopNow(); - externalNotificationModule->setMute(true); - if (screen) { - screen->setFunctionSymbol("M"); - screen->showOverlayBanner("Notifications\nDisabled", 3000); + if (moduleConfig.external_notification.enabled == true) { + if (externalNotificationModule->getMute()) { + externalNotificationModule->setMute(false); + graphics::isMuted = false; + if (screen) screen->showOverlayBanner("Notifications\nEnabled", 3000); + } else { + externalNotificationModule->stopNow(); + externalNotificationModule->setMute(true); + graphics::isMuted = true; + if (screen) screen->showOverlayBanner("Notifications\nDisabled", 3000); } } - } - break; + break; case INPUT_BROKER_MSG_GPS_TOGGLE: #if !MESHTASTIC_EXCLUDE_GPS diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index d08cdb764..8b1c636ac 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -330,7 +330,8 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt // === Draw Title (Centered under header) === const int highlightHeight = FONT_HEIGHT_SMALL - 1; const int titleY = y + 1 + (highlightHeight - FONT_HEIGHT_SMALL) / 2; - const char *titleStr = "Environment"; + const char *titleStr = (SCREEN_WIDTH > 128) ? "Environment" : "Env."; + const int centerX = x + SCREEN_WIDTH / 2; // Use black text on white background if in inverted mode