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: <sender>" 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 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-07-17 22:04:29 +02:00
parent 273fbfde7a
commit 94181831dd
2 changed files with 18 additions and 1 deletions

View File

@@ -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-