From 94181831dd014a8156464b19c55949850dfc84a3 Mon Sep 17 00:00:00 2001 From: Jakub <106778416+MarekZegare4@users.noreply.github.com> Date: Fri, 17 Jul 2026 22:04:29 +0200 Subject: [PATCH] fix(ui): don't draw the new-message alert over a full-screen keyboard UITask::newMsg() (fired for every incoming DM/channel message) triggers a 3s "Msg: " overlay drawn on top of whatever screen is current -- including the shared KeyboardWidget when it's occupying the full screen for text entry (message compose, room/repeater password, channel name, device name, admin custom command, ...). A message arriving mid-typing blanked out the letter grid for the full 3s with no way to see what was being typed. KeyboardWidget now tracks whether it was actually rendered this frame (_visible, set at the top of render(), cleared by the new beginFrame()). UITask's render loop calls _kb.beginFrame() before curr->render() and skips the alert overlay when the keyboard turned out to be what got drawn -- covers every screen that shares _kb, not just message compose. The alert itself is unaffected (still fires, still expires after 3s) -- it just doesn't draw over the keyboard. Co-Authored-By: Claude Sonnet 5 --- examples/companion_radio/ui-new/KeyboardWidget.h | 10 ++++++++++ examples/companion_radio/ui-new/UITask.cpp | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/examples/companion_radio/ui-new/KeyboardWidget.h b/examples/companion_radio/ui-new/KeyboardWidget.h index 3cded1e1..fcdc9f9a 100644 --- a/examples/companion_radio/ui-new/KeyboardWidget.h +++ b/examples/companion_radio/ui-new/KeyboardWidget.h @@ -280,6 +280,15 @@ struct KeyboardWidget { // next letter, then reverts) — Hold-Enter on Shift toggles caps_lock, which // keeps it on for a whole run of capitals instead. bool caps_lock = false; + // Set by render() every time it's actually called; UITask clears it before + // curr->render() each frame (beginFrame()) so it reflects only "was the + // keyboard the thing on screen this frame" -- lets the alert overlay (new + // message toast) skip drawing over a full-screen keyboard, regardless of + // which screen (Messages/Bot/Settings/Admin/...) currently owns it. + bool _visible = false; + void beginFrame() { _visible = false; } + bool isVisible() const { return _visible; } + char _ph_buf[KB_PH_MAX][KB_PH_LEN]; int _ph_count; PopupMenu _ph_menu; @@ -438,6 +447,7 @@ struct KeyboardWidget { } int render(DisplayDriver& display) { + _visible = true; // A stale mid-cycle T9 press (no further input since) finalizes on its own — // the character is already committed to buf, this just stops a later Enter // on the same cell from being treated as a continued cycle. diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 0345ac21..06cfe2e4 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -2284,8 +2284,15 @@ void UITask::loop() { _next_refresh = millis() + Features::LOCKSCREEN_REFRESH_MS; } else if (!_locked && millis() >= _next_refresh && curr) { _display->startFrame(); + _kb.beginFrame(); int delay_millis = curr->render(*_display); - if (millis() < _alert_expiry) { // alert overlay on top of any screen + // Skip the alert overlay (new-message toast) while the keyboard is the + // thing actually on screen this frame -- it's shared across Messages/ + // Bot/Settings/Admin/etc., so this covers every screen that uses it for + // full-screen text entry, not just message compose. Otherwise a message + // arriving mid-typing blanks out the letter grid for 3s with no way to + // see what's being typed. + if (millis() < _alert_expiry && !_kb.isVisible()) { // alert overlay on top of any (non-keyboard) screen renderAlertOverlay(); // Keep refreshing the underlying screen at its own cadence (capped at the // alert's expiry) so layouts that settle over a frame — e.g. the message-