Files
Max Gramser 378d0b3e61 Build each screen in one language: the screen texts from the translations, European letters in the fonts, and Language & region in the app
The firmware takes its texts from screen_manager/translations/<code>.json at build time (components/smart_display:
one table in main.cpp, keys in screen_text_keys.h), and the fonts carry every letter European languages write with.
The app keeps Settings -> Language & region (language, clock, numbers) for every screen, writes LANGUAGE into the
screens' YAML and sends the clock and the number format in the layout message; the per-screen 24-hour clock goes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 14:24:19 +02:00

81 lines
3.7 KiB
C++

#include "screen_text_en.h"
#include "components/smart_display/header_bar.h"
#include <cassert>
#include <cstdio>
using namespace header_bar;
int main() {
assert(kind("clock") == Kind::clock && kind("analog") == Kind::analog && kind("date") == Kind::date);
assert(kind("text") == Kind::text && kind("ago") == Kind::ago);
for (const char *bad : {"", "Clock", "time", "state"}) assert(kind(bad) == Kind::none);
uint32_t c = 0;
assert(color("FFB300", c) && c == 0xFFB300);
assert(color("43a047", c) && c == 0x43A047);
for (const char *bad : {"", "FFB30", "FFB3000", "#FFB30", "GGGGGG"}) assert(!color(bad, c));
// UTF-8: ASCII, two, three and four bytes; a broken sequence still moves on.
std::string s = "a°—\U000F050F";
size_t i = 0;
assert(next_codepoint(s, i) == 'a' && next_codepoint(s, i) == 0xB0 && next_codepoint(s, i) == 0x2014);
assert(next_codepoint(s, i) == 0xF050F && next_codepoint(s, i) == 0 && i == s.size());
std::string broken = "\xE2" "x";
i = 0;
next_codepoint(broken, i);
assert(next_codepoint(broken, i) == 'x');
// The editor's agoText() uses the same words and thresholds.
const int64_t now = 1789401840;
assert(ago_text(now, 0) == "—" && ago_text(0, now) == "—");
assert(ago_text(now - 59, now) == "Just now");
assert(ago_text(now - 60, now) == "1 min ago");
assert(ago_text(now - 3599, now) == "59 min ago");
assert(ago_text(now - 3600, now) == "1 hour ago");
assert(ago_text(now - 86399, now) == "23 hours ago");
assert(ago_text(now - 86400, now) == "Yesterday");
assert(ago_text(now - 172800, now) == "2 days ago");
assert(ago_text(now - 604800, now) == "1 week ago");
assert(ago_text(now - 2 * 604800, now) == "2 weeks ago");
assert(ago_text(now - 2592000, now) == "1 month ago");
assert(ago_text(now - 3 * 2592000, now) == "3 months ago");
assert(ago_text(now - 31536000, now) == "1 year ago");
assert(ago_text(now + 30, now) == "In 1 min");
assert(ago_text(now + 600, now) == "In 10 min");
assert(ago_text(now + 3600, now) == "In 1 hour");
assert(ago_text(now + 7200, now) == "In 2 hours");
assert(ago_text(now + 90000, now) == "Tomorrow");
assert(ago_text(now + 3 * 86400, now) == "In 3 days");
assert(date_text(2, 14, 9) == "Mo 14 Sep" && date_text(1, 1, 1) == "Su 1 Jan" && date_text(7, 31, 12) == "Sa 31 Dec");
assert(date_text(0, 1, 1) == "—" && date_text(1, 1, 13) == "—");
// Guition: digits 15 px high; CYD: 10 px.
auto g = gaps(15);
assert(g.icon == 6 && g.item == 19 && g.name == 24);
auto small = gaps(10);
assert(small.icon == 4 && small.item == 13 && small.name == 16);
assert(gaps(1).icon == 2 && gaps(1).item == 6 && gaps(1).name == 8);
// Everything fits: right-aligned with item gaps, the name keeps the rest.
int widths[] = {80, 50, 49};
auto p = place(widths, 3, g, 448, 100);
assert(p.first == 0 && p.x[2] == 448 - 49 && p.x[1] == p.x[2] - 19 - 50 && p.x[0] == p.x[1] - 19 - 80);
assert(p.name_room == p.x[0] - 24);
// Too full: items leave from the front until the rest fits beside the name.
int many[] = {86, 163, 50, 60};
auto q = place(many, 4, g, 448, 100);
assert(q.first == 1);
int total = 163 + 50 + 60 + 2 * 19;
assert(q.x[1] == 448 - total && q.name_room >= 100);
// A long name keeps 35% of the width, never more than it needs.
auto r = place(many, 4, g, 448, 400);
assert(r.first == 2 && r.name_room >= 448 * 35 / 100);
// Nothing to show: the name gets the whole width.
auto empty = place(many, 0, g, 448, 400);
assert(empty.first == 0 && empty.name_room == 448);
// Items wider than the bar all leave.
int huge[] = {500};
auto none = place(huge, 1, g, 448, 50);
assert(none.first == 1 && none.name_room == 448);
std::puts("test_header_bar: PASS");
}