mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-31 01:08:14 +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:
@@ -690,6 +690,14 @@ void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint3
|
||||
const char *text) {
|
||||
markConnectionActive(from); // in case this is from a server, and we have a connection
|
||||
queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text);
|
||||
// If the on-device Admin screen sent this command (not the BLE/USB app's CLI
|
||||
// terminal), also hand the reply straight to the UI -- queueMessage() above
|
||||
// never displays TXT_TYPE_CLI_DATA on-device (see should_display), since that
|
||||
// path also serves the app's terminal, which must keep working unaffected.
|
||||
if (_ui && ui_pending_admin_reply && memcmp(&ui_pending_admin_reply, from.id.pub_key, 4) == 0) {
|
||||
ui_pending_admin_reply = 0;
|
||||
_ui->onAdminReply(from.id.pub_key, text);
|
||||
}
|
||||
}
|
||||
|
||||
void MyMesh::onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp,
|
||||
@@ -1749,6 +1757,20 @@ static bool isAllZero(const uint8_t* buf, size_t n) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Shared by the BLE/USB CMD_SET_CHANNEL handler below and the on-device
|
||||
// Channels add/edit/delete UI (ChannelsView) -- one place computing "was this
|
||||
// a delete" so the two callers can't drift on the cleanup step.
|
||||
bool MyMesh::setChannelLocal(uint8_t idx, const ChannelDetails& ch) {
|
||||
if (!setChannel(idx, ch)) return false;
|
||||
saveChannels();
|
||||
// An all-zero secret is this codebase's "empty slot" sentinel (same check
|
||||
// loadChannels()/saveChannels() use) -- drop anything that referenced it by
|
||||
// index, the same way onContactRemoved() does for contacts.
|
||||
if (_ui && isAllZero(ch.channel.secret, sizeof(ch.channel.secret)))
|
||||
_ui->onChannelRemoved(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MyMesh::handleCmdFrame(size_t len) {
|
||||
if (cmd_frame[0] == CMD_DEVICE_QUERY && len >= 2) { // sent when app establishes connection
|
||||
app_target_ver = cmd_frame[1]; // which version of protocol does app understand
|
||||
@@ -2451,14 +2473,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
ChannelDetails channel;
|
||||
StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32);
|
||||
memcpy(channel.channel.secret, &cmd_frame[2 + 32], 32); // 256-bit key
|
||||
if (setChannel(channel_idx, channel)) {
|
||||
saveChannels();
|
||||
// An all-zero secret is this codebase's "empty slot" sentinel (same
|
||||
// check loadChannels()/saveChannels() use) -- the app just cleared this
|
||||
// channel, so drop anything that referenced it by index, the same way
|
||||
// onContactRemoved() does for contacts.
|
||||
if (_ui && isAllZero(channel.channel.secret, sizeof(channel.channel.secret)))
|
||||
_ui->onChannelRemoved(channel_idx);
|
||||
if (setChannelLocal(channel_idx, channel)) {
|
||||
writeOKFrame();
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
|
||||
@@ -2469,10 +2484,7 @@ void MyMesh::handleCmdFrame(size_t len) {
|
||||
StrHelper::strncpy(channel.name, (char *)&cmd_frame[2], 32);
|
||||
memset(channel.channel.secret, 0, sizeof(channel.channel.secret));
|
||||
memcpy(channel.channel.secret, &cmd_frame[2 + 32], 16); // 128-bit key
|
||||
if (setChannel(channel_idx, channel)) {
|
||||
saveChannels();
|
||||
if (_ui && isAllZero(channel.channel.secret, sizeof(channel.channel.secret)))
|
||||
_ui->onChannelRemoved(channel_idx);
|
||||
if (setChannelLocal(channel_idx, channel)) {
|
||||
writeOKFrame();
|
||||
} else {
|
||||
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
|
||||
|
||||
Reference in New Issue
Block a user