From 089048a036037cd6bc562ed4a7999e3cdaca291f Mon Sep 17 00:00:00 2001 From: MarekZegare4 Date: Mon, 29 Jun 2026 18:01:29 +0200 Subject: [PATCH] refactor(ui): align screens to the documented UI conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit pass against docs/design/solo_ui_framework.md, converging deviations: - prev/next: replace hand-rolled (c == KEY_LEFT || c == KEY_PREV) with keyIsPrev()/keyIsNext() in QuickMsgScreen, RingtoneEditor, TrailScreen, FullscreenMsgView. Two were real rotary-encoder gaps, not just style: NearbyScreen's filter and WaypointsView's hemisphere toggle used raw KEY_LEFT/RIGHT with no encoder twin, so the encoder couldn't drive them. - NearbyScreen's list right column used a manual setCursor(width - getTextWidth(...)) instead of the existing drawTextRightAlign() helper (which also UTF-8-translates) — now uses it, like Diagnostics/Repeater. - RepeaterScreen hand-rolled the whole drawList skeleton (scroll clamp + reserve + row loop + indicator); collapsed onto drawList(). No D-pad behaviour change; more uniform encoder support. Net -19 lines. Co-Authored-By: Claude Opus 4.8 --- .../ui-new/FullscreenMsgView.h | 4 +-- .../companion_radio/ui-new/NearbyScreen.h | 7 +++-- .../companion_radio/ui-new/QuickMsgScreen.h | 8 +++--- .../companion_radio/ui-new/RepeaterScreen.h | 26 +++---------------- .../ui-new/RingtoneEditorScreen.h | 4 +-- examples/companion_radio/ui-new/TrailScreen.h | 8 +++--- .../companion_radio/ui-new/WaypointsView.h | 2 +- 7 files changed, 20 insertions(+), 39 deletions(-) diff --git a/examples/companion_radio/ui-new/FullscreenMsgView.h b/examples/companion_radio/ui-new/FullscreenMsgView.h index 30bcdff4..ed84dd9c 100644 --- a/examples/companion_radio/ui-new/FullscreenMsgView.h +++ b/examples/companion_radio/ui-new/FullscreenMsgView.h @@ -156,8 +156,8 @@ struct FullscreenMsgView { Result handleInput(char c) { if (c == KEY_UP) { if (scroll > 0) scroll--; return NONE; } if (c == KEY_DOWN) { if (scroll < _max_scroll) scroll++; return NONE; } - if (c == KEY_LEFT) return NEXT; - if (c == KEY_RIGHT) return PREV; + if (keyIsPrev(c)) return NEXT; // page between messages (encoder too) + if (keyIsNext(c)) return PREV; if (c == KEY_CONTEXT_MENU) return REPLY; if (c == KEY_ENTER || c == KEY_CANCEL) return CLOSE; return NONE; diff --git a/examples/companion_radio/ui-new/NearbyScreen.h b/examples/companion_radio/ui-new/NearbyScreen.h index a971b4ee..d07b0f5d 100644 --- a/examples/companion_radio/ui-new/NearbyScreen.h +++ b/examples/companion_radio/ui-new/NearbyScreen.h @@ -715,8 +715,7 @@ public: if (e.dist_km >= 0.0f) geo::fmtDist(right, sizeof(right), e.dist_km, useImperial()); else strncpy(right, "?GPS", sizeof(right)); } - display.setCursor(display.width() - display.getTextWidth(right) - 2 - reserve, y); - display.print(right); + display.drawTextRightAlign(display.width() - reserve - 2, y, right); }); } @@ -779,8 +778,8 @@ public: _detail_refresh_ms = millis(); return true; } - if (c == KEY_LEFT) { _filter = (_filter + F_COUNT - 1) % F_COUNT; refresh(); return true; } - if (c == KEY_RIGHT) { _filter = (_filter + 1) % F_COUNT; refresh(); return true; } + if (keyIsPrev(c)) { _filter = (_filter + F_COUNT - 1) % F_COUNT; refresh(); return true; } + if (keyIsNext(c)) { _filter = (_filter + 1) % F_COUNT; refresh(); return true; } return false; } }; diff --git a/examples/companion_radio/ui-new/QuickMsgScreen.h b/examples/companion_radio/ui-new/QuickMsgScreen.h index 183ce51f..0f8317ea 100644 --- a/examples/companion_radio/ui-new/QuickMsgScreen.h +++ b/examples/companion_radio/ui-new/QuickMsgScreen.h @@ -1518,8 +1518,8 @@ public: } // LEFT/RIGHT cycle Notif/Melody in-place (menu stays open). if (!_pin_picker_active && _num_contacts > 0) { - bool left = (c == KEY_LEFT || c == KEY_PREV); - bool right = (c == KEY_RIGHT || c == KEY_NEXT); + bool left = keyIsPrev(c); + bool right = keyIsNext(c); if (left || right) { static const char* NOTIF_LABELS[] = { "default", "OFF", "ON" }; static const char* ML[] = { "global", "M1", "M2" }; @@ -1674,8 +1674,8 @@ public: if (_ctx_menu.active) { // LEFT/RIGHT cycle Notif/Melody/Fav in-place (menu stays open). if (_num_channels > 0) { - bool left = (c == KEY_LEFT || c == KEY_PREV); - bool right = (c == KEY_RIGHT || c == KEY_NEXT); + bool left = keyIsPrev(c); + bool right = keyIsNext(c); if (left || right) { static const char* NOTIF_LABELS[] = { "default", "OFF", "ON" }; static const char* ML[] = { "global", "M1", "M2" }; diff --git a/examples/companion_radio/ui-new/RepeaterScreen.h b/examples/companion_radio/ui-new/RepeaterScreen.h index 3e546634..b606d059 100644 --- a/examples/companion_radio/ui-new/RepeaterScreen.h +++ b/examples/companion_radio/ui-new/RepeaterScreen.h @@ -143,39 +143,21 @@ public: display.setColor(DisplayDriver::LIGHT); display.drawCenteredHeader("REPEATER"); - const int item_h = display.lineStep(); - const int start_y = display.listStart(); - int visible = display.listVisible(item_h); - if (visible < 1) visible = 1; - // Config only — live forwarding stats live on Tools › Diagnostics. - int total = _item_count; - if (_sel < _scroll) _scroll = _sel; - if (_sel >= _scroll + visible) _scroll = _sel - visible + 1; - int max_scroll = total - visible; - if (max_scroll < 0) max_scroll = 0; - if (_scroll > max_scroll) _scroll = max_scroll; - if (_scroll < 0) _scroll = 0; - - const int reserve = scrollIndicatorReserve(display, total, visible); - for (int i = 0; i < visible && (_scroll + i) < total; i++) { - int row = _scroll + i; - int y = start_y + i * item_h; - char val[16]; - bool sel = (row == _sel); + drawList(display, _item_count, _sel, _scroll, [&](int row, int y, bool sel, int reserve) { int item = _items[row]; - display.drawSelectionRow(0, y - 1, display.width() - reserve, item_h - 1, sel); + display.drawSelectionRow(0, y - 1, display.width() - reserve, display.lineStep() - 1, sel); display.setCursor(2, y); display.print(itemLabel(item)); if (item == IT_RFREQ && sel && _editor.active()) { _editor.render(display, display.valCol(), y); } else { + char val[16]; itemValue(item, p, val, sizeof(val)); display.drawTextRightAlign(display.width() - reserve - 2, y, val); } display.setColor(DisplayDriver::LIGHT); - } - drawScrollIndicator(display, start_y, visible * item_h, total, visible, _scroll); + }); display.setColor(DisplayDriver::LIGHT); if (_picker.menu.active) _picker.menu.render(display); return (_picker.menu.active || _editor.active()) ? 50 : 500; diff --git a/examples/companion_radio/ui-new/RingtoneEditorScreen.h b/examples/companion_radio/ui-new/RingtoneEditorScreen.h index 8b9de323..26ac7696 100644 --- a/examples/companion_radio/ui-new/RingtoneEditorScreen.h +++ b/examples/companion_radio/ui-new/RingtoneEditorScreen.h @@ -164,8 +164,8 @@ public: bool handleInput(char c) override { bool up = (c == KEY_UP); bool down = (c == KEY_DOWN); - bool left = (c == KEY_LEFT || c == KEY_PREV); - bool right = (c == KEY_RIGHT || c == KEY_NEXT); + bool left = keyIsPrev(c); + bool right = keyIsNext(c); bool enter = (c == KEY_ENTER); bool menu_key = (c == KEY_CONTEXT_MENU); bool cancel = (c == KEY_CANCEL); diff --git a/examples/companion_radio/ui-new/TrailScreen.h b/examples/companion_radio/ui-new/TrailScreen.h index fc3b05eb..1f2d2e2f 100644 --- a/examples/companion_radio/ui-new/TrailScreen.h +++ b/examples/companion_radio/ui-new/TrailScreen.h @@ -143,8 +143,8 @@ public: if (_action_menu.active) { // LEFT/RIGHT cycles the focused value — only meaningful in the Settings // submenu; the popup stays open so the user can keep tapping. - if (c == KEY_LEFT || c == KEY_RIGHT || c == KEY_PREV || c == KEY_NEXT) { - int dir = (c == KEY_RIGHT || c == KEY_NEXT) ? 1 : -1; + if (keyIsPrev(c) || keyIsNext(c)) { + int dir = keyIsNext(c) ? 1 : -1; int idx = _action_menu.selectedIndex(); if (idx >= 0 && idx < _act_count && _menu_level == ML_SETTINGS) cycleSetting((ActionId)_act_map[idx], dir); @@ -207,8 +207,8 @@ public: } if (c == KEY_CONTEXT_MENU) { openActionMenu(); return true; } - if (c == KEY_LEFT || c == KEY_PREV) { _view = (uint8_t)((_view + V_COUNT - 1) % V_COUNT); return true; } - if (c == KEY_RIGHT || c == KEY_NEXT) { _view = (uint8_t)((_view + 1) % V_COUNT); return true; } + if (keyIsPrev(c)) { _view = (uint8_t)((_view + V_COUNT - 1) % V_COUNT); return true; } + if (keyIsNext(c)) { _view = (uint8_t)((_view + 1) % V_COUNT); return true; } if (_view == V_SUMMARY && c == KEY_UP) { _summary_scroll = (_summary_scroll > 0) ? _summary_scroll - 1 : _summary_max_scroll; return true; diff --git a/examples/companion_radio/ui-new/WaypointsView.h b/examples/companion_radio/ui-new/WaypointsView.h index 76e4b95d..5af1d8c9 100644 --- a/examples/companion_radio/ui-new/WaypointsView.h +++ b/examples/companion_radio/ui-new/WaypointsView.h @@ -309,7 +309,7 @@ public: if (c == KEY_CANCEL) { _mode = OFF; return true; } if (c == KEY_UP) { _add_sel = (_add_sel > 0) ? _add_sel - 1 : 3; return true; } if (c == KEY_DOWN) { _add_sel = (_add_sel < 3) ? _add_sel + 1 : 0; return true; } - if (c == KEY_LEFT || c == KEY_RIGHT) { + if (keyIsPrev(c) || keyIsNext(c)) { if (_add_sel == 0) _add_lat_neg = !_add_lat_neg; // N <-> S else if (_add_sel == 1) _add_lon_neg = !_add_lon_neg; // E <-> W return true;