diff --git a/docs/solo_features/message_screen/message_screen.md b/docs/solo_features/message_screen/message_screen.md index 290146c6..9063f762 100644 --- a/docs/solo_features/message_screen/message_screen.md +++ b/docs/solo_features/message_screen/message_screen.md @@ -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) | diff --git a/docs/solo_features/tools_screen/tools_screen.md b/docs/solo_features/tools_screen/tools_screen.md index 1b8dcf49..2134d6ee 100644 --- a/docs/solo_features/tools_screen/tools_screen.md +++ b/docs/solo_features/tools_screen/tools_screen.md @@ -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**. | diff --git a/examples/companion_radio/ui-new/MessagesScreen.h b/examples/companion_radio/ui-new/MessagesScreen.h index 48a97935..ad9146b8 100644 --- a/examples/companion_radio/ui-new/MessagesScreen.h +++ b/examples/companion_radio/ui-new/MessagesScreen.h @@ -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); diff --git a/examples/companion_radio/ui-new/RepeaterScreen.h b/examples/companion_radio/ui-new/RepeaterScreen.h index e72b7997..7b9c7cd5 100644 --- a/examples/companion_radio/ui-new/RepeaterScreen.h +++ b/examples/companion_radio/ui-new/RepeaterScreen.h @@ -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"; diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index a089ae8f..9d66036a 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -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" }; diff --git a/examples/companion_radio/ui-new/ToolsScreen.h b/examples/companion_radio/ui-new/ToolsScreen.h index 5dc95d49..b79e8bbd 100644 --- a/examples/companion_radio/ui-new/ToolsScreen.h +++ b/examples/companion_radio/ui-new/ToolsScreen.h @@ -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[] = { diff --git a/examples/companion_radio/ui-new/icons.h b/examples/companion_radio/ui-new/icons.h index f6b6a063..96633459 100644 --- a/examples/companion_radio/ui-new/icons.h +++ b/examples/companion_radio/ui-new/icons.h @@ -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