refactor(ui): align screens to the documented UI conventions

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 <noreply@anthropic.com>
This commit is contained in:
MarekZegare4
2026-06-29 18:01:29 +02:00
parent e44df01b9b
commit 089048a036
7 changed files with 20 additions and 39 deletions

View File

@@ -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;

View File

@@ -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;
}
};

View File

@@ -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" };

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;