mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-10 23:22:05 +00:00
Notification and time
This commit is contained in:
parent
6627f2e873
commit
29402a5e7a
@ -31,6 +31,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "draw/DebugRenderer.h"
|
||||
#include "draw/MessageRenderer.h"
|
||||
#include "draw/NodeListRenderer.h"
|
||||
#include "draw/NotificationRenderer.h"
|
||||
#include "draw/UIRenderer.h"
|
||||
#if !MESHTASTIC_EXCLUDE_GPS
|
||||
#include "GPS.h"
|
||||
@ -76,8 +77,6 @@ using graphics::NodeListRenderer::drawScaledXBitmap16x16;
|
||||
#endif
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
#include "modules/StoreForwardModule.h"
|
||||
#endif
|
||||
|
||||
#if ARCH_PORTDUINO
|
||||
@ -141,61 +140,6 @@ static bool heartbeat = false;
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include <Throttle.h>
|
||||
|
||||
// Start Functions to write date/time to the screen
|
||||
#include <string> // Only needed if you're using std::string elsewhere
|
||||
|
||||
bool isLeapYear(int year)
|
||||
{
|
||||
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
|
||||
}
|
||||
|
||||
const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
// Fills the buffer with a formatted date/time string and returns pixel width
|
||||
int formatDateTime(char *buf, size_t bufSize, uint32_t rtc_sec, OLEDDisplay *display, bool includeTime)
|
||||
{
|
||||
int sec = rtc_sec % 60;
|
||||
rtc_sec /= 60;
|
||||
int min = rtc_sec % 60;
|
||||
rtc_sec /= 60;
|
||||
int hour = rtc_sec % 24;
|
||||
rtc_sec /= 24;
|
||||
|
||||
int year = 1970;
|
||||
while (true) {
|
||||
int daysInYear = isLeapYear(year) ? 366 : 365;
|
||||
if (rtc_sec >= (uint32_t)daysInYear) {
|
||||
rtc_sec -= daysInYear;
|
||||
year++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int month = 0;
|
||||
while (month < 12) {
|
||||
int dim = daysInMonth[month];
|
||||
if (month == 1 && isLeapYear(year))
|
||||
dim++;
|
||||
if (rtc_sec >= (uint32_t)dim) {
|
||||
rtc_sec -= dim;
|
||||
month++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int day = rtc_sec + 1;
|
||||
|
||||
if (includeTime) {
|
||||
snprintf(buf, bufSize, "%04d-%02d-%02d %02d:%02d:%02d", year, month + 1, day, hour, min, sec);
|
||||
} else {
|
||||
snprintf(buf, bufSize, "%04d-%02d-%02d", year, month + 1, day);
|
||||
}
|
||||
|
||||
return display->getStringWidth(buf);
|
||||
}
|
||||
|
||||
// Usage: int stringWidth = formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display);
|
||||
// End Functions to write date/time to the screen
|
||||
|
||||
@ -367,51 +311,6 @@ void Screen::drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int1
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(x_offset + x, 26 + y, message);
|
||||
}
|
||||
|
||||
// Used on boot when a certificate is being created
|
||||
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, y, "Creating SSL certificate");
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
if ((millis() / 1000) % 2) {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . .");
|
||||
} else {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
|
||||
}
|
||||
}
|
||||
|
||||
// Used when booting without a region set
|
||||
static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
|
||||
display->drawString(64 + x, y + FONT_HEIGHT_SMALL, getDeviceName());
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Web or CLI clients.");
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
}
|
||||
// ==============================
|
||||
// Overlay Alert Banner Renderer
|
||||
// ==============================
|
||||
@ -426,79 +325,6 @@ void Screen::showOverlayBanner(const String &message, uint32_t durationMs)
|
||||
alertBannerUntil = (durationMs == 0) ? 0 : millis() + durationMs;
|
||||
}
|
||||
|
||||
// Draws the overlay banner on screen, if still within display duration
|
||||
static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
// Exit if no message is active or duration has passed
|
||||
if (alertBannerMessage.length() == 0 || (alertBannerUntil != 0 && millis() > alertBannerUntil))
|
||||
return;
|
||||
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t padding = 5; // Padding around text inside the box
|
||||
constexpr uint8_t lineSpacing = 1; // Extra space between lines
|
||||
|
||||
// Search the mesage to determine if we need the bell added
|
||||
bool needs_bell = (alertBannerMessage.indexOf("Alert Received") != -1);
|
||||
|
||||
// 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) ===
|
||||
std::vector<String> lines;
|
||||
int start = 0, newlineIdx;
|
||||
while ((newlineIdx = alertBannerMessage.indexOf('\n', start)) != -1) {
|
||||
lines.push_back(alertBannerMessage.substring(start, newlineIdx));
|
||||
start = newlineIdx + 1;
|
||||
}
|
||||
lines.push_back(alertBannerMessage.substring(start));
|
||||
|
||||
// === Measure text dimensions ===
|
||||
uint16_t minWidth = (SCREEN_WIDTH > 128) ? 106 : 78;
|
||||
uint16_t maxWidth = 0;
|
||||
std::vector<uint16_t> lineWidths;
|
||||
for (const auto &line : lines) {
|
||||
uint16_t w = display->getStringWidth(line.c_str(), line.length(), true);
|
||||
lineWidths.push_back(w);
|
||||
if (w > maxWidth)
|
||||
maxWidth = w;
|
||||
}
|
||||
|
||||
uint16_t boxWidth = padding * 2 + maxWidth;
|
||||
if (needs_bell && boxWidth < minWidth)
|
||||
boxWidth += (SCREEN_WIDTH > 128) ? 26 : 20;
|
||||
|
||||
uint16_t boxHeight = padding * 2 + lines.size() * FONT_HEIGHT_SMALL + (lines.size() - 1) * lineSpacing;
|
||||
|
||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||
|
||||
// === Draw background box ===
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft - 1, boxTop - 1, boxWidth + 2, boxHeight + 2); // Slightly oversized box
|
||||
display->setColor(WHITE);
|
||||
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); // Border
|
||||
|
||||
// === Draw each line centered in the box ===
|
||||
int16_t lineY = boxTop + padding;
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
|
||||
uint16_t line_width = display->getStringWidth(lines[i].c_str(), lines[i].length(), 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->drawString(textX, lineY, lines[i]);
|
||||
if (SCREEN_WIDTH > 128)
|
||||
display->drawString(textX + 1, lineY, lines[i]); // Faux bold
|
||||
|
||||
lineY += FONT_HEIGHT_SMALL + lineSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
// draw overlay in bottom right corner of screen to show when notifications are muted or modifier key is active
|
||||
static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
@ -602,32 +428,6 @@ static void drawModuleFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int
|
||||
pi.drawFrame(display, state, x, y);
|
||||
}
|
||||
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, y, "Updating");
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(),
|
||||
"Please be patient and do not power off.");
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
|
||||
char tempBuf[24];
|
||||
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", error_code);
|
||||
display->drawString(0 + x, 0 + y, tempBuf);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
|
||||
}
|
||||
|
||||
// Ignore messages originating from phone (from the current node 0x0) unless range test or store and forward module are enabled
|
||||
static bool shouldDrawMessage(const meshtastic_MeshPacket *packet)
|
||||
{
|
||||
@ -2107,7 +1907,7 @@ static void drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayUiStat
|
||||
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true);
|
||||
char datetimeStr[25];
|
||||
bool showTime = false; // set to true for full datetime
|
||||
formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
|
||||
graphics::UIRenderer::formatDateTime(datetimeStr, sizeof(datetimeStr), rtc_sec, display, showTime);
|
||||
char fullLine[40];
|
||||
snprintf(fullLine, sizeof(fullLine), " Date: %s", datetimeStr);
|
||||
display->drawString(0, ((SCREEN_HEIGHT > 64) ? compactFifthLine : moreCompactFifthLine), fullLine);
|
||||
@ -2926,7 +2726,7 @@ void Screen::setSSLFrames()
|
||||
{
|
||||
if (address_found.address) {
|
||||
// LOG_DEBUG("Show SSL frames");
|
||||
static FrameCallback sslFrames[] = {drawSSLScreen};
|
||||
static FrameCallback sslFrames[] = {NotificationRenderer::drawSSLScreen};
|
||||
ui->setFrames(sslFrames, 1);
|
||||
ui->update();
|
||||
}
|
||||
@ -2938,7 +2738,7 @@ void Screen::setWelcomeFrames()
|
||||
{
|
||||
if (address_found.address) {
|
||||
// LOG_DEBUG("Show Welcome frames");
|
||||
static FrameCallback frames[] = {drawWelcomeScreen};
|
||||
static FrameCallback frames[] = {NotificationRenderer::drawWelcomeScreen};
|
||||
setFrameImmediateDraw(frames);
|
||||
}
|
||||
}
|
||||
@ -3057,7 +2857,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
// If we have a critical fault, show it first
|
||||
fsi.positions.fault = numframes;
|
||||
if (error_code) {
|
||||
normalFrames[numframes++] = drawCriticalFaultFrame;
|
||||
normalFrames[numframes++] = NotificationRenderer::drawCriticalFaultFrame;
|
||||
indicatorIcons.push_back(icon_error);
|
||||
focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame
|
||||
}
|
||||
@ -3145,7 +2945,7 @@ void Screen::setFrames(FrameFocus focus)
|
||||
ui->disableAllIndicators();
|
||||
|
||||
// Add overlays: frame icons and alert banner)
|
||||
static OverlayCallback overlays[] = {NavigationBar, drawAlertBannerOverlay};
|
||||
static OverlayCallback overlays[] = {NavigationBar, NotificationRenderer::drawAlertBannerOverlay};
|
||||
ui->setOverlays(overlays, sizeof(overlays) / sizeof(overlays[0]));
|
||||
|
||||
prevFrame = -1; // Force drawNodeInfo to pick a new node (because our list
|
||||
@ -3231,7 +3031,7 @@ void Screen::handleStartFirmwareUpdateScreen()
|
||||
showingNormalScreen = false;
|
||||
EINK_ADD_FRAMEFLAG(dispdev, DEMAND_FAST); // E-Ink: Explicitly use fast-refresh for next frame
|
||||
|
||||
static FrameCallback frames[] = {drawFrameFirmware};
|
||||
static FrameCallback frames[] = {NotificationRenderer::drawFrameFirmware};
|
||||
setFrameImmediateDraw(frames);
|
||||
}
|
||||
|
||||
|
167
src/graphics/draw/NotificationRenderer.cpp
Normal file
167
src/graphics/draw/NotificationRenderer.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
#include "NotificationRenderer.h"
|
||||
#include "DisplayFormatters.h"
|
||||
#include "NodeDB.h"
|
||||
#include "configuration.h"
|
||||
#include "graphics/ScreenFonts.h"
|
||||
#include "graphics/SharedUIDisplay.h"
|
||||
#include "graphics/images.h"
|
||||
#include "main.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
#include "esp_task_wdt.h"
|
||||
#endif
|
||||
|
||||
using namespace meshtastic;
|
||||
|
||||
// External references to global variables from Screen.cpp
|
||||
extern String alertBannerMessage;
|
||||
extern uint32_t alertBannerUntil;
|
||||
extern std::vector<std::string> functionSymbol;
|
||||
extern std::string functionSymbolString;
|
||||
extern bool hasUnreadMessage;
|
||||
|
||||
// Used on boot when a certificate is being created
|
||||
void NotificationRenderer::drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(64 + x, y, "Creating SSL certificate");
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
if ((millis() / 1000) % 2) {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . .");
|
||||
} else {
|
||||
display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait . . ");
|
||||
}
|
||||
}
|
||||
|
||||
// Used when booting without a region set
|
||||
void NotificationRenderer::drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->drawString(64 + x, y, "//\\ E S H T /\\ S T / C");
|
||||
display->drawString(64 + x, y + FONT_HEIGHT_SMALL, getDeviceName());
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
|
||||
if ((millis() / 10000) % 2) {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Set the region using the");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "Meshtastic Android, iOS,");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "Web or CLI clients.");
|
||||
} else {
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 2 - 3, "Visit meshtastic.org");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 3 - 3, "for more information.");
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL * 4 - 3, "");
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
yield();
|
||||
esp_task_wdt_reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state)
|
||||
{
|
||||
// Exit if no message is active or duration has passed
|
||||
if (alertBannerMessage.length() == 0 || (alertBannerUntil != 0 && millis() > alertBannerUntil))
|
||||
return;
|
||||
|
||||
// === Layout Configuration ===
|
||||
constexpr uint16_t padding = 5; // Padding around text inside the box
|
||||
constexpr uint8_t lineSpacing = 1; // Extra space between lines
|
||||
|
||||
// Search the mesage to determine if we need the bell added
|
||||
bool needs_bell = (alertBannerMessage.indexOf("Alert Received") != -1);
|
||||
|
||||
// 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) ===
|
||||
std::vector<String> lines;
|
||||
int start = 0, newlineIdx;
|
||||
while ((newlineIdx = alertBannerMessage.indexOf('\n', start)) != -1) {
|
||||
lines.push_back(alertBannerMessage.substring(start, newlineIdx));
|
||||
start = newlineIdx + 1;
|
||||
}
|
||||
lines.push_back(alertBannerMessage.substring(start));
|
||||
|
||||
// === Measure text dimensions ===
|
||||
uint16_t minWidth = (SCREEN_WIDTH > 128) ? 106 : 78;
|
||||
uint16_t maxWidth = 0;
|
||||
std::vector<uint16_t> lineWidths;
|
||||
for (const auto &line : lines) {
|
||||
uint16_t w = display->getStringWidth(line.c_str(), line.length(), true);
|
||||
lineWidths.push_back(w);
|
||||
if (w > maxWidth)
|
||||
maxWidth = w;
|
||||
}
|
||||
|
||||
uint16_t boxWidth = padding * 2 + maxWidth;
|
||||
if (needs_bell && boxWidth < minWidth)
|
||||
boxWidth += (SCREEN_WIDTH > 128) ? 26 : 20;
|
||||
|
||||
uint16_t boxHeight = padding * 2 + lines.size() * FONT_HEIGHT_SMALL + (lines.size() - 1) * lineSpacing;
|
||||
|
||||
int16_t boxLeft = (display->width() / 2) - (boxWidth / 2);
|
||||
int16_t boxTop = (display->height() / 2) - (boxHeight / 2);
|
||||
|
||||
// === Draw background box ===
|
||||
display->setColor(BLACK);
|
||||
display->fillRect(boxLeft - 1, boxTop - 1, boxWidth + 2, boxHeight + 2); // Slightly oversized box
|
||||
display->setColor(WHITE);
|
||||
display->drawRect(boxLeft, boxTop, boxWidth, boxHeight); // Border
|
||||
|
||||
// === Draw each line centered in the box ===
|
||||
int16_t lineY = boxTop + padding;
|
||||
for (size_t i = 0; i < lines.size(); ++i) {
|
||||
int16_t textX = boxLeft + (boxWidth - lineWidths[i]) / 2;
|
||||
uint16_t line_width = display->getStringWidth(lines[i].c_str(), lines[i].length(), 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->drawString(textX, lineY, lines[i]);
|
||||
if (SCREEN_WIDTH > 128)
|
||||
display->drawString(textX + 1, lineY, lines[i]); // Faux bold
|
||||
|
||||
lineY += FONT_HEIGHT_SMALL + lineSpacing;
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw the last text message we received
|
||||
void NotificationRenderer::drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
|
||||
char tempBuf[24];
|
||||
snprintf(tempBuf, sizeof(tempBuf), "Critical fault #%d", error_code);
|
||||
display->drawString(0 + x, 0 + y, tempBuf);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(0 + x, FONT_HEIGHT_MEDIUM + y, "For help, please visit \nmeshtastic.org");
|
||||
}
|
||||
|
||||
void NotificationRenderer::drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||||
{
|
||||
display->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display->setFont(FONT_MEDIUM);
|
||||
display->drawString(64 + x, y, "Updating");
|
||||
|
||||
display->setFont(FONT_SMALL);
|
||||
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display->drawStringMaxWidth(0 + x, 2 + y + FONT_HEIGHT_SMALL * 2, x + display->getWidth(),
|
||||
"Please be patient and do not power off.");
|
||||
}
|
14
src/graphics/draw/NotificationRenderer.h
Normal file
14
src/graphics/draw/NotificationRenderer.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "OLEDDisplay.h"
|
||||
#include "OLEDDisplayUi.h"
|
||||
|
||||
class NotificationRenderer
|
||||
{
|
||||
public:
|
||||
static void drawAlertBannerOverlay(OLEDDisplay *display, OLEDDisplayUiState *state);
|
||||
static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
|
||||
};
|
@ -183,8 +183,62 @@ void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const meshta
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace UIRenderer
|
||||
// Start Functions to write date/time to the screen
|
||||
// Helper function to check if a year is a leap year
|
||||
bool isLeapYear(int year)
|
||||
{
|
||||
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
|
||||
}
|
||||
|
||||
// Array of days in each month (non-leap year)
|
||||
const int daysInMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
// Fills the buffer with a formatted date/time string and returns pixel width
|
||||
int formatDateTime(char *buf, size_t bufSize, uint32_t rtc_sec, OLEDDisplay *display, bool includeTime)
|
||||
{
|
||||
int sec = rtc_sec % 60;
|
||||
rtc_sec /= 60;
|
||||
int min = rtc_sec % 60;
|
||||
rtc_sec /= 60;
|
||||
int hour = rtc_sec % 24;
|
||||
rtc_sec /= 24;
|
||||
|
||||
int year = 1970;
|
||||
while (true) {
|
||||
int daysInYear = isLeapYear(year) ? 366 : 365;
|
||||
if (rtc_sec >= (uint32_t)daysInYear) {
|
||||
rtc_sec -= daysInYear;
|
||||
year++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int month = 0;
|
||||
while (month < 12) {
|
||||
int dim = daysInMonth[month];
|
||||
if (month == 1 && isLeapYear(year))
|
||||
dim++;
|
||||
if (rtc_sec >= (uint32_t)dim) {
|
||||
rtc_sec -= dim;
|
||||
month++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int day = rtc_sec + 1;
|
||||
|
||||
if (includeTime) {
|
||||
snprintf(buf, bufSize, "%04d-%02d-%02d %02d:%02d:%02d", year, month + 1, day, hour, min, sec);
|
||||
} else {
|
||||
snprintf(buf, bufSize, "%04d-%02d-%02d", year, month + 1, day);
|
||||
}
|
||||
|
||||
return display->getStringWidth(buf);
|
||||
}
|
||||
|
||||
} // namespace UIRenderer
|
||||
} // namespace graphics
|
||||
|
||||
#endif // !MESHTASTIC_EXCLUDE_GPS
|
||||
|
@ -55,7 +55,7 @@ void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string
|
||||
// Time and date utilities
|
||||
void getTimeAgoStr(uint32_t agoSecs, char *timeStr, uint8_t maxLength);
|
||||
std::string drawTimeDelta(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds);
|
||||
void formatDateTime(char *buffer, size_t bufferSize, uint32_t rtc_sec, OLEDDisplay *display, bool showTime);
|
||||
int formatDateTime(char *buffer, size_t bufferSize, uint32_t rtc_sec, OLEDDisplay *display, bool showTime);
|
||||
|
||||
// Message filtering
|
||||
bool shouldDrawMessage(const meshtastic_MeshPacket *packet);
|
||||
|
Loading…
Reference in New Issue
Block a user