mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-05 03:36:13 +00:00
feat(ui): on-device channel management, remote admin tool, per-language keyboards
Messages: - Add/edit/delete channels on-device (new ChannelsView, owned by the renamed MessagesScreen — was QuickMsgScreen, whose name no longer matched its scope). Channel secret entry supports a typed passphrase (SHA-256'd, same primitive the library already uses for the routing hash) or a raw 32-hex-char key. - MyMesh::setChannelLocal() factors out the setChannel/saveChannels/ onChannelRemoved sequence previously duplicated across the two CMD_SET_CHANNEL branches, shared now by the BLE and on-device paths. Tools > Admin (new): - Log into a repeater/room server's admin account and send CLI commands, the on-device equivalent of the app's repeater-admin feature. - Commands are organised into category tabs (System/Radio/Routing/Actions) with common get/set fields (name, radio profile, tx power, repeat, advert intervals, ...) plus a free-text "Custom command..." fallback for anything else. A field row fetches the current value, opens it pre-filled for editing, and sends the change — falling back to a blank editor if the fetch fails or times out. - The admin password persists and self-heals exactly like room logins in Messages: saved on a confirmed admin-level login, forgotten on a failed one, left alone if merely under-privileged. - New MyMesh::sendAdminCommand()/AbstractUITask::onAdminReply() plumbing so a reply reaches the UI without touching the existing BLE/app CLI-terminal path (queueMessage's should_display gate is untouched). Shared TabBar.h extracted from NearbyScreen/BotScreen's independently duplicated tab-carousel rendering (now a third consumer via Admin) — also fixes neighbouring tabs vanishing outright when they didn't fully fit; they now truncate with an ellipsis instead. Keyboard: the combined "Ext.Latin" alphabet split into 8 separate, linguistically complete per-language keyboards (Polish, Czech, Slovak, German, French, Spanish, Portuguese, Nordic), and fixed an OLED-only bug where tall accented glyphs overlapped the keyboard's separator line (SH1106's Lemon-font ascent constant was 2-3px short for them). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "../GeoUtils.h"
|
||||
#include "NavView.h"
|
||||
#include "TabBar.h"
|
||||
|
||||
// ── Nearby Nodes ──────────────────────────────────────────────────────────────
|
||||
// One list / detail / action-menu interaction path over two sources:
|
||||
@@ -692,56 +693,12 @@ class NearbyScreen : public UIScreen {
|
||||
return false;
|
||||
}
|
||||
|
||||
// One filter tab: short label; the active one is an inverted pill (same look as
|
||||
// a selected row) so it reads as "you are here" in the tab strip.
|
||||
void drawTab(DisplayDriver& display, int x, int w, const char* label, bool active) {
|
||||
int lh = display.getLineHeight();
|
||||
if (active) {
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.fillRect(x, 0, w, lh + 1);
|
||||
display.setColor(DisplayDriver::DARK);
|
||||
} else {
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
display.drawTextCentered(x + w / 2, 0, label);
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
}
|
||||
|
||||
// Header as a circular filter tab bar: the active filter sits centred as a
|
||||
// filled pill, neighbours fan out either side and wrap around (the tab before
|
||||
// "All" is "Snsr", and vice-versa), matching the wrap-around LEFT/RIGHT cycle.
|
||||
// Only whole tabs are drawn — a tab that would spill past a screen edge is
|
||||
// skipped rather than clipped, so labels never wrap onto a second line.
|
||||
// Header as a circular filter tab bar (shared geometry — see TabBar.h): the
|
||||
// active filter sits centred as a filled pill, neighbours fan out either
|
||||
// side and wrap around (the tab before "All" is "Snsr", and vice-versa),
|
||||
// matching the wrap-around LEFT/RIGHT cycle.
|
||||
void drawFilterTabs(DisplayDriver& display) {
|
||||
const int pad = 3, gap = 2;
|
||||
int w[F_COUNT];
|
||||
for (int i = 0; i < F_COUNT; i++)
|
||||
w[i] = display.getTextWidth(FILTER_LABELS[i]) + pad * 2;
|
||||
|
||||
int ax = display.width() / 2 - w[_filter] / 2; // active tab centred
|
||||
drawTab(display, ax, w[_filter], FILTER_LABELS[_filter], true);
|
||||
|
||||
int lx = ax - gap; // next left tab's right edge
|
||||
int rx = ax + w[_filter] + gap; // next right tab's left edge
|
||||
int rx_limit = display.width() - display.menuHintWidth(); // leave room for the ≡ hint
|
||||
bool lfit = true, rfit = true;
|
||||
for (int k = 1; k <= F_COUNT / 2 && (lfit || rfit); k++) {
|
||||
int li = (_filter - k + F_COUNT) % F_COUNT;
|
||||
int ri = (_filter + k) % F_COUNT;
|
||||
if (lfit) {
|
||||
int x = lx - w[li];
|
||||
if (x >= 0) { drawTab(display, x, w[li], FILTER_LABELS[li], false); lx = x - gap; }
|
||||
else lfit = false;
|
||||
}
|
||||
// Skip the right side when it lands on the same tab as the left (the single
|
||||
// opposite tab on an even count) so it isn't drawn twice.
|
||||
if (rfit && ri != li) {
|
||||
if (rx + w[ri] <= rx_limit) { drawTab(display, rx, w[ri], FILTER_LABELS[ri], false); rx += w[ri] + gap; }
|
||||
else rfit = false;
|
||||
}
|
||||
}
|
||||
display.setColor(DisplayDriver::LIGHT);
|
||||
display.fillRect(0, display.headerH() - display.sepH(), display.width(), display.sepH());
|
||||
tabbar::draw(display, FILTER_LABELS, F_COUNT, _filter, display.menuHintWidth());
|
||||
display.drawContextMenuHint(DisplayDriver::LIGHT, ctxMenuOpen()); // Nodes list has a Hold-Enter menu
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user