mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-14 15:16:40 +00:00
polish(ui): text/icon consistency pass across Tools, Settings, and menus
- RepeaterScreen: drop the redundant "Rpt " prefix on the profile fields
(Preset/Freq/SF/BW/CR), matching Settings > Radio's own terminology --
the screen is already dedicated to the repeater's own profile, so the
prefix disambiguated nothing.
- Channel context menu: "Fav: yes/no" -> "Fav: ON/OFF", matching every
other toggle in the app.
- Settings (System tab): six labels left as raw concatenated identifiers
(AutoOff/AutoLock/TimeZone/LowBat/BattDisp/BzrVol) now read like their
space-separated neighbours (Auto pwr/Pwr save/DM sound/GPS pwr), and
BzrVol no longer clashes with "Buzzer" one row above it for the same
feature. Three value-label arrays also had one mismatched-case entry
fixed to match its siblings: Auto-off's "never" -> "OFF", Batt display's
"icon" -> "Icon", Sound's "built-in" -> "Built-in".
- ToolsScreen: re-enabled the mini-icons next to each tool, which had
been commented out ("don't fit visually"). Root cause: the screen's own
drawIcon() centred against lineStep() (line height + inter-row gap)
instead of getLineHeight() alone, 2px too generous for a near-full-
height icon -- now delegates to the already-correct miniIconDraw() used
elsewhere (e.g. the message-list ack checkmark). Also gave Admin and
GPIO their own icons (padlock, 3-pin header) instead of both sharing
System's cog.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -137,7 +137,7 @@ In the **Rooms** list the context menu instead offers:
|
||||
| Mark all read | Clears all unread for this channel |
|
||||
| Notif: default / OFF / ON | Per-channel notification override — **LEFT/RIGHT** to cycle |
|
||||
| Melody: global / M1 / M2 | Per-channel melody override — **LEFT/RIGHT** to cycle |
|
||||
| Fav: yes / no | Add or remove this channel from favourites — **LEFT/RIGHT** to toggle |
|
||||
| Fav: ON / OFF | Add or remove this channel from favourites — **LEFT/RIGHT** to toggle |
|
||||
| Edit | Opens the Add/Edit form below, pre-filled with the channel's name |
|
||||
| Delete | Removes the channel immediately (no confirm prompt) |
|
||||
|
||||
|
||||
@@ -532,9 +532,9 @@ Navigate with **UP/DOWN**; change a value with **LEFT/RIGHT** (or **Enter** for
|
||||
| -------------- | --------------- | -------------------------------------------------------------------------------------------------------------- |
|
||||
| Repeater | ON / OFF | Master switch. The options below appear only while it is ON. |
|
||||
| Network | Current / Custom | **Custom** _(default)_: enabling the repeater switches to a dedicated profile (below), disabling restores the companion's settings. A never-configured device seeds Custom from your own network's band (433/868/915 MHz region), not a flat default, so it can't land outside what's legal for your region. **Current**: relay on the companion's own frequency — opt-in, not the community norm. |
|
||||
| Rpt preset | named presets | _(Custom only)_ **Enter** picks a community/saved preset for the repeater profile. |
|
||||
| Rpt freq | chip range | _(Custom only)_ **Enter** opens the digit-by-digit editor (chip-validated bounds). |
|
||||
| Rpt SF / BW / CR | 5–12 / 7.8–500 kHz / 5–8 | _(Custom only)_ **LEFT/RIGHT** to adjust the profile's spreading factor, bandwidth, coding rate. |
|
||||
| Preset | named presets | _(Custom only)_ **Enter** picks a community/saved preset for the repeater profile. |
|
||||
| Freq | chip range | _(Custom only)_ **Enter** opens the digit-by-digit editor (chip-validated bounds). |
|
||||
| SF / BW / CR | 5–12 / 7.8–500 kHz / 5–8 | _(Custom only)_ **LEFT/RIGHT** to adjust the profile's spreading factor, bandwidth, coding rate. |
|
||||
| Skip advert | ON / OFF | Don't re-flood **advert** packets (the highest-volume flood traffic); messages and acks still relay. |
|
||||
| Max hops | OFF / 1–8 | Drop a flood packet once it has already travelled this many hops. |
|
||||
| Yield | OFF / x2–x9 | Scales the retransmit delay for **forwarded** floods only (your own sends are unaffected), so a mobile companion defers to better-sited fixed repeaters. Widens the window for **Suppress dup**. |
|
||||
|
||||
@@ -1622,8 +1622,8 @@ public:
|
||||
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" };
|
||||
static const char* NOTIF_LABELS[] = { "Default", "OFF", "ON" };
|
||||
static const char* ML[] = { "Global", "M1", "M2" };
|
||||
ContactInfo ci;
|
||||
if (the_mesh.getContactByIdx(_sorted[_contact_sel], ci)) {
|
||||
int sel = _ctx_menu.selectedIndex();
|
||||
@@ -1777,12 +1777,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_CONTEXT_MENU && _num_contacts > 0 && !_room_mode) {
|
||||
static const char* NOTIF_LABELS[] = { "default", "OFF", "ON" };
|
||||
static const char* NOTIF_LABELS[] = { "Default", "OFF", "ON" };
|
||||
ContactInfo ci;
|
||||
the_mesh.getContactByIdx(_sorted[_contact_sel], ci);
|
||||
snprintf(_ctx_notif_item, sizeof(_ctx_notif_item), "Notif: %s",
|
||||
NOTIF_LABELS[dmNotifState(ci.id.pub_key)]);
|
||||
{ static const char* ML[] = { "global", "M1", "M2" };
|
||||
{ static const char* ML[] = { "Global", "M1", "M2" };
|
||||
snprintf(_ctx_melody_item, sizeof(_ctx_melody_item), "Melody: %s",
|
||||
ML[dmMelodySlot(ci.id.pub_key)]); }
|
||||
int pinned_slot = _task->findFavouriteSlot(ci.id.pub_key);
|
||||
@@ -1805,8 +1805,8 @@ public:
|
||||
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" };
|
||||
static const char* NOTIF_LABELS[] = { "Default", "OFF", "ON" };
|
||||
static const char* ML[] = { "Global", "M1", "M2" };
|
||||
uint8_t ch_idx = _ctx_ch_idx; // frozen at menu open — see declaration
|
||||
int sel = _ctx_menu.selectedIndex();
|
||||
if (sel == 1) {
|
||||
@@ -1826,7 +1826,7 @@ public:
|
||||
if (p2) {
|
||||
p2->ch_fav_bitmask ^= (1ULL << ch_idx);
|
||||
bool is_fav = (p2->ch_fav_bitmask & (1ULL << ch_idx));
|
||||
snprintf(_ctx_ch_fav_item, sizeof(_ctx_ch_fav_item), is_fav ? "Fav: yes" : "Fav: no");
|
||||
snprintf(_ctx_ch_fav_item, sizeof(_ctx_ch_fav_item), is_fav ? "Fav: ON" : "Fav: OFF");
|
||||
_ctx_dirty = true;
|
||||
// List rebuild is deferred to menu close: with the fav-only
|
||||
// filter on, un-favouriting this channel removes it from the
|
||||
@@ -1900,15 +1900,15 @@ public:
|
||||
if (c == KEY_CONTEXT_MENU && _num_channels > 0 && _channel_sel < _num_channels) {
|
||||
uint8_t ch_idx = _channel_indices[_channel_sel];
|
||||
_ctx_ch_idx = ch_idx; // freeze the menu's target channel
|
||||
static const char* NOTIF_LABELS[] = { "default", "OFF", "ON" };
|
||||
static const char* NOTIF_LABELS[] = { "Default", "OFF", "ON" };
|
||||
snprintf(_ctx_notif_item, sizeof(_ctx_notif_item), "Notif: %s",
|
||||
NOTIF_LABELS[chNotifState(ch_idx)]);
|
||||
{ static const char* ML[] = { "global", "M1", "M2" };
|
||||
{ static const char* ML[] = { "Global", "M1", "M2" };
|
||||
snprintf(_ctx_melody_item, sizeof(_ctx_melody_item), "Melody: %s",
|
||||
ML[chNotifMelody(ch_idx)]); }
|
||||
{ NodePrefs* p2 = _task->getNodePrefs();
|
||||
bool is_fav = p2 && (p2->ch_fav_bitmask & (1ULL << ch_idx));
|
||||
snprintf(_ctx_ch_fav_item, sizeof(_ctx_ch_fav_item), is_fav ? "Fav: yes" : "Fav: no"); }
|
||||
snprintf(_ctx_ch_fav_item, sizeof(_ctx_ch_fav_item), is_fav ? "Fav: ON" : "Fav: OFF"); }
|
||||
_ctx_menu.begin("Channel options", 6);
|
||||
_ctx_menu.addItem("Mark all read");
|
||||
_ctx_menu.addItem(_ctx_notif_item);
|
||||
|
||||
@@ -74,15 +74,19 @@ class RepeaterScreen : public UIScreen {
|
||||
if (_sel < 0) _sel = 0;
|
||||
}
|
||||
|
||||
// Freq/SF/BW/CR match Settings > Radio's own terminology exactly -- no "Rpt "
|
||||
// prefix needed since this whole screen is already the repeater's own
|
||||
// profile (Settings' radio screen is a separate screen for the companion's
|
||||
// own params), so the prefix was just noise, not disambiguation.
|
||||
static const char* itemLabel(int item) {
|
||||
switch (item) {
|
||||
case IT_REPEATER: return "Repeater";
|
||||
case IT_NETWORK: return "Network";
|
||||
case IT_RPRESET: return "Rpt preset";
|
||||
case IT_RFREQ: return "Rpt freq";
|
||||
case IT_RSF: return "Rpt SF";
|
||||
case IT_RBW: return "Rpt BW";
|
||||
case IT_RCR: return "Rpt CR";
|
||||
case IT_RPRESET: return "Preset";
|
||||
case IT_RFREQ: return "Freq";
|
||||
case IT_RSF: return "SF";
|
||||
case IT_RBW: return "BW";
|
||||
case IT_RCR: return "CR";
|
||||
case IT_SKIP: return "Skip advert";
|
||||
case IT_HOPS: return "Max hops";
|
||||
case IT_YIELD: return "Yield";
|
||||
|
||||
@@ -467,7 +467,7 @@ class SettingsScreen : public UIScreen {
|
||||
display.print("N/A");
|
||||
#endif
|
||||
} else if (item == BUZZER_VOLUME) {
|
||||
display.print("BzrVol");
|
||||
display.print("Buzzer vol");
|
||||
#ifdef PIN_BUZZER
|
||||
renderBar(display, valCol(display), y, _task->getBuzzerVolume() + 1, 5);
|
||||
#else
|
||||
@@ -568,16 +568,16 @@ class SettingsScreen : public UIScreen {
|
||||
if (sel && r > 0) mq_delay = r;
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
} else if (item == AUTO_OFF) {
|
||||
display.print("AutoOff");
|
||||
display.print("Auto off");
|
||||
display.setCursor(valCol(display), y);
|
||||
display.print(AUTO_OFF_LABELS[autoOffIndex()]);
|
||||
#endif
|
||||
} else if (item == AUTO_LOCK) {
|
||||
display.print("AutoLock");
|
||||
display.print("Auto lock");
|
||||
display.setCursor(valCol(display), y);
|
||||
display.print((p && p->auto_lock) ? "ON" : "OFF");
|
||||
} else if (item == TIMEZONE) {
|
||||
display.print("TimeZone");
|
||||
display.print("Time zone");
|
||||
char buf[8];
|
||||
int8_t tz = p ? p->tz_offset_hours : 0;
|
||||
if (tz >= 0) snprintf(buf, sizeof(buf),"UTC+%d", (int)tz);
|
||||
@@ -585,7 +585,7 @@ class SettingsScreen : public UIScreen {
|
||||
display.setCursor(valCol(display), y);
|
||||
display.print(buf);
|
||||
} else if (item == LOW_BAT) {
|
||||
display.print("LowBat");
|
||||
display.print("Low batt");
|
||||
display.setCursor(valCol(display), y);
|
||||
display.print(LOW_BAT_LABELS[lowBatIndex()]);
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
@@ -624,7 +624,7 @@ class SettingsScreen : public UIScreen {
|
||||
display.print((p && p->keyboard_cardkb_compact) ? "Compact" : "Full");
|
||||
#endif
|
||||
} else if (item == BATT_DISPLAY) {
|
||||
display.print("BattDisp");
|
||||
display.print("Batt disp");
|
||||
display.setCursor(valCol(display), y);
|
||||
uint8_t mode = p ? p->batt_display_mode : 0;
|
||||
display.print(BATT_DISPLAY_LABELS[mode < BATT_DISPLAY_COUNT ? mode : 0]);
|
||||
@@ -1118,7 +1118,7 @@ public:
|
||||
|
||||
#if AUTO_OFF_MILLIS > 0
|
||||
const uint16_t SettingsScreen::AUTO_OFF_OPTS[5] = { 5, 15, 30, 60, 0 };
|
||||
const char* SettingsScreen::AUTO_OFF_LABELS[5] = { "5s", "15s", "30s", "60s", "never" };
|
||||
const char* SettingsScreen::AUTO_OFF_LABELS[5] = { "5s", "15s", "30s", "60s", "OFF" };
|
||||
#endif
|
||||
const uint16_t SettingsScreen::LOW_BAT_OPTS[7] = { 0, 3000, 3100, 3200, 3300, 3400, 3500 };
|
||||
const char* SettingsScreen::LOW_BAT_LABELS[7] = { "OFF", "3.0V", "3.1V", "3.2V", "3.3V", "3.4V", "3.5V" };
|
||||
@@ -1126,8 +1126,8 @@ const char* SettingsScreen::LOW_BAT_LABELS[7] = { "OFF", "3.0V", "3.1V", "3.
|
||||
const uint32_t SettingsScreen::GPS_DUTY_OPTS[6] = { 0, 60, 300, 900, 1800, 3600 };
|
||||
const char* SettingsScreen::GPS_DUTY_LABELS[6] = { "OFF", "1 min", "5 min", "15 min", "30 min", "1 h" };
|
||||
#endif
|
||||
const char* SettingsScreen::BATT_DISPLAY_LABELS[3] = { "icon", "%", "V" };
|
||||
const char* SettingsScreen::SOUND_LABELS[4] = { "built-in", "M1", "M2", "None" };
|
||||
const char* SettingsScreen::BATT_DISPLAY_LABELS[3] = { "Icon", "%", "V" };
|
||||
const char* SettingsScreen::SOUND_LABELS[4] = { "Built-in", "M1", "M2", "None" };
|
||||
const char* SettingsScreen::AD_SCOPE_LABELS[2] = { "All", "Zero-hop" };
|
||||
#if FEAT_FULL_REFRESH_SETTING
|
||||
const char* SettingsScreen::EINK_FULL_REFRESH_LABELS[5] = { "OFF", "5", "10", "20", "30" };
|
||||
|
||||
@@ -35,11 +35,16 @@ class ToolsScreen : public UIScreen {
|
||||
// for the widest icon (the 7px cog) at the current font scale.
|
||||
static int gutter(DisplayDriver& d) { return 7 * miniIconScale(d) + 2; }
|
||||
|
||||
// Was hand-rolling its own vertical centring against lineStep() (line height
|
||||
// + the 2px inter-row gap) instead of just the line height itself -- 2px too
|
||||
// much slack pushed a nearly-full-height icon (e.g. the 7px cog) low enough
|
||||
// to clip against the row below, which is what "don't fit visually" meant.
|
||||
// miniIconDraw() (icons.h) already centres correctly against getLineHeight()
|
||||
// alone -- the same call drawAckGlyph uses for the message-list checkmark --
|
||||
// so just delegate to it instead of keeping a second, subtly-wrong copy.
|
||||
static void drawIcon(DisplayDriver& d, int x, int y, const MiniIcon* ic) {
|
||||
if (!ic) return;
|
||||
const int s = miniIconScale(d);
|
||||
const int top = (y - 1) + ((d.lineStep() - 1) - ic->h * s) / 2;
|
||||
miniIconDrawTop(d, x, top, *ic);
|
||||
miniIconDraw(d, x, y, *ic);
|
||||
}
|
||||
|
||||
void dispatch(Action a) {
|
||||
@@ -87,7 +92,7 @@ public:
|
||||
display.setCursor(2, y);
|
||||
display.print(collapsed ? "+" : "-");
|
||||
const int icon_x = 2 + cw + 2;
|
||||
// drawIcon(display, icon_x, y, SECTIONS[sec].icon); // icons disabled for now, don't fit visually
|
||||
drawIcon(display, icon_x, y, SECTIONS[sec].icon);
|
||||
display.setCursor(icon_x + g, y);
|
||||
display.print(SECTIONS[sec].name);
|
||||
},
|
||||
@@ -95,7 +100,7 @@ public:
|
||||
[&](int sec, int item, int y, bool sel, int reserve) {
|
||||
drawRowSelection(display, y, sel, reserve);
|
||||
const int icon_x = 2 + cw + 2; // align item icons under the header icon
|
||||
// drawIcon(display, icon_x, y, SECTIONS[sec].tools[item].icon); // icons disabled for now, don't fit visually
|
||||
drawIcon(display, icon_x, y, SECTIONS[sec].tools[item].icon);
|
||||
display.setCursor(icon_x + g, y);
|
||||
display.print(SECTIONS[sec].tools[item].label);
|
||||
});
|
||||
@@ -128,14 +133,14 @@ const ToolsScreen::Tool ToolsScreen::COMMS_TOOLS[] = {
|
||||
{ "Remote Bot", &ICON_BOT, ACT_BOT },
|
||||
{ "Auto-Advert", &ICON_ADVERT, ACT_AUTOADVERT },
|
||||
{ "Repeater", &ICON_REPEATER, ACT_REPEATER },
|
||||
{ "Admin", &ICON_GEAR, ACT_ADMIN },
|
||||
{ "Admin", &ICON_KEY, ACT_ADMIN },
|
||||
};
|
||||
const ToolsScreen::Tool ToolsScreen::SYSTEM_TOOLS[] = {
|
||||
{ "Clock Tools", &ICON_ALARM, ACT_CLOCK },
|
||||
{ "Ringtone Editor", &ICON_NOTE, ACT_RINGTONE },
|
||||
{ "Diagnostics", &ICON_CHART, ACT_DIAGNOSTICS },
|
||||
#if defined(PIN_GPIO1)
|
||||
{ "GPIO", &ICON_GEAR, ACT_GPIO },
|
||||
{ "GPIO", &ICON_PINS, ACT_GPIO },
|
||||
#endif
|
||||
};
|
||||
const ToolsScreen::Section ToolsScreen::SECTIONS[] = {
|
||||
|
||||
@@ -301,6 +301,17 @@ MINI_ICON(ICON_GEAR, 7, // ⚙ cog with hub hole — system
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user