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:
Jakub
2026-07-12 19:40:53 +02:00
co-authored by Claude Sonnet 5
parent 62e82e8740
commit f399298fa6
21 changed files with 1117 additions and 214 deletions
+5 -2
View File
@@ -76,10 +76,11 @@ class UITask : public AbstractUITask {
UIScreen* splash = nullptr;
UIScreen* home = nullptr;
UIScreen* settings = nullptr;
UIScreen* quick_msg = nullptr;
UIScreen* messages_screen = nullptr;
UIScreen* tools_screen = nullptr;
UIScreen* ringtone_edit = nullptr;
UIScreen* bot_screen = nullptr;
UIScreen* admin_screen = nullptr;
UIScreen* nearby_screen = nullptr;
UIScreen* dashboard_config = nullptr;
UIScreen* auto_advert_screen = nullptr;
@@ -218,7 +219,7 @@ public:
uint16_t getBattMilliVolts() const { return _batt_mv > 0 ? _batt_mv : AbstractUITask::getBattMilliVolts(); }
void gotoHomeScreen() { setCurrScreen(home); }
void gotoSettingsScreen();
void gotoQuickMsgScreen();
void gotoMessagesScreen();
void openContactDM(const ContactInfo& ci);
void shareToMessage(const char* text); // open Messages pre-loaded to share `text`
void quickShareMyLocation(); // Home Map Hold-Enter: one-shot position share
@@ -229,6 +230,7 @@ public:
void gotoToolsScreen();
void gotoRingtoneEditor(int slot = 0);
void gotoBotScreen();
void gotoAdminScreen();
void gotoNearbyScreen();
void gotoDashboardConfig();
void gotoAutoAdvertScreen();
@@ -331,6 +333,7 @@ public:
void onMsgAck(uint32_t ack_crc) override;
void onChannelRelayed(uint32_t seq) override;
void onRoomLoginResult(const uint8_t* pub_key, bool success, uint8_t permissions) override;
void onAdminReply(const uint8_t* pub_key, const char* text) override;
int getDMUnreadTotal() const;
int getMsgCount() const { return _msgcount; }
int getChannelUnreadCount() const;