diff --git a/scripts/build_html.py b/scripts/build_html.py
index 32847760..d11837e8 100644
--- a/scripts/build_html.py
+++ b/scripts/build_html.py
@@ -1,10 +1,85 @@
+import configparser
import os
import re
import gzip
+import subprocess
+import sys
SRC_DIR = "src"
+CROSSPOINT_NAME = "CrossPoint Reader"
+PLACEHOLDERS = {
+ "%%CROSSPOINT%%": CROSSPOINT_NAME,
+}
+
+
+def warn(msg: str) -> None:
+ print(f"WARNING [build_html.py]: {msg}", file=sys.stderr)
+
+
+def get_base_version(project_dir: str) -> str:
+ ini_path = os.path.join(project_dir, "platformio.ini")
+ if not os.path.isfile(ini_path):
+ warn(f"platformio.ini not found at {ini_path}; using 0.0.0")
+ return "0.0.0"
+ config = configparser.ConfigParser()
+ config.read(ini_path)
+ if not config.has_option("crosspoint", "version"):
+ warn("No [crosspoint] section or version in platformio.ini; using 0.0.0")
+ return "0.0.0"
+ return config.get("crosspoint", "version")
+
+
+def get_git_branch(project_dir: str) -> str:
+ try:
+ branch = subprocess.check_output(
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"],
+ text=True,
+ stderr=subprocess.PIPE,
+ cwd=project_dir,
+ ).strip()
+ if branch == "HEAD":
+ branch = subprocess.check_output(
+ ["git", "rev-parse", "--short", "HEAD"],
+ text=True,
+ stderr=subprocess.PIPE,
+ cwd=project_dir,
+ ).strip()
+ return "".join(c for c in branch if c not in '"\\')
+ except FileNotFoundError:
+ warn('git not found on PATH; branch suffix will be "unknown"')
+ return "unknown"
+ except subprocess.CalledProcessError as e:
+ warn(
+ f'git command failed (exit {e.returncode}): {e.stderr.strip()}; branch suffix will be "unknown"'
+ )
+ return "unknown"
+ except Exception as e:
+ warn(
+ f'Unexpected error reading git branch: {e}; branch suffix will be "unknown"'
+ )
+ return "unknown"
+
+
+def get_version_string(project_dir: str) -> str:
+ env_version = os.environ.get("CROSSPOINT_VERSION")
+ if env_version:
+ return env_version.strip('"')
+ base_version = get_base_version(project_dir)
+ pioenv = os.environ.get("PIOENV", "default")
+ if pioenv == "default":
+ branch = get_git_branch(project_dir)
+ return f"{base_version}-dev+{branch}"
+ return base_version
+
+
+def replace_placeholders(html: str, replacements: dict) -> str:
+ for placeholder, replacement in replacements.items():
+ html = html.replace(placeholder, replacement)
+ return html
+
+
def strip_js_comments(js: str) -> str:
"""Remove JS comments while preserving string literals and URLs."""
result = []
@@ -159,6 +234,10 @@ def sanitize_identifier(name: str) -> str:
return sanitized
+project_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+version_string = get_version_string(project_dir)
+PLACEHOLDERS["%%VERSION%%"] = version_string
+
for root, _, files in os.walk(SRC_DIR):
for file in files:
if file.endswith(".html") or file.endswith(".js"):
@@ -166,8 +245,9 @@ for root, _, files in os.walk(SRC_DIR):
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
- # Only minify HTML files; JS files are typically pre-minified (e.g., jszip.min.js)
+ # Replace build-time placeholders only in HTML files
if file.endswith(".html"):
+ content = replace_placeholders(content, PLACEHOLDERS)
processed = minify_html(content)
else:
processed = content
diff --git a/src/activities/network/CalibreConnectActivity.cpp b/src/activities/network/CalibreConnectActivity.cpp
index 6b87beb8..f5cf2bb9 100644
--- a/src/activities/network/CalibreConnectActivity.cpp
+++ b/src/activities/network/CalibreConnectActivity.cpp
@@ -6,10 +6,9 @@
#include
#include
-#include "activities/network/SignalStrengthWidget.h"
-
#include "MappedInputManager.h"
#include "WifiSelectionActivity.h"
+#include "activities/network/SignalStrengthWidget.h"
#include "components/UITheme.h"
#include "fontIds.h"
diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp
index 275d9776..03dec966 100644
--- a/src/activities/network/CrossPointWebServerActivity.cpp
+++ b/src/activities/network/CrossPointWebServerActivity.cpp
@@ -377,8 +377,7 @@ void CrossPointWebServerActivity::render(RenderLock&&) {
}
}
-namespace {
-} // namespace
+namespace {} // namespace
void CrossPointWebServerActivity::renderServerRunning() const {
const auto& metrics = UITheme::getInstance().getMetrics();
@@ -463,7 +462,8 @@ void CrossPointWebServerActivity::renderServerRunning() const {
const int signalHeight = 22;
const int signalWidth = contentRect.width - metrics.contentSidePadding * 2;
const int signalY = startY + height10 + metrics.verticalSpacing * 2;
- drawWifiSignalStrength(renderer, contentRect.x + metrics.contentSidePadding, signalY, signalWidth, signalHeight, currentRssi);
+ drawWifiSignalStrength(renderer, contentRect.x + metrics.contentSidePadding, signalY, signalWidth, signalHeight,
+ currentRssi);
renderer.drawCenteredText(SMALL_FONT_ID, signalY + signalHeight + 2, rssiLabel(currentRssi).c_str(), true);
}
diff --git a/src/activities/network/SignalStrengthWidget.h b/src/activities/network/SignalStrengthWidget.h
index e38c2047..0773bf49 100644
--- a/src/activities/network/SignalStrengthWidget.h
+++ b/src/activities/network/SignalStrengthWidget.h
@@ -1,8 +1,9 @@
#pragma once
-#include
#include
#include
+
+#include
#include
inline StrId getRssiQualityStrId(int rssi) {
@@ -21,18 +22,21 @@ inline StrId getRssiQualityStrId(int rssi) {
inline void drawWifiSignalStrength(const GfxRenderer& renderer, int x, int y, int width, int height, int rssi) {
const int barCount = 4;
const int gap = 6;
- const int barWidth = std::min(10, (width - (barCount - 1) * gap) / barCount);
+ const int barWidth = std::max(1, std::min(10, (width - (barCount - 1) * gap) / barCount));
const int totalWidth = barCount * barWidth + (barCount - 1) * gap;
const int startX = x + (width - totalWidth) / 2;
- const int maxBarHeight = height - 8;
+ const int maxBarHeight = std::max(1, height - 8);
const int bars = rssi == 0 ? 0 : (rssi <= -90 ? 1 : (rssi <= -75 ? 2 : (rssi <= -60 ? 3 : 4)));
const int baseY = y + height - 2;
for (int i = 0; i < barCount; ++i) {
- const int barHeight = ((i + 1) * maxBarHeight) / barCount;
+ const int barHeight = std::max(0, ((i + 1) * maxBarHeight) / barCount);
+ if (barHeight <= 0 || barWidth <= 0) {
+ continue;
+ }
const int barX = startX + i * (barWidth + gap);
const int barY = baseY - barHeight;
renderer.drawRect(barX, barY, barWidth, barHeight, true);
- if (i < bars) {
+ if (i < bars && barWidth > 2 && barHeight > 2) {
renderer.fillRect(barX + 1, barY + 1, barWidth - 2, barHeight - 2);
}
}
diff --git a/src/network/html/WelcomePage.html b/src/network/html/WelcomePage.html
index da29bbae..8ccfe8ae 100644
--- a/src/network/html/WelcomePage.html
+++ b/src/network/html/WelcomePage.html
@@ -4,7 +4,7 @@
- CrossPoint Reader
+ %%CROSSPOINT%%