fix(ui-lvgl): map download popup fits the screen

A progress bar and one line of counts while downloading (the zoom row
hides, it can't change then), failures on one line, the source as
"opentopomap.org", only the WiFi network's name (set up in Settings >
WiFi). The debug line (IP, RSSI, heap) is gone. Roadmap: mentions
highlight added, four items ticked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-09-26 22:54:13 +02:00
co-authored by Claude Opus 5.5
parent 6f141a62f2
commit c7c150da58
4 changed files with 73 additions and 43 deletions
+11 -5
View File
@@ -235,12 +235,18 @@ Ideas to come back to (2026-09-26):
User list, second batch (2026-09-26):
- [ ] Status bar icons look like different sizes?
- [ ] Under own messages: a small counter as in the original (L1), not a
- [x] Status bar icons look like different sizes? Own icon font
(fonts/status_icons.py refits FontAwesome to one size); scrollbars
everywhere thin and at the edge, clear of the content.
- [x] Under own messages: a small counter as in the original (L1), not a
checkmark with "relayed".
- [ ] Polish the path popup of a sent / received message.
- [ ] Map download popup runs off the screen; take the WiFi settings out
of it (one place: Settings > WiFi).
- [x] Polish the path popup of a sent / received message (roles on the
right, our post's repeaters under us, long paths scroll).
- [x] Map download popup runs off the screen; take the WiFi settings out
of it (one place: Settings > WiFi). Compact: a progress bar, one
line of counts, errors on one line, only the network's name.
- [ ] Mentions: highlight @[nick] in message text (a coloured chip in
place of the raw "@[...]" markup), our own name stronger.
- [ ] Splash: "MeshCore Solo" with the upstream version and ours, all in
the MeshCore title font.
- [ ] Emoji, ideally the full range (glyphs could live on the SD card).
@@ -303,17 +303,6 @@ static void netEnd() {
}
// One line for the download popup: link details and the internal heap (TLS,
// WiFi and BLE all compete for it).
static void netInfo(char* out, size_t n) {
size_t free_int = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
size_t big_int = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
if (WiFi.status() == WL_CONNECTED)
snprintf(out, n, "%s %d dBm heap %uk/%uk", WiFi.localIP().toString().c_str(), (int)WiFi.RSSI(),
(unsigned)(free_int / 1024), (unsigned)(big_int / 1024));
else
snprintf(out, n, "WiFi status %d heap %uk/%uk", (int)WiFi.status(),
(unsigned)(free_int / 1024), (unsigned)(big_int / 1024));
}
// Async scan: scanStart(), then scanResults() returns -1 while running, else
// the count, filling `names` (strongest first, as the driver reports them).
static void scanStart() {
@@ -541,7 +530,6 @@ static void setLiveTiles(bool on) { s_live_tiles = on; }
static void netBegin(const char*, const char*) {}
static int netState() { return NET_UP; }
static void netEnd() {}
static void netInfo(char* out, size_t n) { snprintf(out, n, "browser network"); }
static uint32_t s_scan_at = 0;
static void scanStart() { s_scan_at = millis(); }
static int scanResults(char names[][33], int max) { // a pretend scan, for the UI
+60 -26
View File
@@ -600,14 +600,14 @@ void UITask::mapDownloadPopup() {
lv_obj_set_style_border_width(panel, 1, 0);
lv_obj_set_style_radius(panel, theme::RADIUS, 0);
lv_obj_set_style_pad_all(panel, theme::PAD, 0);
lv_obj_set_style_pad_row(panel, 6, 0);
lv_obj_set_style_pad_row(panel, 4, 0);
lv_obj_set_flex_flow(panel, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_max_height(panel, lv_display_get_vertical_resolution(NULL) - theme::STATUS_H - 12, 0); // scrolls past that
lv_obj_t* hdr = lv_obj_create(panel);
styleSurface(hdr, theme::BG);
lv_obj_remove_flag(hdr, LV_OBJ_FLAG_SCROLLABLE);
lv_obj_set_size(hdr, LV_PCT(100), 28);
lv_obj_set_size(hdr, LV_PCT(100), 26);
lv_obj_align(label(hdr, "Download this area", THEME_FONT_TITLE, theme::TEXT), LV_ALIGN_LEFT_MID, 0, 0);
headerButton(hdr, LV_SYMBOL_CLOSE, onDlClose, 0, NULL);
@@ -640,6 +640,15 @@ void UITask::mapDownloadPopup() {
lv_label_set_long_mode(_dl_info, LV_LABEL_LONG_WRAP);
lv_obj_set_width(_dl_info, LV_PCT(100));
lv_obj_set_style_text_line_space(_dl_info, 2, 0);
_dl_bar = lv_bar_create(panel);
lv_obj_set_size(_dl_bar, LV_PCT(100), 6);
lv_obj_set_style_bg_color(_dl_bar, lv_color_hex(theme::SURFACE_2), 0);
lv_obj_set_style_bg_color(_dl_bar, lv_color_hex(theme::ACCENT), LV_PART_INDICATOR);
lv_obj_add_flag(_dl_bar, LV_OBJ_FLAG_HIDDEN);
_dl_err = label(panel, "", THEME_FONT_SMALL, theme::FAIL);
lv_label_set_long_mode(_dl_err, LV_LABEL_LONG_DOT); // one line, whatever the server said
lv_obj_set_width(_dl_err, LV_PCT(100));
lv_obj_add_flag(_dl_err, LV_OBJ_FLAG_HIDDEN);
lv_obj_t* acts = lv_obj_create(panel);
styleSurface(acts, theme::BG);
@@ -663,7 +672,7 @@ void UITask::mapDownloadPopup() {
void UITask::mapDownloadClose() {
if (_dl_overlay) lv_obj_delete_async(_dl_overlay); // may be closing from its own button
_dl_overlay = _dl_info = _dl_zoom_lbl = _dl_start_lbl = _dl_job_row = _dl_job_lbl = nullptr;
_dl_overlay = _dl_info = _dl_bar = _dl_err = _dl_zoom_lbl = _dl_start_lbl = _dl_job_row = _dl_job_lbl = nullptr;
}
void UITask::mapDownloadZmax(int delta) {
@@ -674,27 +683,52 @@ void UITask::mapDownloadZmax(int delta) {
refreshDownloadPopup();
}
// "a.tile.opentopomap.org" -> "opentopomap.org": the name people know.
static const char* shortHost(const char* h) {
const char* p = h;
for (;;) {
const char* dot = strchr(p, '.');
if (!dot || !strchr(dot + 1, '.')) return p; // two labels left
p = dot + 1;
}
}
static void dlSize(char* out, size_t n, uint64_t bytes) {
if (bytes < 1024 * 1024) snprintf(out, n, "%lu KB", (unsigned long)(bytes / 1024));
else snprintf(out, n, "%lu MB", (unsigned long)((bytes + 512 * 1024) / (1024 * 1024)));
}
void UITask::refreshDownloadPopup() {
if (!_dl_info) return;
mapview::TileDownloader& dl = mapview::s_dl;
lv_label_set_text_fmt(_dl_zoom_lbl, "z%d", _dl_zmax);
if (dl.active()) {
char net[64];
lvport::netInfo(net, sizeof(net));
if (dl.state() == mapview::TileDownloader::CONNECTING)
lv_label_set_text_fmt(_dl_info, "Connecting to WiFi...\nFrom %s\n%s", dl.sourceHost(), net);
else if (dl.failed())
lv_label_set_text_fmt(_dl_info, "Downloading %lu / %lu tiles - %lu failed\nLast error: %s\n%s",
(unsigned long)dl.processed(), (unsigned long)dl.total(),
(unsigned long)dl.failed(), dl.message(), net);
else
lv_label_set_text_fmt(_dl_info, "Downloading %lu / %lu tiles (%lu new)\nFrom %s - you can close this\n%s",
(unsigned long)dl.processed(), (unsigned long)dl.total(),
(unsigned long)dl.downloaded(), dl.sourceHost(), net);
lv_label_set_text(_dl_start_lbl, LV_SYMBOL_STOP " Stop");
const char* host = shortHost(dl.sourceHost());
lv_obj_t* zoom_row = lv_obj_get_parent(_dl_zoom_lbl);
if (dl.active()) { // the range is fixed while it runs: room for the progress instead
lv_obj_add_flag(zoom_row, LV_OBJ_FLAG_HIDDEN);
if (_dl_job_row) lv_obj_add_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN);
lv_obj_remove_flag(_dl_bar, LV_OBJ_FLAG_HIDDEN);
uint32_t total = dl.total();
lv_bar_set_range(_dl_bar, 0, total > 0 ? (int32_t)total : 1);
lv_bar_set_value(_dl_bar, (int32_t)dl.processed(), LV_ANIM_OFF);
if (dl.state() == mapview::TileDownloader::CONNECTING)
lv_label_set_text_fmt(_dl_info, "Connecting to WiFi... - from %s", host);
else
lv_label_set_text_fmt(_dl_info, "%lu / %lu tiles, %lu new - from %s\nYou can close this, it carries on",
(unsigned long)dl.processed(), (unsigned long)total,
(unsigned long)dl.downloaded(), host);
if (dl.failed()) {
lv_label_set_text_fmt(_dl_err, "%lu failed: %s", (unsigned long)dl.failed(), dl.message());
lv_obj_remove_flag(_dl_err, LV_OBJ_FLAG_HIDDEN);
} else {
lv_obj_add_flag(_dl_err, LV_OBJ_FLAG_HIDDEN);
}
lv_label_set_text(_dl_start_lbl, LV_SYMBOL_STOP " Stop");
return;
}
lv_obj_remove_flag(zoom_row, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(_dl_bar, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(_dl_err, LV_OBJ_FLAG_HIDDEN);
mapview::TileArea job;
if (_dl_job_row && dl.savedJob(job)) {
lv_label_set_text_fmt(_dl_job_lbl, "Unfinished: z%d-%d,\n%lu tiles", job.zmin, job.zmax,
@@ -706,20 +740,20 @@ void UITask::refreshDownloadPopup() {
int w = _map_area ? lv_obj_get_width(_map_area) : 320, h = _map_area ? lv_obj_get_height(_map_area) : 218;
mapview::TileArea a = visibleArea(_map_cx, _map_cy, _map_z, w, h, dlZmin(_map_z), _dl_zmax);
uint32_t n = mapview::countTiles(a);
char ssid[33], pass[65];
bool have_wifi = lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass));
char size[16];
dlSize(size, sizeof(size), (uint64_t)n * mapview::AVG_TILE_BYTES);
// The network itself is set up in Settings > WiFi only; here just which one.
char ssid[33], pass[65], net[64];
if (!lvport::wifiAllowed()) snprintf(net, sizeof(net), "WiFi is off - Settings > WiFi");
else if (!lvport::loadWifi(ssid, sizeof(ssid), pass, sizeof(pass))) snprintf(net, sizeof(net), "No WiFi network - Settings > WiFi");
else snprintf(net, sizeof(net), "Over WiFi: %s", ssid);
char last[64] = "";
bool job_shown = _dl_job_row && !lv_obj_has_flag(_dl_job_row, LV_OBJ_FLAG_HIDDEN); // it says enough
if (!job_shown && (dl.state() == mapview::TileDownloader::DONE || dl.state() == mapview::TileDownloader::FAILED ||
dl.state() == mapview::TileDownloader::CANCELLED))
snprintf(last, sizeof(last), "\nLast: %s (%lu new)", dl.message(), (unsigned long)dl.downloaded());
char size[16];
uint64_t bytes = (uint64_t)n * mapview::AVG_TILE_BYTES;
if (bytes < 1024 * 1024) snprintf(size, sizeof(size), "%lu KB", (unsigned long)(bytes / 1024));
else snprintf(size, sizeof(size), "%lu MB", (unsigned long)((bytes + 512 * 1024) / (1024 * 1024)));
lv_label_set_text_fmt(_dl_info, "z%d-%d: %lu tiles, about %s - from %s\nWiFi: %s%s",
a.zmin, a.zmax, (unsigned long)n, size,
dl.sourceHost(), have_wifi ? ssid : "none - Settings > WiFi", last);
lv_label_set_text_fmt(_dl_info, "z%d-%d: %lu tiles, about %s - %s\n%s%s",
a.zmin, a.zmax, (unsigned long)n, size, host, net, last);
lv_label_set_text(_dl_start_lbl, n > mapview::TileDownloader::MAX_TILES ? "Too large - zoom in"
: LV_SYMBOL_DOWNLOAD " Download");
}
@@ -474,6 +474,8 @@ private:
lv_obj_t* _map_dl_pill = nullptr; // download progress over the map
lv_obj_t* _dl_overlay = nullptr; // download popup
lv_obj_t* _dl_info = nullptr;
lv_obj_t* _dl_bar = nullptr; // progress while downloading
lv_obj_t* _dl_err = nullptr; // failures, one line
lv_obj_t* _dl_zoom_lbl = nullptr;
lv_obj_t* _dl_start_lbl = nullptr;
lv_obj_t* _dl_job_row = nullptr; // "Unfinished ... Resume" in the popup