3e959b3df9
Everything a user sees or reads is now English: both boards' labels, status replies and logs, the ESP Screens editor and Alerts cheatsheet, and the README and guides (docs/TILES.md, CALIBRATING.md, ACCEPTANCE.md and TROUBLESHOOTING.md replace the Dutch file names). Labels follow Home Assistant's own English names (Heat/Cool modes, Heating/Cooling actions, Away, Returning to dock, weather conditions), dates use English abbreviations and the top bar writes numbers the English way. Docs use HA 2026.9's menu names (Settings -> Apps, App store, Settings -> Tools). Unused legacy files (home-like.yaml, buttons.yaml, a.out) are removed. Firmware 0.2.34 names its entities in English. Home Assistant registers a renamed ESPHome entity under a new entity ID, so the inbox text.<screen>_tegelinstellingen becomes text.<screen>_tile_settings and the layout stored under the old ID would be lost. The manager now recognises the screen by its device, during a run or after a restart, and moves its layout and update history along; the Update button and the nightly round follow the screen through the rename. Screens that still run 0.2.33 or older keep working: both languages are matched. Main is the only release branch from now on. Tested on a Home Assistant Yellow (HA 2026.9.1) with both bench boards: see docs/TEST_RESULTS_0240.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
80 lines
3.6 KiB
C++
80 lines
3.6 KiB
C++
#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");
|
|
}
|