refactor(ui): remove dead code and fix stale comments after the review

- ui-core: Diagnostics::systemLines, NearbyModel::typeShort,
  rptctl::currentPresetName, RoomSessions::pendingKey, settings::isSwitch,
  UiCore::reconcileDMUnread.
- ui-new: the retired Recent page, fmtAlt, the battMvToPercent wrapper,
  setFavouriteChannelSlot, AccordionList onHeader/visibleCount, drawBoxedIcon
  and seven unused icons; info::row folded into info::valueRow.
- ui-lvgl: onOpenNav, TileDownloader::withTrails; the trail header size is
  one constant (TRAIL_HDR) for live and saved trails.
- Home quick panels save prefs only when a value changed.
- Comments brought in line with the code (status bar reserve, settings rows,
  page order, SH1106 frame skip, UiCore header).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-02 13:49:26 +02:00
co-authored by Claude Opus 5.5
parent 096b8e2b1d
commit 687a31e657
19 changed files with 58 additions and 177 deletions
@@ -35,10 +35,8 @@ public:
rebuild();
}
int visibleCount() const { return _vis_count; }
bool collapsed(int sec) const { return (_collapsed >> sec) & 1; }
const Row& selected() const { return _rows[_sel]; }
bool onHeader() const { return _vis_count && _rows[_sel].item < 0; }
// Paint via the shared drawList skeleton. `header(sec, y, sel, reserve,
// collapsed)` and `item(sec, item, y, sel, reserve)` each draw one row
+4 -15
View File
@@ -11,9 +11,8 @@
namespace info {
// Label at the left, value flush right with its unit after a space ("50 m").
// `reserve` keeps the value clear of a scroll column.
// Whether a value fits on its label's line (else rowH() gives it a line below).
// `reserve` keeps the value clear of a scroll column.
inline bool rowFits(DisplayDriver& d, const char* label, const char* value, int reserve = 0, int x0 = 1) {
if (!value || !*value) return true;
const int room = d.width() - reserve - 2 - (x0 + d.getTextWidth(label) + d.getCharWidth());
@@ -40,17 +39,6 @@ inline void rowWrapped(DisplayDriver& d, int y, const char* label, const char* v
else d.drawTextEllipsized(right - room, vy, room, value);
}
// A value too long for the space left beside its label ends in an ellipsis.
inline void row(DisplayDriver& d, int y, const char* label, const char* value, int reserve = 0, int x0 = 1) {
d.setCursor(x0, y);
d.print(label);
if (!value || !*value) return;
const int right = d.width() - reserve - 2;
const int room = right - (x0 + d.getTextWidth(label) + d.getCharWidth());
if ((int)d.getTextWidth(value) <= room) d.drawTextRightAlign(right, y, value);
else if (room > d.getCharWidth()) d.drawTextEllipsized(right - room, y, room, value);
}
// A dotted rule across [x, x + w), the separator between categories.
inline void rule(DisplayDriver& d, int x, int y, int w) {
const int s = miniIconScale(d);
@@ -146,8 +134,9 @@ inline void toggle(DisplayDriver& d, int x_right, int y, bool on, bool inv = fal
}
// ── List rows (call after drawRowSelection(); text is already in the row's ink)
// A setting or field: label at x0, value flush right. A value too long for the
// room beside the label is cut, and scrolls while the row is selected.
// A setting or field: label at x0, value flush right with its unit after a
// space ("50 m"). A value too long for the room beside the label is cut, and
// scrolls while the row is selected (sel).
// Returns that marquee's next-step delay (0: nothing moving).
inline int valueRow(DisplayDriver& d, int y, const char* label, const char* value, bool sel,
int reserve, int x0 = 2) {
@@ -400,8 +400,9 @@ class SettingsScreen : public UIScreen {
}
}
// Default: CLOCK FAVOURITES RECENT RADIO BT ADVERT [GPS] [SENSORS] SETTINGS
// MAP TOOLS MESSAGES SHUTDOWN — mirrors the home-carousel enum order. Every
// page has an explicit slot now (PAGE_ORDER_LEN == HPB_COUNT).
// MAP TOOLS MESSAGES SHUTDOWN. Every bit keeps a slot (PAGE_ORDER_LEN ==
// HPB_COUNT), retired ones too: RECENT shows nowhere, and Status stands in
// the RADIO slot for the old Radio, GPS and Sensors pages.
int j = 0;
p->page_order[j++] = NodePrefs::HPB_CLOCK + 1;
p->page_order[j++] = NodePrefs::HPB_FAVOURITES + 1;
@@ -107,7 +107,7 @@ private:
if (f.place(d.lineStep())) { // label, the last half hour, the value now
const int nf = (int)radio_driver.getNoiseFloor();
if (nf) snprintf(a, sizeof(a), "%d dBm", nf); else strcpy(a, "-");
info::row(d, f.at, "Noise", a, rsv);
info::valueRow(d, f.at, "Noise", a, false, rsv, 1);
const int x0 = 1 + d.getTextWidth("Noise") + 6;
const int x1 = d.width() - rsv - 2 - d.getTextWidth(a) - 6;
if (x1 - x0 > 12) info::spark(d, x0, f.at, x1 - x0, lh - 1, _noise);
@@ -115,7 +115,7 @@ private:
if (f.place(d.lineStep())) {
const float snr = radio_driver.getLastSNR();
snprintf(b, sizeof(b), "%d dBm", (int)radio_driver.getLastRSSI());
info::row(d, f.at, "Last RX", b, rsv);
info::valueRow(d, f.at, "Last RX", b, false, rsv, 1);
drawSignalBars(d, d.width() - rsv - 2 - d.getTextWidth(b) - 5, f.at, (int)(snr * 4));
}
snprintf(b, sizeof(b), "%.1f dB", radio_driver.getLastSNR());
@@ -128,7 +128,7 @@ private:
const int lh = d.getLineHeight();
const bool on = _task->getGPSState();
if (f.place(d.lineStep())) {
info::row(d, f.at, "GPS", nullptr, rsv);
info::valueRow(d, f.at, "GPS", nullptr, false, rsv, 1);
info::toggle(d, d.width() - rsv - 2, f.at, on);
}
LocationProvider* loc = sensors.getLocationProvider();
@@ -525,15 +525,15 @@ private:
}
if (f.place(d.lineStep())) {
snprintf(a, sizeof(a), "%d", _store->count());
info::row(d, f.at, "Points", a, rsv);
info::valueRow(d, f.at, "Points", a, false, rsv, 1);
const int x0 = 1 + d.getTextWidth("Points") + 6, x1 = right - d.getTextWidth("000") - 6;
if (x1 - x0 > 10) info::meter(d, x0, f.at, x1 - x0, lh - 1, (float)_store->count() / TrailStore::CAPACITY);
}
if (f.place(d.lineStep())) {
formatAvgPaceOrSpeed(a, sizeof(a), _task->getNodePrefs());
char* c = strstr(a, ": "); // "Avg: 5 km/h" -> label + value
if (c) { *c = 0; info::row(d, f.at, a, c + 2, rsv); }
else info::row(d, f.at, a, nullptr, rsv);
if (c) { *c = 0; info::valueRow(d, f.at, a, c + 2, false, rsv, 1); }
else info::valueRow(d, f.at, a, nullptr, false, rsv, 1);
}
}
+26 -35
View File
@@ -48,10 +48,6 @@
#define LONG_PRESS_MILLIS 1200
#ifndef UI_RECENT_LIST_SIZE
#define UI_RECENT_LIST_SIZE 4
#endif
#include "icons.h"
#include "../ui-core/Lettering.h" // boot splash wordmark + lettering (shared with the L2)
@@ -140,6 +136,11 @@ public:
static const int QUICK_MSGS_MAX = 10;
// Telemetry (ui-core/Telemetry.h) in this display's font and width: tight for
// the dashboard's short fields, spaced ("49 m") on the Status screen's rows.
static const telemetry::Style L1_TELEMETRY = { "\xc2\xb0", false, false, 3 };
static const telemetry::Style L1_INFO = { "\xc2\xb0", true, false, 5 };
// ── Screen fragments — included into THIS translation unit only ───────────────
// These headers are not standalone: they are compiled solely as part of
// UITask.cpp, in the order below. Two consequences a new screen must respect:
@@ -151,14 +152,6 @@ static const int QUICK_MSGS_MAX = 10;
// scope (e.g. NearbyScreen::FILTER_LABELS), so including any of them from a
// second .cpp is a duplicate-symbol link error. Keep them UITask-internal;
// anything genuinely shareable belongs in a real header (icons.h, GeoUtils.h).
// Telemetry (ui-core/Telemetry.h) in this display's font and width: tight for
// the dashboard's short fields, spaced ("49 m") on the Status screen's rows.
static const telemetry::Style L1_TELEMETRY = { "\xc2\xb0", false, false, 3 };
static const telemetry::Style L1_INFO = { "\xc2\xb0", true, false, 5 };
// Altitude (baro or GPS) in Settings > System > Units, always the small unit.
static void fmtAlt(char* buf, int n, float meters, bool imperial) {
telemetry::altText(meters, imperial, L1_TELEMETRY, buf, n);
}
#include "FullscreenMsgView.h"
#include "../ui-core/MessageText.h"
@@ -192,9 +185,6 @@ static void fmtAlt(char* buf, int n, float meters, bool imperial) {
#include "../ui-core/Battery.h"
// Voltage -> battery %, from the Core (top bar and dashboard Batt% alike).
static int battMvToPercent(int mv, int low_mv) { return battery::percent(mv, low_mv); }
// The time on a tall portrait panel (e-ink in portrait -- height > width): HH
// and MM stacked on two lines in the huge built-in font (size 4, ~56 px tall)
// so the digits fill the narrow width. Returns the y just below it.
@@ -300,7 +290,6 @@ class HomeScreen : public UIScreen {
enum HomePage {
CLOCK,
FAVOURITES,
RECENT,
STATUS, // radio, GPS, power, mesh at a glance (took over Radio / GPS / Sensors)
BLUETOOTH,
ADVERT,
@@ -393,6 +382,7 @@ class HomeScreen : public UIScreen {
};
uint8_t _quick_sel = 0;
bool _quick_edit = false; // the selected row is being changed with Left/Right
bool _quick_dirty = false; // ...and has moved: saved once when it ends
static bool isQuickPage(int p) {
return p == SETTINGS || p == QUICK_MSG || p == BLUETOOTH || p == ADVERT || p == TOOLS || p == SHUTDOWN;
}
@@ -536,7 +526,7 @@ class HomeScreen : public UIScreen {
// The charge left, which is what you weigh before switching off.
const int mv = _task->getBattMilliVolts();
snprintf(rows[n - 1].value, sizeof(rows[0].value), "%d%%%s",
battMvToPercent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0),
battery::percent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0),
board.isExternalPowered() ? " USB" : "");
}
return n;
@@ -637,7 +627,6 @@ class HomeScreen : public UIScreen {
int pageBit(int page) const {
if (page == CLOCK) return NodePrefs::HPB_CLOCK;
if (page == FAVOURITES) return NodePrefs::HPB_FAVOURITES;
if (page == RECENT) return NodePrefs::HPB_RECENT;
if (page == STATUS) return NodePrefs::HPB_RADIO; // the old Radio slot
if (page == BLUETOOTH) return NodePrefs::HPB_BLUETOOTH;
if (page == ADVERT) return NodePrefs::HPB_ADVERT;
@@ -653,7 +642,6 @@ class HomeScreen : public UIScreen {
switch (bit) {
case NodePrefs::HPB_CLOCK: return CLOCK;
case NodePrefs::HPB_FAVOURITES: return FAVOURITES;
case NodePrefs::HPB_RECENT: return RECENT;
case NodePrefs::HPB_RADIO: return STATUS;
case NodePrefs::HPB_BLUETOOTH: return BLUETOOTH;
case NodePrefs::HPB_ADVERT: return ADVERT;
@@ -667,7 +655,6 @@ class HomeScreen : public UIScreen {
}
bool isPageVisible(int page) const {
if (page == RECENT) return false; // Recent adverts folded into Nearby Nodes; page retired
int bit = pageBit(page);
if (bit < 0) return true;
uint16_t mask = (_node_prefs && _node_prefs->home_pages_mask) ? _node_prefs->home_pages_mask : NodePrefs::HP_ALL;
@@ -711,13 +698,11 @@ class HomeScreen : public UIScreen {
}
// reserve_left: how much width from x=0 must stay clear of status icons --
// the node name on every other page (name_min below), or the LOCK page's
// own clock (see the LOCK branch in render(), which passes its actual
// footprint here so the icon row sheds low-priority icons instead of
// drawing over the clock). -1 = use the normal name reserve.
// the time / node name on the pages (name_min below); the lock page passes
// 0, its clock sits under the bar. -1 = use the normal name reserve.
int renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts, int reserve_left = -1) {
int low_mv = _node_prefs ? (int)_node_prefs->low_batt_mv : 0;
int pct = battMvToPercent((int)batteryMilliVolts, low_mv);
int pct = battery::percent((int)batteryMilliVolts, low_mv);
uint8_t mode = battery::mode(_node_prefs ? _node_prefs->batt_display_mode : 0);
@@ -760,10 +745,9 @@ class HomeScreen : public UIScreen {
}
// Secondary status icons, laid out right→left in PRIORITY order so a crowded
// bar sheds its least-important cues instead of crushing the node name. Once
// an icon won't fit above the reserved name area, every lower-priority icon
// after it is dropped too (the list is ordered high→low). A blinking icon
// still reserves its slot while off, so the name width doesn't flicker.
// bar sheds its least-important cues instead of crushing the time. Once an
// icon won't fit above the reserved area, every lower-priority icon after
// it is dropped too (the list is ordered high→low).
//
// Priority: BT > GPS fix > alarm > mute > auto-advert > trail > live-share >
// repeater. Battery (drawn above) is always rightmost. The background modes
@@ -1260,7 +1244,7 @@ public:
#endif
const int mv = _task->getBattMilliVolts();
const int pct = battMvToPercent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0);
const int pct = battery::percent(mv, _node_prefs ? (int)_node_prefs->low_batt_mv : 0);
snprintf(h, sizeof(h), "%d%%", pct);
snprintf(t, sizeof(t), "%d.%02d V%s", mv / 1000, (mv % 1000) / 10, board.isExternalPowered() ? " USB" : "");
tile(0, 1, nullptr, pct / 100.0f, h, t);
@@ -1279,7 +1263,6 @@ public:
switch (page) {
case CLOCK: return &ICON_PG_CLOCK;
case FAVOURITES: return &ICON_PG_STAR;
case RECENT: return &ICON_PG_RECENT;
case STATUS: return &ICON_CHART;
case BLUETOOTH: return &ICON_PG_BT;
case ADVERT: return &ICON_PG_ADVERT;
@@ -1611,16 +1594,24 @@ public:
const int d = c == KEY_RIGHT ? 1 : -1;
if (act == QA_BRIGHTNESS) {
uint8_t& b = _node_prefs->display_brightness;
b = (uint8_t)constrain((int)b + d, 0, 4);
_task->applyDisplayPrefs();
const uint8_t nb = (uint8_t)constrain((int)b + d, 0, 4);
if (nb != b) { b = nb; _quick_dirty = true; _task->applyDisplayPrefs(); }
} else if (act == QA_AUTO_ADVERT) {
const int i = constrain(AutoAdvertScreen::indexOf(_node_prefs->advert_auto_interval_sec) + d,
0, AutoAdvertScreen::OPT_COUNT - 1);
_node_prefs->advert_auto_interval_sec = AutoAdvertScreen::OPTS[i];
if (_node_prefs->advert_auto_interval_sec != AutoAdvertScreen::OPTS[i]) {
_node_prefs->advert_auto_interval_sec = AutoAdvertScreen::OPTS[i];
_quick_dirty = true;
}
}
return true;
}
if (c == KEY_ENTER || c == KEY_CANCEL) { _quick_edit = false; the_mesh.savePrefs(); return true; }
if (c == KEY_ENTER || c == KEY_CANCEL) {
_quick_edit = false;
_task->savePrefsIfDirty(_quick_dirty);
_quick_dirty = false;
return true;
}
return true; // nothing else while editing
}
if (isQuickPage(_page)) {
-1
View File
@@ -418,7 +418,6 @@ public:
int findFavouriteChannelSlot(uint8_t ch_idx) const { return favslots::findChannel(_node_prefs, ch_idx); }
bool isFavouriteSlotEmpty(int slot) const { return favslots::isEmpty(_node_prefs, slot); }
void setFavouriteSlot(int slot, const uint8_t* pub_key) { favslots::setContact(_node_prefs, slot, pub_key); }
void setFavouriteChannelSlot(int slot, uint8_t ch_idx) { favslots::setChannel(_node_prefs, slot, ch_idx); }
void clearFavouriteSlot(int slot) { favslots::clear(_node_prefs, slot); }
bool isButtonPressed() const;
+2 -59
View File
@@ -93,16 +93,6 @@ inline void drawSlotIcon(DisplayDriver& d, int x, int box_w, int box_h, const Mi
miniIconDrawTop(d, ix, iy, ic);
}
// Inverted status indicator: fill the box [x, 0, box_w, box_h] LIGHT, draw the
// glyph DARK and centred, then restore ink to LIGHT.
inline void drawBoxedIcon(DisplayDriver& d, int x, int box_w, int box_h, const MiniIcon& ic) {
d.setColor(DisplayDriver::LIGHT);
d.fillRect(x, 0, box_w, box_h);
d.setColor(DisplayDriver::DARK);
drawSlotIcon(d, x, box_w, box_h, ic);
d.setColor(DisplayDriver::LIGHT);
}
// Horizontal row of `count` square dots (scaled, vertically centred). Used by
// the "awaiting ACK" marker, where the dot count = number of send attempts.
inline void miniIconDotRow(DisplayDriver& d, int x, int top_y, int count) {
@@ -275,40 +265,14 @@ MINI_ICON(ICON_GPS_SEARCH, 5, // the reticle broken, no dot: GPS on, still sea
packRow("#...#"),
packRow(".#.#."));
// Tools-menu glyphs (auto-reply bot, ringtone editor, diagnostics, system).
MINI_ICON(ICON_BOT, 5, // robot head: antenna + eyes + grille (auto-reply bot)
packRow("..#.."),
packRow("#####"),
packRow("#.#.#"),
packRow("#####"),
packRow("#.#.#"),
packRow("#####"));
MINI_ICON(ICON_NOTE, 5, // ♪ quaver — ringtone editor
packRow("...##"),
packRow("...##"),
packRow("...#."),
packRow("...#."),
packRow("...#."),
packRow("####."),
packRow("####."));
MINI_ICON(ICON_CHART, 5, // ascending bars — diagnostics / stats
// The Status page's glyph.
MINI_ICON(ICON_CHART, 5, // ascending bars — Home › Status
packRow("....#"),
packRow("..#.#"),
packRow("..#.#"),
packRow("#.#.#"),
packRow("#.#.#"),
packRow("#####"));
MINI_ICON(ICON_KEY, 5, // padlock — remote admin (privileged/password-gated access)
packRow(".###."),
packRow("#...#"),
packRow("#...#"),
packRow("#####"),
packRow("##.##"),
packRow("#####"));
MINI_ICON(ICON_PINS, 5, // 3-pin header — GPIO
packRow("#.#.#"),
packRow("#.#.#"),
packRow("#####"));
// Home-carousel page glyphs — a uniform 5x5 set, deliberately smaller than the
// menu/status icons above, used in place of the page-indicator dots. One per
@@ -325,12 +289,6 @@ MINI_ICON(ICON_PG_STAR, 5, // favourites
packRow(".###."),
packRow("##.##"),
packRow("#...#"));
MINI_ICON(ICON_PG_RECENT, 5, // stacked lines — recent list
packRow("#####"),
packRow("....."),
packRow("#####"),
packRow("....."),
packRow("#####"));
MINI_ICON(ICON_PG_RADIO, 5, // antenna tower — radio params
packRow("..#.."),
packRow(".###."),
@@ -421,12 +379,6 @@ MINI_ICON(ICON_MAP_NORTH, 5, // "N" with a peaked roof — compass north ma
packRow("#.#.#"),
packRow("#..##"),
packRow("#...#"));
MINI_ICON(ICON_MAP_ARROW, 5, // → distance-to-nearest-tracked-contact indicator
packRow("..#.."),
packRow("...#."),
packRow("#####"),
packRow("...#."),
packRow("..#.."));
MINI_ICON(ICON_MAP_TARGET, 5, // ⚑ flag on a pole — the active Locator/Nav target
packRow("####."),
packRow("#..#."),
@@ -469,15 +421,6 @@ MINI_ICON(ICON_SPACE_R, 8,
packRow(".......#"),
packRow("########"));
// Scroll-indicator caps — small up/down triangles (authored on the 1× grid).
MINI_ICON(ICON_SCROLL_UP, 5, // ▲
packRow("..#.."),
packRow(".###."),
packRow("#####"));
MINI_ICON(ICON_SCROLL_DOWN, 5, // ▼
packRow("#####"),
packRow(".###."),
packRow("..#.."));
// Width of the right-edge column drawScrollIndicator occupies, or 0 when the
// list fits and no indicator is drawn. Subtract from a row's content width so