mirror of
https://github.com/skoelle/m5stack-dashboard.git
synced 2026-09-17 16:50:23 +00:00
improve ui
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
// No NTP/network time used, purely computed from date strings coming from
|
||||
// the calendar API itself, as specified.
|
||||
namespace DateUtils {
|
||||
|
||||
inline const char *weekdayShortDE(int isoWeekday /* 0=Mon..6=Sun */) {
|
||||
static const char *names[7] = {"Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"};
|
||||
if (isoWeekday < 0 || isoWeekday > 6) return "??";
|
||||
return names[isoWeekday];
|
||||
}
|
||||
|
||||
// Sakamoto's algorithm, returns 0=Monday..6=Sunday
|
||||
inline int computeWeekdayMonBased(int year, int month, int day) {
|
||||
static const int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
|
||||
int y = year;
|
||||
if (month < 3) y -= 1;
|
||||
int w = (y + y / 4 - y / 100 + y / 400 + t[month - 1] + day) % 7; // 0=Sun
|
||||
return (w + 6) % 7; // convert to 0=Mon
|
||||
}
|
||||
|
||||
struct ParsedDateTime {
|
||||
bool valid = false;
|
||||
int year = 0, month = 0, day = 0, hour = 0, minute = 0;
|
||||
};
|
||||
|
||||
inline ParsedDateTime parseIso(const String &iso) {
|
||||
ParsedDateTime r;
|
||||
if (iso.length() < 10) return r;
|
||||
|
||||
int y = iso.substring(0, 4).toInt();
|
||||
int mo = iso.substring(5, 7).toInt();
|
||||
int d = iso.substring(8, 10).toInt();
|
||||
|
||||
int h = 0, mi = 0;
|
||||
int tIdx = iso.indexOf('T');
|
||||
if (tIdx > 0 && iso.length() >= tIdx + 6) {
|
||||
h = iso.substring(tIdx + 1, tIdx + 3).toInt();
|
||||
mi = iso.substring(tIdx + 4, tIdx + 6).toInt();
|
||||
}
|
||||
|
||||
if (y == 0 || mo == 0 || d == 0) return r;
|
||||
|
||||
r.valid = true;
|
||||
r.year = y; r.month = mo; r.day = d; r.hour = h; r.minute = mi;
|
||||
return r;
|
||||
}
|
||||
|
||||
// "Mo 3.8. 14:00" for timed events, "Mo 3.8." for all-day events.
|
||||
inline String formatShortDE(const String &iso, bool allDay) {
|
||||
ParsedDateTime p = parseIso(iso);
|
||||
if (!p.valid) return iso;
|
||||
|
||||
int wd = computeWeekdayMonBased(p.year, p.month, p.day);
|
||||
String out = String(weekdayShortDE(wd)) + " " + String(p.day) + "." + String(p.month) + ".";
|
||||
|
||||
if (!allDay) {
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof(buf), " %02d:%02d", p.hour, p.minute);
|
||||
out += buf;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace DateUtils
|
||||
+9
-17
@@ -1,35 +1,27 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
// The M5Stack default font does not correctly render UTF-8 encoded German
|
||||
// umlauts (ä, ö, ü, ß), they show up as garbled characters or boxes.
|
||||
// This helper replaces them with their common ASCII transliteration
|
||||
// (ö -> oe, ä -> ae, ü -> ue, ß -> ss) before printing to the display.
|
||||
// This is the simplest, most robust fix without needing a custom font.
|
||||
// M5Stack default font can't render UTF-8 German umlauts correctly.
|
||||
// Transliterate them to ASCII before printing.
|
||||
inline String sanitizeGermanText(const String &input) {
|
||||
String out;
|
||||
out.reserve(input.length());
|
||||
|
||||
for (size_t i = 0; i < input.length(); i++) {
|
||||
unsigned char c1 = input[i];
|
||||
|
||||
// UTF-8 two-byte sequences for German umlauts start with 0xC3
|
||||
if (c1 == 0xC3 && i + 1 < input.length()) {
|
||||
unsigned char c2 = input[i + 1];
|
||||
switch (c2) {
|
||||
case 0xA4: out += "ae"; i++; continue; // ä
|
||||
case 0xB6: out += "oe"; i++; continue; // ö
|
||||
case 0xBC: out += "ue"; i++; continue; // ü
|
||||
case 0x84: out += "Ae"; i++; continue; // Ä
|
||||
case 0x96: out += "Oe"; i++; continue; // Ö
|
||||
case 0x9C: out += "Ue"; i++; continue; // Ü
|
||||
case 0x9F: out += "ss"; i++; continue; // ß
|
||||
case 0xA4: out += "ae"; i++; continue;
|
||||
case 0xB6: out += "oe"; i++; continue;
|
||||
case 0xBC: out += "ue"; i++; continue;
|
||||
case 0x84: out += "Ae"; i++; continue;
|
||||
case 0x96: out += "Oe"; i++; continue;
|
||||
case 0x9C: out += "Ue"; i++; continue;
|
||||
case 0x9F: out += "ss"; i++; continue;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
out += (char)c1;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
+13
-15
@@ -1,23 +1,21 @@
|
||||
#pragma once
|
||||
#include <M5Stack.h>
|
||||
|
||||
// "iPhone Dark Mode" inspired theme: near-black background, white text,
|
||||
// desaturated accent colors used sparingly.
|
||||
|
||||
namespace Theme {
|
||||
constexpr uint16_t BG = 0x0000; // near-black background
|
||||
constexpr uint16_t BG_CARD = 0x1082; // slightly lighter card background (dark gray)
|
||||
constexpr uint16_t TEXT = 0xFFFF; // white
|
||||
constexpr uint16_t TEXT_DIM = 0x8410; // light gray, secondary text
|
||||
constexpr uint16_t BG = 0x0000;
|
||||
constexpr uint16_t BG_CARD = 0x1082;
|
||||
constexpr uint16_t TEXT = 0xFFFF;
|
||||
constexpr uint16_t TEXT_DIM = 0x8410;
|
||||
|
||||
constexpr uint16_t ACCENT_WEATHER = 0x051D; // muted blue
|
||||
constexpr uint16_t ACCENT_SUN = 0xFEA0; // warm yellow
|
||||
constexpr uint16_t ACCENT_RAIN = 0x03BF; // muted cyan/blue
|
||||
constexpr uint16_t ACCENT_CALENDAR= 0x7BEF; // muted lavender/gray
|
||||
constexpr uint16_t ACCENT_UBAHN = 0x0410; // U-Bahn blue (muted)
|
||||
constexpr uint16_t ACCENT_SBAHN = 0x0540; // S-Bahn green (muted)
|
||||
constexpr uint16_t ACCENT_WARN = 0xFB00; // muted orange for delays/warnings
|
||||
constexpr uint16_t ACCENT_ERROR = 0xF800; // red for errors/cancellations
|
||||
constexpr uint16_t ACCENT_WEATHER = 0x051D;
|
||||
constexpr uint16_t ACCENT_SUN = 0xFEA0;
|
||||
constexpr uint16_t ACCENT_RAIN = 0x03BF;
|
||||
constexpr uint16_t ACCENT_CALENDAR= 0x7BEF;
|
||||
constexpr uint16_t ACCENT_UBAHN = 0x0410;
|
||||
constexpr uint16_t ACCENT_SBAHN = 0x0540;
|
||||
constexpr uint16_t ACCENT_WARN = 0xFB00;
|
||||
constexpr uint16_t ACCENT_ERROR = 0xF800;
|
||||
constexpr uint16_t ACCENT_STORM = 0xFD20;
|
||||
|
||||
constexpr int SCREEN_W = 320;
|
||||
constexpr int SCREEN_H = 240;
|
||||
|
||||
Reference in New Issue
Block a user